diff --git a/bin/apidoc.bat b/bin/apidoc.bat index 4f99006f5..786c57d26 100644 --- a/bin/apidoc.bat +++ b/bin/apidoc.bat @@ -1,7 +1,7 @@ -@ECHO OFF - -SET APP_HOME=%~dp0 - -IF NOT EXIST "%APP_HOME%\conf\application.xml" SET APP_HOME=%~dp0.. - -java -DCMD=APIDOC -DAPP_HOME="%APP_HOME%" -classpath "%APP_HOME%"\lib\* org.redkale.boot.Application +@ECHO OFF + +SET APP_HOME=%~dp0 + +IF NOT EXIST "%APP_HOME%\conf\application.xml" SET APP_HOME=%~dp0.. + +java -DCMD=APIDOC -DAPP_HOME="%APP_HOME%" -classpath "%APP_HOME%"\lib\* org.redkale.boot.Application diff --git a/bin/apidoc.sh b/bin/apidoc.sh index b258d4958..60137bf28 100644 --- a/bin/apidoc.sh +++ b/bin/apidoc.sh @@ -6,7 +6,7 @@ APP_HOME=`dirname "$0"` if [ ! -f "$APP_HOME"/conf/application.xml ]; then APP_HOME="$APP_HOME"/.. -fi +fi lib='.' for jar in `ls $APP_HOME/lib/*.jar` diff --git a/bin/command.bat b/bin/command.bat index 3fb08d1d2..93ad7ab8b 100644 --- a/bin/command.bat +++ b/bin/command.bat @@ -1,7 +1,7 @@ -@ECHO OFF - -SET APP_HOME=%~dp0 - -IF NOT EXIST "%APP_HOME%\conf\application.xml" SET APP_HOME=%~dp0.. - -java -DCMD=%1 -DAPP_HOME="%APP_HOME%" -classpath "%APP_HOME%"\lib\* org.redkale.boot.Application +@ECHO OFF + +SET APP_HOME=%~dp0 + +IF NOT EXIST "%APP_HOME%\conf\application.xml" SET APP_HOME=%~dp0.. + +java -DCMD=%1 -DAPP_HOME="%APP_HOME%" -classpath "%APP_HOME%"\lib\* org.redkale.boot.Application diff --git a/bin/restart.bat b/bin/restart.bat index f8f029afa..3a1247088 100644 --- a/bin/restart.bat +++ b/bin/restart.bat @@ -1,9 +1,9 @@ -@ECHO OFF - -SET APP_HOME=%~dp0 - -IF NOT EXIST "%APP_HOME%\conf\application.xml" SET APP_HOME=%~dp0.. - -call "%APP_HOME%\bin\shutdown.bat" - +@ECHO OFF + +SET APP_HOME=%~dp0 + +IF NOT EXIST "%APP_HOME%\conf\application.xml" SET APP_HOME=%~dp0.. + +call "%APP_HOME%\bin\shutdown.bat" + call "%APP_HOME%\bin\start.bat" \ No newline at end of file diff --git a/bin/shutdown.bat b/bin/shutdown.bat index 714e75505..7246f6f0b 100644 --- a/bin/shutdown.bat +++ b/bin/shutdown.bat @@ -1,7 +1,7 @@ -@ECHO OFF - -SET APP_HOME=%~dp0 - -IF NOT EXIST "%APP_HOME%\conf\application.xml" SET APP_HOME=%~dp0.. - -java -DCMD=SHUTDOWN -DAPP_HOME="%APP_HOME%" -classpath "%APP_HOME%"\lib\* org.redkale.boot.Application +@ECHO OFF + +SET APP_HOME=%~dp0 + +IF NOT EXIST "%APP_HOME%\conf\application.xml" SET APP_HOME=%~dp0.. + +java -DCMD=SHUTDOWN -DAPP_HOME="%APP_HOME%" -classpath "%APP_HOME%"\lib\* org.redkale.boot.Application diff --git a/bin/start.bat b/bin/start.bat index e0ad68fc2..bcebe18e1 100644 --- a/bin/start.bat +++ b/bin/start.bat @@ -1,8 +1,8 @@ -@ECHO OFF - -SET APP_HOME=%~dp0 - -IF NOT EXIST "%APP_HOME%\conf\application.xml" SET APP_HOME=%~dp0.. - -java -server -DAPP_HOME="%APP_HOME%" -classpath "%APP_HOME%"\lib\* org.redkale.boot.Application - +@ECHO OFF + +SET APP_HOME=%~dp0 + +IF NOT EXIST "%APP_HOME%\conf\application.xml" SET APP_HOME=%~dp0.. + +java -server -DAPP_HOME="%APP_HOME%" -classpath "%APP_HOME%"\lib\* org.redkale.boot.Application + diff --git a/conf/persistence.xml b/conf/persistence.xml index 280c07dce..e9b34ce6b 100644 --- a/conf/persistence.xml +++ b/conf/persistence.xml @@ -24,7 +24,7 @@ ALL - + diff --git a/lib/readme.txt b/lib/readme.txt index 39089a77d..c33974e9d 100644 --- a/lib/readme.txt +++ b/lib/readme.txt @@ -1 +1 @@ -所有进程运行所依赖的第三方jar默认放在此处 \ No newline at end of file +所有进程运行所依赖的第三方jar默认放在此处 \ No newline at end of file diff --git a/my/settings.xml b/my/settings.xml index 4f003e0ba..1a4f1b695 100644 --- a/my/settings.xml +++ b/my/settings.xml @@ -1,99 +1,99 @@ - - - - ossrh - redkale - xxxxxxxxxxxxxxxxxxxxxxxxx - - - - - - ossrh - - true - - - gpg2 - xxxxxxxxxxxxxxxxxxxxxxxxx - - - - - release - - - + + + + ossrh + redkale + xxxxxxxxxxxxxxxxxxxxxxxxx + + + + + + ossrh + + true + + + gpg2 + xxxxxxxxxxxxxxxxxxxxxxxxx + + + + + release + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 0f1202c9a..8ddb83b8a 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ RedkaleProject https://redkale.org redkale -- java framework - 2.5.0 + 2.5.0 UTF-8 diff --git a/root/readme.txt b/root/readme.txt index e69de29bb..0519ecba6 100644 --- a/root/readme.txt +++ b/root/readme.txt @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/main/java/javax/annotation/Priority.java b/src/main/java/javax/annotation/Priority.java index a23830532..30f376277 100644 --- a/src/main/java/javax/annotation/Priority.java +++ b/src/main/java/javax/annotation/Priority.java @@ -1,39 +1,39 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package javax.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * 鍊艰秺澶э紝浼樺厛绾ц秺楂 - * - * @since Common Annotations 1.2 - */ -@Target({ElementType.TYPE}) -@Retention(RetentionPolicy.RUNTIME) -public @interface Priority { - - /** - * 浼樺厛绾у - * - * @return int - */ - int value(); -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package javax.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 鍊艰秺澶э紝浼樺厛绾ц秺楂 + * + * @since Common Annotations 1.2 + */ +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +public @interface Priority { + + /** + * 浼樺厛绾у + * + * @return int + */ + int value(); +} diff --git a/src/main/java/javax/annotation/Resource.java b/src/main/java/javax/annotation/Resource.java index 2be9de072..7105c2e4c 100644 --- a/src/main/java/javax/annotation/Resource.java +++ b/src/main/java/javax/annotation/Resource.java @@ -1,83 +1,83 @@ -/* - * 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 javax.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * @since Common Annotations 1.0 - */ -@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) -@Retention(RetentionPolicy.RUNTIME) -public @interface Resource { - - /** - * AuthenticationType - */ - @Deprecated - public enum AuthenticationType { - /** - * @deprecated - */ - CONTAINER, - /** - * @deprecated - */ - APPLICATION - } - - /** - * 璧勬簮鍚嶇О - * - * @return String - */ - public String name() default ""; - - /** - * 渚濊禆娉ㄥ叆鐨勭被鍨 - * - * @return Class - */ - public Class type() default Object.class; - - /** - * - * @return AuthenticationType - */ - @Deprecated - public AuthenticationType authenticationType() default AuthenticationType.CONTAINER; - - /** - * - * @return boolean - */ - @Deprecated - public boolean shareable() default true; - - /** - * - * @return String - */ - @Deprecated - public String description() default ""; - - /** - * - * @return String - */ - @Deprecated - public String mappedName() default ""; - - /** - * - * @return String - */ - @Deprecated - public String lookup() default ""; -} +/* + * 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 javax.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @since Common Annotations 1.0 + */ +@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface Resource { + + /** + * AuthenticationType + */ + @Deprecated + public enum AuthenticationType { + /** + * @deprecated + */ + CONTAINER, + /** + * @deprecated + */ + APPLICATION + } + + /** + * 璧勬簮鍚嶇О + * + * @return String + */ + public String name() default ""; + + /** + * 渚濊禆娉ㄥ叆鐨勭被鍨 + * + * @return Class + */ + public Class type() default Object.class; + + /** + * + * @return AuthenticationType + */ + @Deprecated + public AuthenticationType authenticationType() default AuthenticationType.CONTAINER; + + /** + * + * @return boolean + */ + @Deprecated + public boolean shareable() default true; + + /** + * + * @return String + */ + @Deprecated + public String description() default ""; + + /** + * + * @return String + */ + @Deprecated + public String mappedName() default ""; + + /** + * + * @return String + */ + @Deprecated + public String lookup() default ""; +} diff --git a/src/main/java/javax/persistence/Cacheable.java b/src/main/java/javax/persistence/Cacheable.java index fd6f6b181..45238dd98 100644 --- a/src/main/java/javax/persistence/Cacheable.java +++ b/src/main/java/javax/persistence/Cacheable.java @@ -1,62 +1,62 @@ -/** ***************************************************************************** - * Copyright (c) 2008 - 2013 Oracle Corporation. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 - * which accompanies this distribution. - * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * Contributors: - * Linda DeMichiel - Java Persistence 2.1 - * Linda DeMichiel - Java Persistence 2.0 - * - ***************************************************************************** */ -package javax.persistence; - -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * Specifies whether an entity should be cached if caching is enabled - * when the value of the persistence.xml caching element - * is ENABLE_SELECTIVE or DISABLE_SELECTIVE. - * The value of the Cacheable annotation is inherited by - * subclasses; it can be overridden by specifying - * Cacheable on a subclass. - * - *

- * Cacheable(false) means that the entity and its state must - * not be cached by the provider. - * - * @since Java Persistence 2.0 - */ -@Target({TYPE}) -@Retention(RUNTIME) -public @interface Cacheable { - - /** - * (Optional) Whether or not the entity should be cached. - * - * @return boolean - */ - boolean value() default true; - - /** - * (Optional) 瀹氭椂鑷姩鏇存柊缂撳瓨鐨勫懆鏈熺鏁帮紝涓0琛ㄧず涓嶅仛瀹氭椂鏇存柊锛 澶т簬0琛ㄧず姣忕粡杩噄nterval绉掑悗浼氳嚜鍔ㄤ粠鏁版嵁搴撲腑鎷夊彇鏁版嵁鏇存柊Cache - * - * @return int - */ - int interval() default 0; - - /** - * DataSource鏄惁鐩存帴杩斿洖瀵硅薄鐨勭湡瀹炲紩鐢紝 鑰屼笉鏄痗opy涓浠 - * - * @return boolean - */ - boolean direct() default false; - -} +/** ***************************************************************************** + * Copyright (c) 2008 - 2013 Oracle Corporation. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 + * which accompanies this distribution. + * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * Contributors: + * Linda DeMichiel - Java Persistence 2.1 + * Linda DeMichiel - Java Persistence 2.0 + * + ***************************************************************************** */ +package javax.persistence; + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** + * Specifies whether an entity should be cached if caching is enabled + * when the value of the persistence.xml caching element + * is ENABLE_SELECTIVE or DISABLE_SELECTIVE. + * The value of the Cacheable annotation is inherited by + * subclasses; it can be overridden by specifying + * Cacheable on a subclass. + * + *

+ * Cacheable(false) means that the entity and its state must + * not be cached by the provider. + * + * @since Java Persistence 2.0 + */ +@Target({TYPE}) +@Retention(RUNTIME) +public @interface Cacheable { + + /** + * (Optional) Whether or not the entity should be cached. + * + * @return boolean + */ + boolean value() default true; + + /** + * (Optional) 瀹氭椂鑷姩鏇存柊缂撳瓨鐨勫懆鏈熺鏁帮紝涓0琛ㄧず涓嶅仛瀹氭椂鏇存柊锛 澶т簬0琛ㄧず姣忕粡杩噄nterval绉掑悗浼氳嚜鍔ㄤ粠鏁版嵁搴撲腑鎷夊彇鏁版嵁鏇存柊Cache + * + * @return int + */ + int interval() default 0; + + /** + * DataSource鏄惁鐩存帴杩斿洖瀵硅薄鐨勭湡瀹炲紩鐢紝 鑰屼笉鏄痗opy涓浠 + * + * @return boolean + */ + boolean direct() default false; + +} diff --git a/src/main/java/org/redkale/asm/MethodDebugVisitor.java b/src/main/java/org/redkale/asm/MethodDebugVisitor.java index 3045c4b8d..f7223642e 100644 --- a/src/main/java/org/redkale/asm/MethodDebugVisitor.java +++ b/src/main/java/org/redkale/asm/MethodDebugVisitor.java @@ -1,274 +1,274 @@ -/* - * 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.asm; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.util.*; -import static org.redkale.asm.Opcodes.*; - -/** - * MethodVisitor 鐨勮皟璇曠被 - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public class MethodDebugVisitor { - - private final MethodVisitor visitor; - - private boolean debug = false; - - public MethodDebugVisitor setDebug(boolean d) { - debug = d; - return this; - } - - public void debugLine() { - if (!debug) return; - System.out.println(); - System.out.println(); - System.out.println(); - } - - private final Map labels = new LinkedHashMap<>(); - - private static final String[] opcodes = new String[200]; //0 -18 - - static { - try { - for (java.lang.reflect.Field field : Opcodes.class.getFields()) { - String name = field.getName(); - if (name.startsWith("ASM")) continue; - if (name.startsWith("V1_")) continue; - if (name.startsWith("ACC_")) continue; - if (name.startsWith("T_")) continue; - if (name.startsWith("H_")) continue; - if (name.startsWith("F_")) continue; - if (field.getType() != int.class) continue; - opcodes[(int) (Integer) field.get(null)] = name; - } - } catch (Exception ex) { - throw new RuntimeException(ex); //涓嶅彲鑳戒細鍙戠敓 - } - } - - /** - * - * @param visitor MethodVisitor - */ - public MethodDebugVisitor(MethodVisitor visitor) { - //super(Opcodes.ASM5, visitor); - this.visitor = visitor; - } - - public void visitTryCatchBlock(Label start, Label end, Label handler, String type) { - visitor.visitTryCatchBlock(start, end, handler, type); - if (debug) System.out.println("mv.visitTryCatchBlock(label0, label1, label2, \"" + type + "\");"); - } - - public AnnotationVisitor visitParameterAnnotation(int i, String string, boolean bln) { - AnnotationVisitor av = visitor.visitParameterAnnotation(i, string, bln); - if (debug) System.out.println("mv.visitParameterAnnotation(" + i + ", \"" + string + "\", " + bln + ");"); - return av; - } - - public AnnotationVisitor visitAnnotation(String desc, boolean flag) { - AnnotationVisitor av = visitor.visitAnnotation(desc, flag); - if (debug) System.out.println("mv.visitAnnotation(\"" + desc + "\", " + flag + ");"); - return av; - } - - public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) { - AnnotationVisitor av = visitor.visitTypeAnnotation(typeRef, typePath, desc, visible); - if (debug) System.out.println("mv.visitTypeAnnotation(" + typeRef + ", " + typePath + ", \"" + desc + "\", " + visible + ");"); - return av; - } - - public void visitParameter(String name, int access) { - visitor.visitParameter(name, access); - if (debug) System.out.println("mv.visitParameter(" + name + ", " + access + ");"); - } - - public void visitVarInsn(int opcode, int var) { - visitor.visitVarInsn(opcode, var); - if (debug) System.out.println("mv.visitVarInsn(" + opcodes[opcode] + ", " + var + ");"); - } - - public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) { - visitor.visitFrame(type, nLocal, local, nStack, stack); - if (debug) { - String typestr = "" + type; - if (type == -1) { - typestr = "Opcodes.F_NEW"; - } else if (type == 1) { - typestr = "Opcodes.F_APPEND"; - } else if (type == 2) { - typestr = "Opcodes.F_CHOP"; - } else if (type == 3) { - typestr = "Opcodes.F_SAME"; - } else if (type == 4) { - typestr = "Opcodes.F_SAME1"; - } - System.out.println("mv.visitFrame(" + typestr + ", " + nLocal + ", " + Arrays.toString(local) + ", " + nStack + ", " + Arrays.toString(stack) + ");"); - } - } - - public void visitJumpInsn(int opcode, Label var) { //璋冪敤姝ゆ柟娉曠殑 ClassWriter 蹇呴』鐢 COMPUTE_FRAMES 鏋勫缓 - visitor.visitJumpInsn(opcode, var); - if (debug) { - Integer index = labels.get(var); - if (index == null) { - index = labels.size(); - labels.put(var, index); - System.out.println("Label l" + index + " = new Label();"); - } - System.out.println("mv.visitJumpInsn(" + opcodes[opcode] + ", l" + index + ");"); - } - } - - public void visitCode() { - visitor.visitCode(); - if (debug) System.out.println("mv.visitCode();"); - } - - public void visitLabel(Label var) { - visitor.visitLabel(var); - if (debug) { - Integer index = labels.get(var); - if (index == null) { - index = labels.size(); - labels.put(var, index); - System.out.println("Label l" + index + " = new Label();"); - } - System.out.println("mv.visitLabel(l" + index + ");"); - } - } - - public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { - visitor.visitMethodInsn(opcode, owner, name, desc, itf); - if (debug) System.out.println("mv.visitMethodInsn(" + opcodes[opcode] + ", \"" + owner + "\", \"" + name + "\", \"" + desc + "\", " + itf + ");"); - } - - public void visitFieldInsn(int opcode, String owner, String name, String desc) { - visitor.visitFieldInsn(opcode, owner, name, desc); - if (debug) System.out.println("mv.visitFieldInsn(" + opcodes[opcode] + ", \"" + owner + "\", \"" + name + "\", \"" + desc + "\");"); - } - - public void visitTypeInsn(int opcode, String type) { - visitor.visitTypeInsn(opcode, type); - if (debug) System.out.println("mv.visitTypeInsn(" + opcodes[opcode] + ", \"" + type + "\");"); - } - - public void visitInsn(int opcode) { - visitor.visitInsn(opcode); - if (debug) System.out.println("mv.visitInsn(" + opcodes[opcode] + ");"); - } - - public void visitIntInsn(int opcode, int value) { - visitor.visitIntInsn(opcode, value); - if (debug) System.out.println("mv.visitIntInsn(" + opcodes[opcode] + ", " + value + ");"); - } - - public void visitIincInsn(int opcode, int value) { - visitor.visitIincInsn(opcode, value); - if (debug) System.out.println("mv.visitIincInsn(" + opcode + ", " + value + ");"); - } - - public void visitLdcInsn(Object o) { - visitor.visitLdcInsn(o); - if (debug) { - if (o instanceof CharSequence) { - System.out.println("mv.visitLdcInsn(\"" + o + "\");"); - } else if (o instanceof org.redkale.asm.Type) { - System.out.println("mv.visitLdcInsn(Type.getType(\"" + o + "\"));"); - } else { - System.out.println("mv.visitLdcInsn(" + o + ");"); - } - } - } - - public void visitMaxs(int maxStack, int maxLocals) { - visitor.visitMaxs(maxStack, maxLocals); - if (debug) System.out.println("mv.visitMaxs(" + maxStack + ", " + maxLocals + ");"); - } - - public void visitEnd() { - visitor.visitEnd(); - if (debug) System.out.println("mv.visitEnd();\r\n\r\n\r\n"); - } - - public static void pushInt(MethodDebugVisitor mv, int num) { - if (num < 6) { - mv.visitInsn(ICONST_0 + num); - } else if (num <= Byte.MAX_VALUE) { - mv.visitIntInsn(BIPUSH, num); - } else if (num <= Short.MAX_VALUE) { - mv.visitIntInsn(SIPUSH, num); - } else { - mv.visitLdcInsn(num); - } - } - - public static void pushInt(MethodVisitor mv, int num) { - if (num < 6) { - mv.visitInsn(ICONST_0 + num); - } else if (num <= Byte.MAX_VALUE) { - mv.visitIntInsn(BIPUSH, num); - } else if (num <= Short.MAX_VALUE) { - mv.visitIntInsn(SIPUSH, num); - } else { - mv.visitLdcInsn(num); - } - } - - public static void visitAnnotation(final AnnotationVisitor av, final Annotation ann) { - try { - for (Method anm : ann.annotationType().getMethods()) { - final String mname = anm.getName(); - if ("equals".equals(mname) || "hashCode".equals(mname) || "toString".equals(mname) || "annotationType".equals(mname)) continue; - final Object r = anm.invoke(ann); - if (r instanceof String[]) { - AnnotationVisitor av1 = av.visitArray(mname); - for (String item : (String[]) r) { - av1.visit(null, item); - } - av1.visitEnd(); - } else if (r instanceof Class[]) { - AnnotationVisitor av1 = av.visitArray(mname); - for (Class item : (Class[]) r) { - av1.visit(null, Type.getType(item)); - } - av1.visitEnd(); - } else if (r instanceof Enum[]) { - AnnotationVisitor av1 = av.visitArray(mname); - for (Enum item : (Enum[]) r) { - av1.visitEnum(null, Type.getDescriptor(item.getClass()), ((Enum) item).name()); - } - av1.visitEnd(); - } else if (r instanceof Annotation[]) { - AnnotationVisitor av1 = av.visitArray(mname); - for (Annotation item : (Annotation[]) r) { - visitAnnotation(av1.visitAnnotation(null, Type.getDescriptor(((Annotation) item).annotationType())), item); - } - av1.visitEnd(); - } else if (r instanceof Class) { - av.visit(mname, Type.getType((Class) r)); - } else if (r instanceof Enum) { - av.visitEnum(mname, Type.getDescriptor(r.getClass()), ((Enum) r).name()); - } else if (r instanceof Annotation) { - visitAnnotation(av.visitAnnotation(null, Type.getDescriptor(((Annotation) r).annotationType())), (Annotation) r); - } else { - av.visit(mname, r); - } - } - av.visitEnd(); - } catch (Exception e) { - e.printStackTrace(); - } - } -} +/* + * 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.asm; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.util.*; +import static org.redkale.asm.Opcodes.*; + +/** + * MethodVisitor 鐨勮皟璇曠被 + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public class MethodDebugVisitor { + + private final MethodVisitor visitor; + + private boolean debug = false; + + public MethodDebugVisitor setDebug(boolean d) { + debug = d; + return this; + } + + public void debugLine() { + if (!debug) return; + System.out.println(); + System.out.println(); + System.out.println(); + } + + private final Map labels = new LinkedHashMap<>(); + + private static final String[] opcodes = new String[200]; //0 -18 + + static { + try { + for (java.lang.reflect.Field field : Opcodes.class.getFields()) { + String name = field.getName(); + if (name.startsWith("ASM")) continue; + if (name.startsWith("V1_")) continue; + if (name.startsWith("ACC_")) continue; + if (name.startsWith("T_")) continue; + if (name.startsWith("H_")) continue; + if (name.startsWith("F_")) continue; + if (field.getType() != int.class) continue; + opcodes[(int) (Integer) field.get(null)] = name; + } + } catch (Exception ex) { + throw new RuntimeException(ex); //涓嶅彲鑳戒細鍙戠敓 + } + } + + /** + * + * @param visitor MethodVisitor + */ + public MethodDebugVisitor(MethodVisitor visitor) { + //super(Opcodes.ASM5, visitor); + this.visitor = visitor; + } + + public void visitTryCatchBlock(Label start, Label end, Label handler, String type) { + visitor.visitTryCatchBlock(start, end, handler, type); + if (debug) System.out.println("mv.visitTryCatchBlock(label0, label1, label2, \"" + type + "\");"); + } + + public AnnotationVisitor visitParameterAnnotation(int i, String string, boolean bln) { + AnnotationVisitor av = visitor.visitParameterAnnotation(i, string, bln); + if (debug) System.out.println("mv.visitParameterAnnotation(" + i + ", \"" + string + "\", " + bln + ");"); + return av; + } + + public AnnotationVisitor visitAnnotation(String desc, boolean flag) { + AnnotationVisitor av = visitor.visitAnnotation(desc, flag); + if (debug) System.out.println("mv.visitAnnotation(\"" + desc + "\", " + flag + ");"); + return av; + } + + public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) { + AnnotationVisitor av = visitor.visitTypeAnnotation(typeRef, typePath, desc, visible); + if (debug) System.out.println("mv.visitTypeAnnotation(" + typeRef + ", " + typePath + ", \"" + desc + "\", " + visible + ");"); + return av; + } + + public void visitParameter(String name, int access) { + visitor.visitParameter(name, access); + if (debug) System.out.println("mv.visitParameter(" + name + ", " + access + ");"); + } + + public void visitVarInsn(int opcode, int var) { + visitor.visitVarInsn(opcode, var); + if (debug) System.out.println("mv.visitVarInsn(" + opcodes[opcode] + ", " + var + ");"); + } + + public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) { + visitor.visitFrame(type, nLocal, local, nStack, stack); + if (debug) { + String typestr = "" + type; + if (type == -1) { + typestr = "Opcodes.F_NEW"; + } else if (type == 1) { + typestr = "Opcodes.F_APPEND"; + } else if (type == 2) { + typestr = "Opcodes.F_CHOP"; + } else if (type == 3) { + typestr = "Opcodes.F_SAME"; + } else if (type == 4) { + typestr = "Opcodes.F_SAME1"; + } + System.out.println("mv.visitFrame(" + typestr + ", " + nLocal + ", " + Arrays.toString(local) + ", " + nStack + ", " + Arrays.toString(stack) + ");"); + } + } + + public void visitJumpInsn(int opcode, Label var) { //璋冪敤姝ゆ柟娉曠殑 ClassWriter 蹇呴』鐢 COMPUTE_FRAMES 鏋勫缓 + visitor.visitJumpInsn(opcode, var); + if (debug) { + Integer index = labels.get(var); + if (index == null) { + index = labels.size(); + labels.put(var, index); + System.out.println("Label l" + index + " = new Label();"); + } + System.out.println("mv.visitJumpInsn(" + opcodes[opcode] + ", l" + index + ");"); + } + } + + public void visitCode() { + visitor.visitCode(); + if (debug) System.out.println("mv.visitCode();"); + } + + public void visitLabel(Label var) { + visitor.visitLabel(var); + if (debug) { + Integer index = labels.get(var); + if (index == null) { + index = labels.size(); + labels.put(var, index); + System.out.println("Label l" + index + " = new Label();"); + } + System.out.println("mv.visitLabel(l" + index + ");"); + } + } + + public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { + visitor.visitMethodInsn(opcode, owner, name, desc, itf); + if (debug) System.out.println("mv.visitMethodInsn(" + opcodes[opcode] + ", \"" + owner + "\", \"" + name + "\", \"" + desc + "\", " + itf + ");"); + } + + public void visitFieldInsn(int opcode, String owner, String name, String desc) { + visitor.visitFieldInsn(opcode, owner, name, desc); + if (debug) System.out.println("mv.visitFieldInsn(" + opcodes[opcode] + ", \"" + owner + "\", \"" + name + "\", \"" + desc + "\");"); + } + + public void visitTypeInsn(int opcode, String type) { + visitor.visitTypeInsn(opcode, type); + if (debug) System.out.println("mv.visitTypeInsn(" + opcodes[opcode] + ", \"" + type + "\");"); + } + + public void visitInsn(int opcode) { + visitor.visitInsn(opcode); + if (debug) System.out.println("mv.visitInsn(" + opcodes[opcode] + ");"); + } + + public void visitIntInsn(int opcode, int value) { + visitor.visitIntInsn(opcode, value); + if (debug) System.out.println("mv.visitIntInsn(" + opcodes[opcode] + ", " + value + ");"); + } + + public void visitIincInsn(int opcode, int value) { + visitor.visitIincInsn(opcode, value); + if (debug) System.out.println("mv.visitIincInsn(" + opcode + ", " + value + ");"); + } + + public void visitLdcInsn(Object o) { + visitor.visitLdcInsn(o); + if (debug) { + if (o instanceof CharSequence) { + System.out.println("mv.visitLdcInsn(\"" + o + "\");"); + } else if (o instanceof org.redkale.asm.Type) { + System.out.println("mv.visitLdcInsn(Type.getType(\"" + o + "\"));"); + } else { + System.out.println("mv.visitLdcInsn(" + o + ");"); + } + } + } + + public void visitMaxs(int maxStack, int maxLocals) { + visitor.visitMaxs(maxStack, maxLocals); + if (debug) System.out.println("mv.visitMaxs(" + maxStack + ", " + maxLocals + ");"); + } + + public void visitEnd() { + visitor.visitEnd(); + if (debug) System.out.println("mv.visitEnd();\r\n\r\n\r\n"); + } + + public static void pushInt(MethodDebugVisitor mv, int num) { + if (num < 6) { + mv.visitInsn(ICONST_0 + num); + } else if (num <= Byte.MAX_VALUE) { + mv.visitIntInsn(BIPUSH, num); + } else if (num <= Short.MAX_VALUE) { + mv.visitIntInsn(SIPUSH, num); + } else { + mv.visitLdcInsn(num); + } + } + + public static void pushInt(MethodVisitor mv, int num) { + if (num < 6) { + mv.visitInsn(ICONST_0 + num); + } else if (num <= Byte.MAX_VALUE) { + mv.visitIntInsn(BIPUSH, num); + } else if (num <= Short.MAX_VALUE) { + mv.visitIntInsn(SIPUSH, num); + } else { + mv.visitLdcInsn(num); + } + } + + public static void visitAnnotation(final AnnotationVisitor av, final Annotation ann) { + try { + for (Method anm : ann.annotationType().getMethods()) { + final String mname = anm.getName(); + if ("equals".equals(mname) || "hashCode".equals(mname) || "toString".equals(mname) || "annotationType".equals(mname)) continue; + final Object r = anm.invoke(ann); + if (r instanceof String[]) { + AnnotationVisitor av1 = av.visitArray(mname); + for (String item : (String[]) r) { + av1.visit(null, item); + } + av1.visitEnd(); + } else if (r instanceof Class[]) { + AnnotationVisitor av1 = av.visitArray(mname); + for (Class item : (Class[]) r) { + av1.visit(null, Type.getType(item)); + } + av1.visitEnd(); + } else if (r instanceof Enum[]) { + AnnotationVisitor av1 = av.visitArray(mname); + for (Enum item : (Enum[]) r) { + av1.visitEnum(null, Type.getDescriptor(item.getClass()), ((Enum) item).name()); + } + av1.visitEnd(); + } else if (r instanceof Annotation[]) { + AnnotationVisitor av1 = av.visitArray(mname); + for (Annotation item : (Annotation[]) r) { + visitAnnotation(av1.visitAnnotation(null, Type.getDescriptor(((Annotation) item).annotationType())), item); + } + av1.visitEnd(); + } else if (r instanceof Class) { + av.visit(mname, Type.getType((Class) r)); + } else if (r instanceof Enum) { + av.visitEnum(mname, Type.getDescriptor(r.getClass()), ((Enum) r).name()); + } else if (r instanceof Annotation) { + visitAnnotation(av.visitAnnotation(null, Type.getDescriptor(((Annotation) r).annotationType())), (Annotation) r); + } else { + av.visit(mname, r); + } + } + av.visitEnd(); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/org/redkale/asm/asm.txt b/src/main/java/org/redkale/asm/asm.txt index f3f74d9ab..7719a4d13 100644 --- a/src/main/java/org/redkale/asm/asm.txt +++ b/src/main/java/org/redkale/asm/asm.txt @@ -1,27 +1,27 @@ -need copy classes: - -AnnotationVisitor.java -AnnotationWriter.java -Attribute.java -ByteVector.java -ClassReader.java -ClassVisitor.java -ClassWriter.java -Context.java -CurrentFrame.java -Edge.java -FieldVisitor.java -FieldWriter.java -Frame.java -Handle.java -Handler.java -Item.java -Label.java -MethodVisitor.java -MethodWriter.java -ModuleVisitor.java -ModuleWriter.java -Opcodes.java -Type.java -TypePath.java -TypeReference.java +need copy classes: + +AnnotationVisitor.java +AnnotationWriter.java +Attribute.java +ByteVector.java +ClassReader.java +ClassVisitor.java +ClassWriter.java +Context.java +CurrentFrame.java +Edge.java +FieldVisitor.java +FieldWriter.java +Frame.java +Handle.java +Handler.java +Item.java +Label.java +MethodVisitor.java +MethodWriter.java +ModuleVisitor.java +ModuleWriter.java +Opcodes.java +Type.java +TypePath.java +TypeReference.java diff --git a/src/main/java/org/redkale/asm/package-info.java b/src/main/java/org/redkale/asm/package-info.java index a0d8621f7..f91083ffa 100644 --- a/src/main/java/org/redkale/asm/package-info.java +++ b/src/main/java/org/redkale/asm/package-info.java @@ -1,4 +1,4 @@ -/** - * 鏈寘涓嬫墍鏈変唬鐮佸潎鏄粠/java.base/jdk/internal/org/objectweb/asm 鎷疯礉杩囨潵鐨 - */ -package org.redkale.asm; +/** + * 鏈寘涓嬫墍鏈変唬鐮佸潎鏄粠/java.base/jdk/internal/org/objectweb/asm 鎷疯礉杩囨潵鐨 + */ +package org.redkale.asm; diff --git a/src/main/java/org/redkale/boot/ApiDocsService.java b/src/main/java/org/redkale/boot/ApiDocsService.java index 7ad9f0782..12a65df87 100644 --- a/src/main/java/org/redkale/boot/ApiDocsService.java +++ b/src/main/java/org/redkale/boot/ApiDocsService.java @@ -1,535 +1,535 @@ -/* - * 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.boot; - -import java.io.*; -import java.lang.reflect.*; -import java.math.*; -import java.nio.charset.StandardCharsets; -import java.util.*; -import java.util.concurrent.atomic.*; -import java.util.logging.*; -import javax.persistence.*; -import org.redkale.convert.*; -import org.redkale.convert.json.*; -import org.redkale.mq.MessageMultiConsumer; -import org.redkale.net.http.*; -import org.redkale.service.RetResult; -import org.redkale.source.*; -import org.redkale.util.*; - -/** - * API鎺ュ彛鏂囨。鐢熸垚绫伙紝浣滅敤锛氱敓鎴怉pplication瀹炰緥涓墍鏈塇ttpServer鐨勫彲鐢℉ttpServlet鐨凙PI鎺ュ彛鏂规硶
- * 缁ф壙 HttpBaseServlet 鏄负浜嗚幏鍙 HttpMapping 淇℃伅
- * https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public final class ApiDocsService { - - private static final java.lang.reflect.Type TYPE_RETRESULT_OBJECT = new TypeToken>() { - }.getType(); - - private static final java.lang.reflect.Type TYPE_RETRESULT_STRING = new TypeToken>() { - }.getType(); - - private static final java.lang.reflect.Type TYPE_RETRESULT_INTEGER = new TypeToken>() { - }.getType(); - - private static final java.lang.reflect.Type TYPE_RETRESULT_LONG = new TypeToken>() { - }.getType(); - - private final Application app; //Application鍏ㄥ眬瀵硅薄 - - public ApiDocsService(Application app) { - this.app = app; - } - - public void run(String[] args) throws Exception { - //鏄惁璺宠繃RPC鎺ュ彛 - final boolean skipRPC = Arrays.toString(args).toLowerCase().contains("skip-rpc") && !Arrays.toString(args).toLowerCase().contains("skip-rpc=false"); - - List serverList = new ArrayList<>(); - Field __prefix = HttpServlet.class.getDeclaredField("_prefix"); - __prefix.setAccessible(true); - Map>> typesMap = new LinkedHashMap<>(); - //https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md - Map swaggerPathsMap = new LinkedHashMap<>(); - List swaggerServers = new ArrayList<>(); - List swaggerTags = new ArrayList<>(); - Map> swaggerComponentsMap = new LinkedHashMap<>(); - for (NodeServer node : app.servers) { - if (!(node instanceof NodeHttpServer)) continue; - final Map map = new LinkedHashMap<>(); - serverList.add(map); - HttpServer server = node.getServer(); - map.put("address", server.getSocketAddress()); - swaggerServers.add(Utility.ofMap("url", "http://localhost:" + server.getSocketAddress().getPort())); - List> servletsList = new ArrayList<>(); - map.put("servlets", servletsList); - String plainContentType = server.getResponseConfig() == null ? "application/json" : server.getResponseConfig().plainContentType; - if (plainContentType == null || plainContentType.isEmpty()) plainContentType = "application/json"; - if (plainContentType.indexOf(';') > 0) plainContentType = plainContentType.substring(0, plainContentType.indexOf(';')); - - for (HttpServlet servlet : server.getPrepareServlet().getServlets()) { - if (!(servlet instanceof HttpServlet)) continue; - if (servlet instanceof WebSocketServlet) continue; - if (servlet.getClass().getAnnotation(MessageMultiConsumer.class) != null) { - node.logger.log(Level.INFO, servlet + " be skipped because has @MessageMultiConsumer"); - continue; - } - WebServlet ws = servlet.getClass().getAnnotation(WebServlet.class); - if (ws == null) { - node.logger.log(Level.WARNING, servlet + " not found @WebServlet"); - continue; - } - if (ws.name().isEmpty()) { - node.logger.log(Level.INFO, servlet + " be skipped because @WebServlet.name is empty"); - continue; - } - final String tag = ws.name().isEmpty() ? servlet.getClass().getSimpleName().replace("Servlet", "").toLowerCase() : ws.name(); - final Map servletMap = new LinkedHashMap<>(); - String prefix = (String) __prefix.get(servlet); - String[] urlregs = ws.value(); - if (prefix != null && !prefix.isEmpty()) { - for (int i = 0; i < urlregs.length; i++) { - urlregs[i] = prefix + urlregs[i]; - } - } - servletMap.put("urlregs", urlregs); - servletMap.put("moduleid", ws.moduleid()); - servletMap.put("name", ws.name()); - servletMap.put("comment", ws.comment()); - - List mappingsList = new ArrayList<>(); - servletMap.put("mappings", mappingsList); - final Class selfClz = servlet.getClass(); - Class clz = servlet.getClass(); - HashSet actionUrls = new HashSet<>(); - do { - if (Modifier.isAbstract(clz.getModifiers())) break; - for (Method method : clz.getMethods()) { - if (method.getParameterCount() != 2) continue; - HttpMapping action = method.getAnnotation(HttpMapping.class); - if (action == null) continue; - if (!action.inherited() && selfClz != clz) continue; //蹇界暐涓嶈缁ф壙鐨勬柟娉 - if (actionUrls.contains(action.url())) continue; - if (HttpScope.class.isAssignableFrom(action.result())) continue; //蹇界暐妯℃澘寮曟搸鐨勬柟娉 - if (action.rpconly() && skipRPC) continue; //涓嶇敓鎴怰PC鎺ュ彛 - - final List> swaggerParamsList = new ArrayList<>(); - - final Map mappingMap = new LinkedHashMap<>(); - mappingMap.put("url", prefix + action.url()); - actionUrls.add(action.url()); - mappingMap.put("auth", action.auth()); - mappingMap.put("actionid", action.actionid()); - mappingMap.put("comment", action.comment()); - List paramsList = new ArrayList<>(); - mappingMap.put("params", paramsList); - List results = new ArrayList<>(); - Type resultType = action.result(); - if (!action.resultref().isEmpty()) { - Field f = servlet.getClass().getDeclaredField(action.resultref()); - f.setAccessible(true); - resultType = (Type) f.get(servlet); - } -// for (final Class rtype : action.results()) { -// results.add(rtype.getName()); -// if (typesMap.containsKey(rtype.getName())) continue; -// if (rtype.getName().startsWith("java.")) continue; -// if (rtype.getName().startsWith("javax.")) continue; -// final boolean filter = FilterBean.class.isAssignableFrom(rtype); -// final Map> typeMap = new LinkedHashMap<>(); -// Class loop = rtype; -// do { -// if (loop == null || loop.isInterface()) break; -// for (Field field : loop.getDeclaredFields()) { -// if (Modifier.isFinal(field.getModifiers())) continue; -// if (Modifier.isStatic(field.getModifiers())) continue; -// -// Map fieldmap = new LinkedHashMap<>(); -// fieldmap.put("type", field.getType().isArray() ? (field.getType().getComponentType().getName() + "[]") : field.getGenericType().getTypeName()); -// -// Comment comment = field.getAnnotation(Comment.class); -// Column col = field.getAnnotation(Column.class); -// FilterColumn fc = field.getAnnotation(FilterColumn.class); -// if (comment != null) { -// fieldmap.put("comment", comment.value()); -// } else if (col != null) { -// fieldmap.put("comment", col.comment()); -// } else if (fc != null) { -// fieldmap.put("comment", fc.comment()); -// } -// fieldmap.put("primary", !filter && (field.getAnnotation(Id.class) != null)); -// fieldmap.put("updatable", (filter || col == null || col.updatable())); -// if (servlet.getClass().getAnnotation(Rest.RestDyn.class) != null) { -// if (field.getAnnotation(RestAddress.class) != null) continue; -// } -// -// typeMap.put(field.getName(), fieldmap); -// } -// } while ((loop = loop.getSuperclass()) != Object.class); -// typesMap.put(rtype.getName(), typeMap); -// } - mappingMap.put("results", results); - boolean hasbodyparam = false; - Map swaggerRequestBody = new LinkedHashMap<>(); - for (HttpParam param : method.getAnnotationsByType(HttpParam.class)) { - final Map oldapisParamMap = new LinkedHashMap<>(); - final boolean isarray = param.type().isArray(); - final Class ptype = isarray ? param.type().getComponentType() : param.type(); - oldapisParamMap.put("name", param.name()); - oldapisParamMap.put("radix", param.radix()); - oldapisParamMap.put("type", ptype.getName() + (isarray ? "[]" : "")); - oldapisParamMap.put("style", param.style()); - oldapisParamMap.put("comment", param.comment()); - oldapisParamMap.put("required", param.required()); - paramsList.add(oldapisParamMap); - { - final Map paramSchemaMap = new LinkedHashMap<>(); - Type paramGenericType = param.type(); - if (!param.typeref().isEmpty()) { - Field f = servlet.getClass().getDeclaredField(param.typeref()); - f.setAccessible(true); - paramGenericType = (Type) f.get(servlet); - } - simpleSchemaType(node.getLogger(), swaggerComponentsMap, param.type(), paramGenericType, paramSchemaMap, true); - if (param.style() == HttpParam.HttpParameterStyle.BODY) { - swaggerRequestBody.put("description", param.comment()); - swaggerRequestBody.put("content", Utility.ofMap(plainContentType, Utility.ofMap("schema", paramSchemaMap))); - } else { - final Map swaggerParamMap = new LinkedHashMap<>(); - swaggerParamMap.put("name", param.name()); - swaggerParamMap.put("in", param.style().name().toLowerCase()); - swaggerParamMap.put("description", param.comment()); - swaggerParamMap.put("required", param.required()); - if (param.deprecated()) { - swaggerParamMap.put("deprecated", param.deprecated()); - } - //https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#parameterStyle - swaggerParamMap.put("style", param.style() == HttpParam.HttpParameterStyle.HEADER || param.name().indexOf('#') == 0 ? "simple" : "form"); - swaggerParamMap.put("explode", true); - swaggerParamMap.put("schema", paramSchemaMap); - Object example = formatExample(param.example(), param.type(), paramGenericType); - if (example != null) swaggerParamMap.put("example", example); - if (!param.example().isEmpty()) { - swaggerParamMap.put("example", param.example()); - } - swaggerParamsList.add(swaggerParamMap); - } - } - if (param.style() == HttpParam.HttpParameterStyle.BODY) hasbodyparam = true; - if (ptype.isPrimitive() || ptype == String.class) continue; - if (typesMap.containsKey(ptype.getName())) continue; - if (ptype.getName().startsWith("java.")) continue; - if (ptype.getName().startsWith("javax.")) continue; - - final Map> typeMap = new LinkedHashMap<>(); - Class loop = ptype; - final boolean filter = FilterBean.class.isAssignableFrom(loop); - do { - if (loop == null || loop.isInterface()) break; - for (Field field : loop.getDeclaredFields()) { - if (Modifier.isFinal(field.getModifiers())) continue; - if (Modifier.isStatic(field.getModifiers())) continue; - - Map fieldmap = new LinkedHashMap<>(); - fieldmap.put("type", field.getType().isArray() ? (field.getType().getComponentType().getName() + "[]") : field.getGenericType().getTypeName()); - - Column col = field.getAnnotation(Column.class); - FilterColumn fc = field.getAnnotation(FilterColumn.class); - Comment comment = field.getAnnotation(Comment.class); - if (comment != null) { - fieldmap.put("comment", comment.value()); - } else if (col != null) { - fieldmap.put("comment", col.comment()); - } else if (fc != null) { - fieldmap.put("comment", fc.comment()); - } - fieldmap.put("primary", !filter && (field.getAnnotation(Id.class) != null)); - fieldmap.put("updatable", (filter || col == null || col.updatable())); - - if (servlet.getClass().getAnnotation(Rest.RestDyn.class) != null) { - if (field.getAnnotation(RestAddress.class) != null) continue; - } - - typeMap.put(field.getName(), fieldmap); - } - } while ((loop = loop.getSuperclass()) != Object.class); - - typesMap.put(ptype.getName(), typeMap); - } - mappingMap.put("result", action.result().getSimpleName().replace("void", "Object")); - mappingsList.add(mappingMap); - - final Map swaggerOperatMap = new LinkedHashMap<>(); - swaggerOperatMap.put("tags", new String[]{tag}); - swaggerOperatMap.put("operationId", action.name()); - if (method.getAnnotation(Deprecated.class) != null) { - swaggerOperatMap.put("deprecated", true); - } - Map respSchemaMap = new LinkedHashMap<>(); - simpleSchemaType(node.getLogger(), swaggerComponentsMap, action.result(), resultType, respSchemaMap, true); - - Map respMap = new LinkedHashMap<>(); - respMap.put("schema", respSchemaMap); - Object example = formatExample(action.example(), action.result(), resultType); - if (example != null) swaggerOperatMap.put("example", example); - if (!swaggerRequestBody.isEmpty()) swaggerOperatMap.put("requestBody", swaggerRequestBody); - swaggerOperatMap.put("parameters", swaggerParamsList); - String actiondesc = action.comment(); - if (action.rpconly()) actiondesc = "[Only for RPC API] " + actiondesc; - swaggerOperatMap.put("responses", Utility.ofMap("200", Utility.ofMap("description", actiondesc, "content", Utility.ofMap("application/json", respMap)))); - - String m = action.methods() == null || action.methods().length == 0 ? null : action.methods()[0].toLowerCase(); - if (m == null) { - m = hasbodyparam || TYPE_RETRESULT_STRING.equals(resultType) || TYPE_RETRESULT_INTEGER.equals(resultType) - || TYPE_RETRESULT_LONG.equals(resultType) || action.name().contains("create") || action.name().contains("insert") - || action.name().contains("update") || action.name().contains("delete") || action.name().contains("send") ? "post" : "get"; - } - swaggerPathsMap.put(prefix + action.url(), Utility.ofMap("description", action.comment(), m, swaggerOperatMap)); - } - } while ((clz = clz.getSuperclass()) != HttpServlet.class); - mappingsList.sort((o1, o2) -> ((String) o1.get("url")).compareTo((String) o2.get("url"))); - servletsList.add(servletMap); - if (!actionUrls.isEmpty()) swaggerTags.add(Utility.ofMap("name", tag, "description", ws.comment())); - } - servletsList.sort((o1, o2) -> { - String[] urlregs1 = (String[]) o1.get("urlregs"); - String[] urlregs2 = (String[]) o2.get("urlregs"); - return urlregs1.length > 0 ? (urlregs2.length > 0 ? urlregs1[0].compareTo(urlregs2[0]) : 1) : -1; - }); - } - { // https://github.com/OAI/OpenAPI-Specification - Map swaggerResultMap = new LinkedHashMap<>(); - swaggerResultMap.put("openapi", "3.0.0"); - Map infomap = new LinkedHashMap<>(); - infomap.put("title", "Redkale generate apidoc"); - infomap.put("version", "1.0.0"); - swaggerResultMap.put("info", infomap); - swaggerResultMap.put("servers", swaggerServers); - swaggerResultMap.put("paths", swaggerPathsMap); - swaggerResultMap.put("tags", swaggerTags); - if (!swaggerComponentsMap.isEmpty()) swaggerResultMap.put("components", Utility.ofMap("schemas", swaggerComponentsMap)); - final FileOutputStream out = new FileOutputStream(new File(app.getHome(), "openapi-doc.json")); - out.write(JsonConvert.root().convertTo(swaggerResultMap).getBytes(StandardCharsets.UTF_8)); - out.close(); - } - { - Map oldapisResultMap = new LinkedHashMap<>(); - oldapisResultMap.put("servers", serverList); - oldapisResultMap.put("types", typesMap); - final String json = JsonConvert.root().convertTo(oldapisResultMap); - final FileOutputStream out = new FileOutputStream(new File(app.getHome(), "apidoc.json")); - out.write(json.getBytes(StandardCharsets.UTF_8)); - out.close(); - File doctemplate = new File(app.getConfPath().toString(), "apidoc-template.html"); - InputStream in = null; - if (doctemplate.isFile() && doctemplate.canRead()) { - in = new FileInputStream(doctemplate); - } - if (in == null) in = ApiDocsService.class.getResourceAsStream("apidoc-template.html"); - String content = Utility.read(in).replace("'${content}'", json); - in.close(); - FileOutputStream outhtml = new FileOutputStream(new File(app.getHome(), "apidoc.html")); - outhtml.write(content.getBytes(StandardCharsets.UTF_8)); - outhtml.close(); - } - } - - private static void simpleSchemaType(Logger logger, Map> componentsMap, Class type, Type genericType, Map schemaMap, boolean recursive) { - if (type == int.class || type == Integer.class || type == AtomicInteger.class) { - schemaMap.put("type", "integer"); - schemaMap.put("format", "int32"); - } else if (type == long.class || type == Long.class - || type == AtomicLong.class || type == LongAdder.class || type == BigInteger.class) { - schemaMap.put("type", "integer"); - schemaMap.put("format", "int64"); - } else if (type == float.class || type == Float.class) { - schemaMap.put("type", "number"); - schemaMap.put("format", "float"); - } else if (type == double.class || type == Double.class || type == BigDecimal.class) { - schemaMap.put("type", "number"); - schemaMap.put("format", "double"); - } else if (type == boolean.class || type == Boolean.class || type == AtomicBoolean.class) { - schemaMap.put("type", "boolean"); - } else if (type.isPrimitive() || Number.class.isAssignableFrom(type)) { - schemaMap.put("type", "number"); - } else if (type == String.class || CharSequence.class.isAssignableFrom(type)) { - schemaMap.put("type", "string"); - } else if (recursive && (type.isArray() || Collection.class.isAssignableFrom(type))) { - schemaMap.put("type", "array"); - Map sbumap = new LinkedHashMap<>(); - if (type.isArray()) { - simpleSchemaType(logger, componentsMap, type.getComponentType(), type.getComponentType(), sbumap, false); - } else if (genericType instanceof ParameterizedType) { - Type subpt = ((ParameterizedType) genericType).getActualTypeArguments()[0]; - if (subpt instanceof Class) { - simpleSchemaType(logger, componentsMap, (Class) subpt, subpt, sbumap, false); - } else if (subpt instanceof ParameterizedType && ((ParameterizedType) subpt).getOwnerType() instanceof Class) { - simpleSchemaType(logger, componentsMap, (Class) ((ParameterizedType) subpt).getOwnerType(), subpt, sbumap, false); - } else { - sbumap.put("type", "object"); - } - } else { - sbumap.put("type", "object"); - } - schemaMap.put("items", sbumap); - } else if (!type.getName().startsWith("java.") && !type.getName().startsWith("javax.")) { - String ct = simpleComponentType(logger, componentsMap, type, genericType); - if (ct == null) { - schemaMap.put("type", "object"); - } else { - schemaMap.put("$ref", "#/components/schemas/" + ct); - } - } else { - schemaMap.put("type", "object"); - } - } - - private static String simpleComponentType(Logger logger, Map> componentsMap, Class type, Type genericType) { - try { - Encodeable encodeable = JsonFactory.root().loadEncoder(genericType); - String ct = componentKey(logger, componentsMap, null, encodeable, true); - if (ct == null || ct.length() == 0) return null; - if (componentsMap.containsKey(ct)) return ct; - Map cmap = new LinkedHashMap<>(); - componentsMap.put(ct, cmap); //蹇呴』鍦ㄨ皟鐢╯impleSchemaType涔嬪墠put锛屼笉鐒跺祵濂楁儏鍐典笅姝诲惊鐜 - - cmap.put("type", "object"); - List requireds = new ArrayList<>(); - Map properties = new LinkedHashMap<>(); - if (encodeable instanceof ObjectEncoder) { - for (EnMember member : ((ObjectEncoder) encodeable).getMembers()) { - Map schemaMap = new LinkedHashMap<>(); - simpleSchemaType(logger, componentsMap, TypeToken.typeToClassOrElse(member.getEncoder().getType(), Object.class), member.getEncoder().getType(), schemaMap, true); - String desc = ""; - if (member.getField() != null) { - Column col = member.getField().getAnnotation(Column.class); - if (col == null) { - FilterColumn fcol = member.getField().getAnnotation(FilterColumn.class); - if (fcol != null) { - desc = fcol.comment(); - if (fcol.required()) requireds.add(member.getAttribute().field()); - } - } else { - desc = col.comment(); - if (!col.nullable()) requireds.add(member.getAttribute().field()); - } - if (desc.isEmpty() && member.getField().getAnnotation(Comment.class) != null) { - desc = member.getField().getAnnotation(Comment.class).value(); - } - } else if (member.getMethod() != null) { - Column col = member.getMethod().getAnnotation(Column.class); - if (col == null) { - FilterColumn fcol = member.getMethod().getAnnotation(FilterColumn.class); - if (fcol != null) { - desc = fcol.comment(); - if (fcol.required()) requireds.add(member.getAttribute().field()); - } - } else { - desc = col.comment(); - if (!col.nullable()) requireds.add(member.getAttribute().field()); - } - if (desc.isEmpty() && member.getMethod().getAnnotation(Comment.class) != null) { - desc = member.getMethod().getAnnotation(Comment.class).value(); - } - } - if (!desc.isEmpty()) schemaMap.put("description", desc); - properties.put(member.getAttribute().field(), schemaMap); - } - } - if (!requireds.isEmpty()) cmap.put("required", requireds); - cmap.put("properties", properties); - return ct; - } catch (Exception e) { - logger.log(Level.WARNING, genericType + " generate component info error", e); - return null; - } - } - - private static String componentKey(Logger logger, Map> componentsMap, EnMember field, Encodeable encodeable, boolean first) { - if (encodeable instanceof ObjectEncoder) { - StringBuilder sb = new StringBuilder(); - sb.append(((ObjectEncoder) encodeable).getTypeClass().getSimpleName()); - for (EnMember member : ((ObjectEncoder) encodeable).getMembers()) { - if (member.getEncoder() instanceof ArrayEncoder - || member.getEncoder() instanceof CollectionEncoder) { - String subsb = componentKey(logger, componentsMap, member, member.getEncoder(), false); - if (subsb == null) return null; - AccessibleObject real = member.getField() == null ? member.getMethod() : member.getField(); - if (real == null) continue; - Class cz = real instanceof Field ? ((Field) real).getType() : ((Method) real).getReturnType(); - Type ct = real instanceof Field ? ((Field) real).getGenericType() : ((Method) real).getGenericReturnType(); - if (cz == ct) continue; - if (sb.length() > 0 && subsb.length() > 0) sb.append("_"); - sb.append(subsb); - } else if (member.getEncoder() instanceof ObjectEncoder || member.getEncoder() instanceof SimpledCoder) { - AccessibleObject real = member.getField() == null ? member.getMethod() : member.getField(); - if (real == null) continue; - if (member.getEncoder() instanceof SimpledCoder) { - simpleSchemaType(logger, componentsMap, ((SimpledCoder) member.getEncoder()).getType(), ((SimpledCoder) member.getEncoder()).getType(), new LinkedHashMap<>(), true); - } else { - simpleSchemaType(logger, componentsMap, ((ObjectEncoder) member.getEncoder()).getTypeClass(), ((ObjectEncoder) member.getEncoder()).getType(), new LinkedHashMap<>(), true); - } - Class cz = real instanceof Field ? ((Field) real).getType() : ((Method) real).getReturnType(); - Type ct = real instanceof Field ? ((Field) real).getGenericType() : ((Method) real).getGenericReturnType(); - if (cz == ct) continue; - String subsb = componentKey(logger, componentsMap, member, member.getEncoder(), false); - if (subsb == null) return null; - if (sb.length() > 0 && subsb.length() > 0) sb.append("_"); - sb.append(subsb); - } else if (member.getEncoder() instanceof MapEncoder) { - continue; - } else { - return null; - } - } - return sb.toString(); - } else if (encodeable instanceof ArrayEncoder || encodeable instanceof CollectionEncoder) { - final boolean array = (encodeable instanceof ArrayEncoder); - Encodeable subEncodeable = array ? ((ArrayEncoder) encodeable).getComponentEncoder() : ((CollectionEncoder) encodeable).getComponentEncoder(); - if (subEncodeable instanceof SimpledCoder && field != null) return ""; - final String sb = componentKey(logger, componentsMap, null, subEncodeable, false); - if (sb == null || sb.isEmpty()) return sb; - if (field != null && field.getField() != null && field.getField().getDeclaringClass() == Sheet.class) { - return sb; - } - return sb + (array ? "_Array" : "_Collection"); - } else if (encodeable instanceof SimpledCoder) { - Class stype = ((SimpledCoder) encodeable).getType(); - if (stype.isPrimitive() || stype == Boolean.class || Number.class.isAssignableFrom(stype) || CharSequence.class.isAssignableFrom(stype)) { - return stype.getSimpleName(); - } - return ""; - } else if (encodeable instanceof MapEncoder) { - return first ? null : ""; - } else { - return null; - } - } - - private static Object formatExample(String example, Class type, Type genericType) { - if (example == null || example.isEmpty()) return null; - if (type == Flipper.class) { - return new Flipper(); - } else if (TYPE_RETRESULT_OBJECT.equals(genericType)) { - return RetResult.success(); - } else if (TYPE_RETRESULT_STRING.equals(genericType)) { - return RetResult.success(); - } else if (TYPE_RETRESULT_INTEGER.equals(genericType)) { - return RetResult.success(0); - } else if (TYPE_RETRESULT_LONG.equals(genericType)) { - return RetResult.success(0L); - } - return example; - } - -} +/* + * 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.boot; + +import java.io.*; +import java.lang.reflect.*; +import java.math.*; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.concurrent.atomic.*; +import java.util.logging.*; +import javax.persistence.*; +import org.redkale.convert.*; +import org.redkale.convert.json.*; +import org.redkale.mq.MessageMultiConsumer; +import org.redkale.net.http.*; +import org.redkale.service.RetResult; +import org.redkale.source.*; +import org.redkale.util.*; + +/** + * API鎺ュ彛鏂囨。鐢熸垚绫伙紝浣滅敤锛氱敓鎴怉pplication瀹炰緥涓墍鏈塇ttpServer鐨勫彲鐢℉ttpServlet鐨凙PI鎺ュ彛鏂规硶
+ * 缁ф壙 HttpBaseServlet 鏄负浜嗚幏鍙 HttpMapping 淇℃伅
+ * https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public final class ApiDocsService { + + private static final java.lang.reflect.Type TYPE_RETRESULT_OBJECT = new TypeToken>() { + }.getType(); + + private static final java.lang.reflect.Type TYPE_RETRESULT_STRING = new TypeToken>() { + }.getType(); + + private static final java.lang.reflect.Type TYPE_RETRESULT_INTEGER = new TypeToken>() { + }.getType(); + + private static final java.lang.reflect.Type TYPE_RETRESULT_LONG = new TypeToken>() { + }.getType(); + + private final Application app; //Application鍏ㄥ眬瀵硅薄 + + public ApiDocsService(Application app) { + this.app = app; + } + + public void run(String[] args) throws Exception { + //鏄惁璺宠繃RPC鎺ュ彛 + final boolean skipRPC = Arrays.toString(args).toLowerCase().contains("skip-rpc") && !Arrays.toString(args).toLowerCase().contains("skip-rpc=false"); + + List serverList = new ArrayList<>(); + Field __prefix = HttpServlet.class.getDeclaredField("_prefix"); + __prefix.setAccessible(true); + Map>> typesMap = new LinkedHashMap<>(); + //https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md + Map swaggerPathsMap = new LinkedHashMap<>(); + List swaggerServers = new ArrayList<>(); + List swaggerTags = new ArrayList<>(); + Map> swaggerComponentsMap = new LinkedHashMap<>(); + for (NodeServer node : app.servers) { + if (!(node instanceof NodeHttpServer)) continue; + final Map map = new LinkedHashMap<>(); + serverList.add(map); + HttpServer server = node.getServer(); + map.put("address", server.getSocketAddress()); + swaggerServers.add(Utility.ofMap("url", "http://localhost:" + server.getSocketAddress().getPort())); + List> servletsList = new ArrayList<>(); + map.put("servlets", servletsList); + String plainContentType = server.getResponseConfig() == null ? "application/json" : server.getResponseConfig().plainContentType; + if (plainContentType == null || plainContentType.isEmpty()) plainContentType = "application/json"; + if (plainContentType.indexOf(';') > 0) plainContentType = plainContentType.substring(0, plainContentType.indexOf(';')); + + for (HttpServlet servlet : server.getPrepareServlet().getServlets()) { + if (!(servlet instanceof HttpServlet)) continue; + if (servlet instanceof WebSocketServlet) continue; + if (servlet.getClass().getAnnotation(MessageMultiConsumer.class) != null) { + node.logger.log(Level.INFO, servlet + " be skipped because has @MessageMultiConsumer"); + continue; + } + WebServlet ws = servlet.getClass().getAnnotation(WebServlet.class); + if (ws == null) { + node.logger.log(Level.WARNING, servlet + " not found @WebServlet"); + continue; + } + if (ws.name().isEmpty()) { + node.logger.log(Level.INFO, servlet + " be skipped because @WebServlet.name is empty"); + continue; + } + final String tag = ws.name().isEmpty() ? servlet.getClass().getSimpleName().replace("Servlet", "").toLowerCase() : ws.name(); + final Map servletMap = new LinkedHashMap<>(); + String prefix = (String) __prefix.get(servlet); + String[] urlregs = ws.value(); + if (prefix != null && !prefix.isEmpty()) { + for (int i = 0; i < urlregs.length; i++) { + urlregs[i] = prefix + urlregs[i]; + } + } + servletMap.put("urlregs", urlregs); + servletMap.put("moduleid", ws.moduleid()); + servletMap.put("name", ws.name()); + servletMap.put("comment", ws.comment()); + + List mappingsList = new ArrayList<>(); + servletMap.put("mappings", mappingsList); + final Class selfClz = servlet.getClass(); + Class clz = servlet.getClass(); + HashSet actionUrls = new HashSet<>(); + do { + if (Modifier.isAbstract(clz.getModifiers())) break; + for (Method method : clz.getMethods()) { + if (method.getParameterCount() != 2) continue; + HttpMapping action = method.getAnnotation(HttpMapping.class); + if (action == null) continue; + if (!action.inherited() && selfClz != clz) continue; //蹇界暐涓嶈缁ф壙鐨勬柟娉 + if (actionUrls.contains(action.url())) continue; + if (HttpScope.class.isAssignableFrom(action.result())) continue; //蹇界暐妯℃澘寮曟搸鐨勬柟娉 + if (action.rpconly() && skipRPC) continue; //涓嶇敓鎴怰PC鎺ュ彛 + + final List> swaggerParamsList = new ArrayList<>(); + + final Map mappingMap = new LinkedHashMap<>(); + mappingMap.put("url", prefix + action.url()); + actionUrls.add(action.url()); + mappingMap.put("auth", action.auth()); + mappingMap.put("actionid", action.actionid()); + mappingMap.put("comment", action.comment()); + List paramsList = new ArrayList<>(); + mappingMap.put("params", paramsList); + List results = new ArrayList<>(); + Type resultType = action.result(); + if (!action.resultref().isEmpty()) { + Field f = servlet.getClass().getDeclaredField(action.resultref()); + f.setAccessible(true); + resultType = (Type) f.get(servlet); + } +// for (final Class rtype : action.results()) { +// results.add(rtype.getName()); +// if (typesMap.containsKey(rtype.getName())) continue; +// if (rtype.getName().startsWith("java.")) continue; +// if (rtype.getName().startsWith("javax.")) continue; +// final boolean filter = FilterBean.class.isAssignableFrom(rtype); +// final Map> typeMap = new LinkedHashMap<>(); +// Class loop = rtype; +// do { +// if (loop == null || loop.isInterface()) break; +// for (Field field : loop.getDeclaredFields()) { +// if (Modifier.isFinal(field.getModifiers())) continue; +// if (Modifier.isStatic(field.getModifiers())) continue; +// +// Map fieldmap = new LinkedHashMap<>(); +// fieldmap.put("type", field.getType().isArray() ? (field.getType().getComponentType().getName() + "[]") : field.getGenericType().getTypeName()); +// +// Comment comment = field.getAnnotation(Comment.class); +// Column col = field.getAnnotation(Column.class); +// FilterColumn fc = field.getAnnotation(FilterColumn.class); +// if (comment != null) { +// fieldmap.put("comment", comment.value()); +// } else if (col != null) { +// fieldmap.put("comment", col.comment()); +// } else if (fc != null) { +// fieldmap.put("comment", fc.comment()); +// } +// fieldmap.put("primary", !filter && (field.getAnnotation(Id.class) != null)); +// fieldmap.put("updatable", (filter || col == null || col.updatable())); +// if (servlet.getClass().getAnnotation(Rest.RestDyn.class) != null) { +// if (field.getAnnotation(RestAddress.class) != null) continue; +// } +// +// typeMap.put(field.getName(), fieldmap); +// } +// } while ((loop = loop.getSuperclass()) != Object.class); +// typesMap.put(rtype.getName(), typeMap); +// } + mappingMap.put("results", results); + boolean hasbodyparam = false; + Map swaggerRequestBody = new LinkedHashMap<>(); + for (HttpParam param : method.getAnnotationsByType(HttpParam.class)) { + final Map oldapisParamMap = new LinkedHashMap<>(); + final boolean isarray = param.type().isArray(); + final Class ptype = isarray ? param.type().getComponentType() : param.type(); + oldapisParamMap.put("name", param.name()); + oldapisParamMap.put("radix", param.radix()); + oldapisParamMap.put("type", ptype.getName() + (isarray ? "[]" : "")); + oldapisParamMap.put("style", param.style()); + oldapisParamMap.put("comment", param.comment()); + oldapisParamMap.put("required", param.required()); + paramsList.add(oldapisParamMap); + { + final Map paramSchemaMap = new LinkedHashMap<>(); + Type paramGenericType = param.type(); + if (!param.typeref().isEmpty()) { + Field f = servlet.getClass().getDeclaredField(param.typeref()); + f.setAccessible(true); + paramGenericType = (Type) f.get(servlet); + } + simpleSchemaType(node.getLogger(), swaggerComponentsMap, param.type(), paramGenericType, paramSchemaMap, true); + if (param.style() == HttpParam.HttpParameterStyle.BODY) { + swaggerRequestBody.put("description", param.comment()); + swaggerRequestBody.put("content", Utility.ofMap(plainContentType, Utility.ofMap("schema", paramSchemaMap))); + } else { + final Map swaggerParamMap = new LinkedHashMap<>(); + swaggerParamMap.put("name", param.name()); + swaggerParamMap.put("in", param.style().name().toLowerCase()); + swaggerParamMap.put("description", param.comment()); + swaggerParamMap.put("required", param.required()); + if (param.deprecated()) { + swaggerParamMap.put("deprecated", param.deprecated()); + } + //https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#parameterStyle + swaggerParamMap.put("style", param.style() == HttpParam.HttpParameterStyle.HEADER || param.name().indexOf('#') == 0 ? "simple" : "form"); + swaggerParamMap.put("explode", true); + swaggerParamMap.put("schema", paramSchemaMap); + Object example = formatExample(param.example(), param.type(), paramGenericType); + if (example != null) swaggerParamMap.put("example", example); + if (!param.example().isEmpty()) { + swaggerParamMap.put("example", param.example()); + } + swaggerParamsList.add(swaggerParamMap); + } + } + if (param.style() == HttpParam.HttpParameterStyle.BODY) hasbodyparam = true; + if (ptype.isPrimitive() || ptype == String.class) continue; + if (typesMap.containsKey(ptype.getName())) continue; + if (ptype.getName().startsWith("java.")) continue; + if (ptype.getName().startsWith("javax.")) continue; + + final Map> typeMap = new LinkedHashMap<>(); + Class loop = ptype; + final boolean filter = FilterBean.class.isAssignableFrom(loop); + do { + if (loop == null || loop.isInterface()) break; + for (Field field : loop.getDeclaredFields()) { + if (Modifier.isFinal(field.getModifiers())) continue; + if (Modifier.isStatic(field.getModifiers())) continue; + + Map fieldmap = new LinkedHashMap<>(); + fieldmap.put("type", field.getType().isArray() ? (field.getType().getComponentType().getName() + "[]") : field.getGenericType().getTypeName()); + + Column col = field.getAnnotation(Column.class); + FilterColumn fc = field.getAnnotation(FilterColumn.class); + Comment comment = field.getAnnotation(Comment.class); + if (comment != null) { + fieldmap.put("comment", comment.value()); + } else if (col != null) { + fieldmap.put("comment", col.comment()); + } else if (fc != null) { + fieldmap.put("comment", fc.comment()); + } + fieldmap.put("primary", !filter && (field.getAnnotation(Id.class) != null)); + fieldmap.put("updatable", (filter || col == null || col.updatable())); + + if (servlet.getClass().getAnnotation(Rest.RestDyn.class) != null) { + if (field.getAnnotation(RestAddress.class) != null) continue; + } + + typeMap.put(field.getName(), fieldmap); + } + } while ((loop = loop.getSuperclass()) != Object.class); + + typesMap.put(ptype.getName(), typeMap); + } + mappingMap.put("result", action.result().getSimpleName().replace("void", "Object")); + mappingsList.add(mappingMap); + + final Map swaggerOperatMap = new LinkedHashMap<>(); + swaggerOperatMap.put("tags", new String[]{tag}); + swaggerOperatMap.put("operationId", action.name()); + if (method.getAnnotation(Deprecated.class) != null) { + swaggerOperatMap.put("deprecated", true); + } + Map respSchemaMap = new LinkedHashMap<>(); + simpleSchemaType(node.getLogger(), swaggerComponentsMap, action.result(), resultType, respSchemaMap, true); + + Map respMap = new LinkedHashMap<>(); + respMap.put("schema", respSchemaMap); + Object example = formatExample(action.example(), action.result(), resultType); + if (example != null) swaggerOperatMap.put("example", example); + if (!swaggerRequestBody.isEmpty()) swaggerOperatMap.put("requestBody", swaggerRequestBody); + swaggerOperatMap.put("parameters", swaggerParamsList); + String actiondesc = action.comment(); + if (action.rpconly()) actiondesc = "[Only for RPC API] " + actiondesc; + swaggerOperatMap.put("responses", Utility.ofMap("200", Utility.ofMap("description", actiondesc, "content", Utility.ofMap("application/json", respMap)))); + + String m = action.methods() == null || action.methods().length == 0 ? null : action.methods()[0].toLowerCase(); + if (m == null) { + m = hasbodyparam || TYPE_RETRESULT_STRING.equals(resultType) || TYPE_RETRESULT_INTEGER.equals(resultType) + || TYPE_RETRESULT_LONG.equals(resultType) || action.name().contains("create") || action.name().contains("insert") + || action.name().contains("update") || action.name().contains("delete") || action.name().contains("send") ? "post" : "get"; + } + swaggerPathsMap.put(prefix + action.url(), Utility.ofMap("description", action.comment(), m, swaggerOperatMap)); + } + } while ((clz = clz.getSuperclass()) != HttpServlet.class); + mappingsList.sort((o1, o2) -> ((String) o1.get("url")).compareTo((String) o2.get("url"))); + servletsList.add(servletMap); + if (!actionUrls.isEmpty()) swaggerTags.add(Utility.ofMap("name", tag, "description", ws.comment())); + } + servletsList.sort((o1, o2) -> { + String[] urlregs1 = (String[]) o1.get("urlregs"); + String[] urlregs2 = (String[]) o2.get("urlregs"); + return urlregs1.length > 0 ? (urlregs2.length > 0 ? urlregs1[0].compareTo(urlregs2[0]) : 1) : -1; + }); + } + { // https://github.com/OAI/OpenAPI-Specification + Map swaggerResultMap = new LinkedHashMap<>(); + swaggerResultMap.put("openapi", "3.0.0"); + Map infomap = new LinkedHashMap<>(); + infomap.put("title", "Redkale generate apidoc"); + infomap.put("version", "1.0.0"); + swaggerResultMap.put("info", infomap); + swaggerResultMap.put("servers", swaggerServers); + swaggerResultMap.put("paths", swaggerPathsMap); + swaggerResultMap.put("tags", swaggerTags); + if (!swaggerComponentsMap.isEmpty()) swaggerResultMap.put("components", Utility.ofMap("schemas", swaggerComponentsMap)); + final FileOutputStream out = new FileOutputStream(new File(app.getHome(), "openapi-doc.json")); + out.write(JsonConvert.root().convertTo(swaggerResultMap).getBytes(StandardCharsets.UTF_8)); + out.close(); + } + { + Map oldapisResultMap = new LinkedHashMap<>(); + oldapisResultMap.put("servers", serverList); + oldapisResultMap.put("types", typesMap); + final String json = JsonConvert.root().convertTo(oldapisResultMap); + final FileOutputStream out = new FileOutputStream(new File(app.getHome(), "apidoc.json")); + out.write(json.getBytes(StandardCharsets.UTF_8)); + out.close(); + File doctemplate = new File(app.getConfPath().toString(), "apidoc-template.html"); + InputStream in = null; + if (doctemplate.isFile() && doctemplate.canRead()) { + in = new FileInputStream(doctemplate); + } + if (in == null) in = ApiDocsService.class.getResourceAsStream("apidoc-template.html"); + String content = Utility.read(in).replace("'${content}'", json); + in.close(); + FileOutputStream outhtml = new FileOutputStream(new File(app.getHome(), "apidoc.html")); + outhtml.write(content.getBytes(StandardCharsets.UTF_8)); + outhtml.close(); + } + } + + private static void simpleSchemaType(Logger logger, Map> componentsMap, Class type, Type genericType, Map schemaMap, boolean recursive) { + if (type == int.class || type == Integer.class || type == AtomicInteger.class) { + schemaMap.put("type", "integer"); + schemaMap.put("format", "int32"); + } else if (type == long.class || type == Long.class + || type == AtomicLong.class || type == LongAdder.class || type == BigInteger.class) { + schemaMap.put("type", "integer"); + schemaMap.put("format", "int64"); + } else if (type == float.class || type == Float.class) { + schemaMap.put("type", "number"); + schemaMap.put("format", "float"); + } else if (type == double.class || type == Double.class || type == BigDecimal.class) { + schemaMap.put("type", "number"); + schemaMap.put("format", "double"); + } else if (type == boolean.class || type == Boolean.class || type == AtomicBoolean.class) { + schemaMap.put("type", "boolean"); + } else if (type.isPrimitive() || Number.class.isAssignableFrom(type)) { + schemaMap.put("type", "number"); + } else if (type == String.class || CharSequence.class.isAssignableFrom(type)) { + schemaMap.put("type", "string"); + } else if (recursive && (type.isArray() || Collection.class.isAssignableFrom(type))) { + schemaMap.put("type", "array"); + Map sbumap = new LinkedHashMap<>(); + if (type.isArray()) { + simpleSchemaType(logger, componentsMap, type.getComponentType(), type.getComponentType(), sbumap, false); + } else if (genericType instanceof ParameterizedType) { + Type subpt = ((ParameterizedType) genericType).getActualTypeArguments()[0]; + if (subpt instanceof Class) { + simpleSchemaType(logger, componentsMap, (Class) subpt, subpt, sbumap, false); + } else if (subpt instanceof ParameterizedType && ((ParameterizedType) subpt).getOwnerType() instanceof Class) { + simpleSchemaType(logger, componentsMap, (Class) ((ParameterizedType) subpt).getOwnerType(), subpt, sbumap, false); + } else { + sbumap.put("type", "object"); + } + } else { + sbumap.put("type", "object"); + } + schemaMap.put("items", sbumap); + } else if (!type.getName().startsWith("java.") && !type.getName().startsWith("javax.")) { + String ct = simpleComponentType(logger, componentsMap, type, genericType); + if (ct == null) { + schemaMap.put("type", "object"); + } else { + schemaMap.put("$ref", "#/components/schemas/" + ct); + } + } else { + schemaMap.put("type", "object"); + } + } + + private static String simpleComponentType(Logger logger, Map> componentsMap, Class type, Type genericType) { + try { + Encodeable encodeable = JsonFactory.root().loadEncoder(genericType); + String ct = componentKey(logger, componentsMap, null, encodeable, true); + if (ct == null || ct.length() == 0) return null; + if (componentsMap.containsKey(ct)) return ct; + Map cmap = new LinkedHashMap<>(); + componentsMap.put(ct, cmap); //蹇呴』鍦ㄨ皟鐢╯impleSchemaType涔嬪墠put锛屼笉鐒跺祵濂楁儏鍐典笅姝诲惊鐜 + + cmap.put("type", "object"); + List requireds = new ArrayList<>(); + Map properties = new LinkedHashMap<>(); + if (encodeable instanceof ObjectEncoder) { + for (EnMember member : ((ObjectEncoder) encodeable).getMembers()) { + Map schemaMap = new LinkedHashMap<>(); + simpleSchemaType(logger, componentsMap, TypeToken.typeToClassOrElse(member.getEncoder().getType(), Object.class), member.getEncoder().getType(), schemaMap, true); + String desc = ""; + if (member.getField() != null) { + Column col = member.getField().getAnnotation(Column.class); + if (col == null) { + FilterColumn fcol = member.getField().getAnnotation(FilterColumn.class); + if (fcol != null) { + desc = fcol.comment(); + if (fcol.required()) requireds.add(member.getAttribute().field()); + } + } else { + desc = col.comment(); + if (!col.nullable()) requireds.add(member.getAttribute().field()); + } + if (desc.isEmpty() && member.getField().getAnnotation(Comment.class) != null) { + desc = member.getField().getAnnotation(Comment.class).value(); + } + } else if (member.getMethod() != null) { + Column col = member.getMethod().getAnnotation(Column.class); + if (col == null) { + FilterColumn fcol = member.getMethod().getAnnotation(FilterColumn.class); + if (fcol != null) { + desc = fcol.comment(); + if (fcol.required()) requireds.add(member.getAttribute().field()); + } + } else { + desc = col.comment(); + if (!col.nullable()) requireds.add(member.getAttribute().field()); + } + if (desc.isEmpty() && member.getMethod().getAnnotation(Comment.class) != null) { + desc = member.getMethod().getAnnotation(Comment.class).value(); + } + } + if (!desc.isEmpty()) schemaMap.put("description", desc); + properties.put(member.getAttribute().field(), schemaMap); + } + } + if (!requireds.isEmpty()) cmap.put("required", requireds); + cmap.put("properties", properties); + return ct; + } catch (Exception e) { + logger.log(Level.WARNING, genericType + " generate component info error", e); + return null; + } + } + + private static String componentKey(Logger logger, Map> componentsMap, EnMember field, Encodeable encodeable, boolean first) { + if (encodeable instanceof ObjectEncoder) { + StringBuilder sb = new StringBuilder(); + sb.append(((ObjectEncoder) encodeable).getTypeClass().getSimpleName()); + for (EnMember member : ((ObjectEncoder) encodeable).getMembers()) { + if (member.getEncoder() instanceof ArrayEncoder + || member.getEncoder() instanceof CollectionEncoder) { + String subsb = componentKey(logger, componentsMap, member, member.getEncoder(), false); + if (subsb == null) return null; + AccessibleObject real = member.getField() == null ? member.getMethod() : member.getField(); + if (real == null) continue; + Class cz = real instanceof Field ? ((Field) real).getType() : ((Method) real).getReturnType(); + Type ct = real instanceof Field ? ((Field) real).getGenericType() : ((Method) real).getGenericReturnType(); + if (cz == ct) continue; + if (sb.length() > 0 && subsb.length() > 0) sb.append("_"); + sb.append(subsb); + } else if (member.getEncoder() instanceof ObjectEncoder || member.getEncoder() instanceof SimpledCoder) { + AccessibleObject real = member.getField() == null ? member.getMethod() : member.getField(); + if (real == null) continue; + if (member.getEncoder() instanceof SimpledCoder) { + simpleSchemaType(logger, componentsMap, ((SimpledCoder) member.getEncoder()).getType(), ((SimpledCoder) member.getEncoder()).getType(), new LinkedHashMap<>(), true); + } else { + simpleSchemaType(logger, componentsMap, ((ObjectEncoder) member.getEncoder()).getTypeClass(), ((ObjectEncoder) member.getEncoder()).getType(), new LinkedHashMap<>(), true); + } + Class cz = real instanceof Field ? ((Field) real).getType() : ((Method) real).getReturnType(); + Type ct = real instanceof Field ? ((Field) real).getGenericType() : ((Method) real).getGenericReturnType(); + if (cz == ct) continue; + String subsb = componentKey(logger, componentsMap, member, member.getEncoder(), false); + if (subsb == null) return null; + if (sb.length() > 0 && subsb.length() > 0) sb.append("_"); + sb.append(subsb); + } else if (member.getEncoder() instanceof MapEncoder) { + continue; + } else { + return null; + } + } + return sb.toString(); + } else if (encodeable instanceof ArrayEncoder || encodeable instanceof CollectionEncoder) { + final boolean array = (encodeable instanceof ArrayEncoder); + Encodeable subEncodeable = array ? ((ArrayEncoder) encodeable).getComponentEncoder() : ((CollectionEncoder) encodeable).getComponentEncoder(); + if (subEncodeable instanceof SimpledCoder && field != null) return ""; + final String sb = componentKey(logger, componentsMap, null, subEncodeable, false); + if (sb == null || sb.isEmpty()) return sb; + if (field != null && field.getField() != null && field.getField().getDeclaringClass() == Sheet.class) { + return sb; + } + return sb + (array ? "_Array" : "_Collection"); + } else if (encodeable instanceof SimpledCoder) { + Class stype = ((SimpledCoder) encodeable).getType(); + if (stype.isPrimitive() || stype == Boolean.class || Number.class.isAssignableFrom(stype) || CharSequence.class.isAssignableFrom(stype)) { + return stype.getSimpleName(); + } + return ""; + } else if (encodeable instanceof MapEncoder) { + return first ? null : ""; + } else { + return null; + } + } + + private static Object formatExample(String example, Class type, Type genericType) { + if (example == null || example.isEmpty()) return null; + if (type == Flipper.class) { + return new Flipper(); + } else if (TYPE_RETRESULT_OBJECT.equals(genericType)) { + return RetResult.success(); + } else if (TYPE_RETRESULT_STRING.equals(genericType)) { + return RetResult.success(); + } else if (TYPE_RETRESULT_INTEGER.equals(genericType)) { + return RetResult.success(0); + } else if (TYPE_RETRESULT_LONG.equals(genericType)) { + return RetResult.success(0L); + } + return example; + } + +} diff --git a/src/main/java/org/redkale/boot/ApplicationListener.java b/src/main/java/org/redkale/boot/ApplicationListener.java index dd1ce9274..8148f5495 100644 --- a/src/main/java/org/redkale/boot/ApplicationListener.java +++ b/src/main/java/org/redkale/boot/ApplicationListener.java @@ -1,69 +1,69 @@ -/* - * 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.boot; - -import org.redkale.util.AnyValue; - -/** - * Application鍚姩鍜屽叧闂椂鐨勭洃鍚簨浠
- * 鍙兘閫氳繃application.xml閰嶇疆 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public interface ApplicationListener { - - /** - * 鍒濆鍖栨柟娉 - * - * @param config 閰嶇疆鍙傛暟 - */ - default void init(AnyValue config) { - - } - - /** - * Application 鍦ㄨ繍琛宻tart鍓嶈皟鐢 - * - * @param application Application - */ - default void preStart(Application application) { - } - - /** - * Application 鍦ㄨ繍琛宻tart鍚庤皟鐢 - * - * @param application Application - */ - default void postStart(Application application) { - } - - /** - * Application 鍦ㄨ繍琛孋ompile鍓嶈皟鐢 - * - * @param application Application - */ - default void preCompile(Application application) { - } - - /** - * Application 鍦ㄨ繍琛孋ompile鍚庤皟鐢 - * - * @param application Application - */ - default void postCompile(Application application) { - } - - /** - * Application 鍦ㄨ繍琛宻hutdown鍓嶈皟鐢 - * - * @param application Application - */ - default void preShutdown(Application application) { - } -} +/* + * 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.boot; + +import org.redkale.util.AnyValue; + +/** + * Application鍚姩鍜屽叧闂椂鐨勭洃鍚簨浠
+ * 鍙兘閫氳繃application.xml閰嶇疆 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public interface ApplicationListener { + + /** + * 鍒濆鍖栨柟娉 + * + * @param config 閰嶇疆鍙傛暟 + */ + default void init(AnyValue config) { + + } + + /** + * Application 鍦ㄨ繍琛宻tart鍓嶈皟鐢 + * + * @param application Application + */ + default void preStart(Application application) { + } + + /** + * Application 鍦ㄨ繍琛宻tart鍚庤皟鐢 + * + * @param application Application + */ + default void postStart(Application application) { + } + + /** + * Application 鍦ㄨ繍琛孋ompile鍓嶈皟鐢 + * + * @param application Application + */ + default void preCompile(Application application) { + } + + /** + * Application 鍦ㄨ繍琛孋ompile鍚庤皟鐢 + * + * @param application Application + */ + default void postCompile(Application application) { + } + + /** + * Application 鍦ㄨ繍琛宻hutdown鍓嶈皟鐢 + * + * @param application Application + */ + default void preShutdown(Application application) { + } +} diff --git a/src/main/java/org/redkale/boot/ClassFilter.java b/src/main/java/org/redkale/boot/ClassFilter.java index c9b946926..cdd1df635 100644 --- a/src/main/java/org/redkale/boot/ClassFilter.java +++ b/src/main/java/org/redkale/boot/ClassFilter.java @@ -1,606 +1,606 @@ -/* - * 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.boot; - -import java.io.*; -import java.lang.annotation.*; -import java.lang.reflect.Modifier; -import java.net.*; -import java.nio.charset.StandardCharsets; -import java.util.*; -import java.util.concurrent.*; -import java.util.function.Predicate; -import java.util.jar.*; -import java.util.logging.*; -import java.util.regex.*; -import org.redkale.util.*; -import org.redkale.util.AnyValue.DefaultAnyValue; - -/** - * class杩囨护鍣紝 绗﹀悎鏉′欢鐨刢lass浼氫繚鐣欎笅鏉ュ瓨鍏ilterEntry銆 - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param 娉涘瀷 - */ -@SuppressWarnings("unchecked") -public final class ClassFilter { - - private static final Logger logger = Logger.getLogger(ClassFilter.class.getName()); //鏃ュ織瀵硅薄 - - private static final boolean finest = logger.isLoggable(Level.FINEST); //鏃ュ織绾у埆 - - private final Set> entrys = new HashSet<>(); //绗﹀悎鏉′欢鐨勭粨鏋 - - private final Set> expectEntrys = new HashSet<>(); //鍑嗗绗﹀悎鏉′欢鐨勭粨鏋 - - private Predicate expectPredicate; - - private boolean refused; //鏄惁鎷掔粷鎵鏈夋暟鎹,璁剧疆true锛屽垯鍏朵粬瑙勫垯澶辨晥,閮芥槸鎷掔粷. - - private Class superClass; //绗﹀悎鐨勭埗绫诲瀷銆備笉涓虹┖鏃讹紝鎵弿缁撴灉鐨刢lass蹇呴』鏄痵uperClass鐨勫瓙绫 - - private Class[] excludeSuperClasses; //涓嶇鍚堢殑鐖剁被鍨嬨 - - private Class annotationClass;//绗﹀悎鐨勬敞瑙c備笉涓虹┖鏃讹紝鎵弿缁撴灉鐨刢lass蹇呴』鍖呭惈璇ユ敞瑙 - - private Pattern[] includePatterns; //绗﹀悎鐨刢lassname姝e垯琛ㄨ揪寮 - - private Pattern[] excludePatterns;//鎷掔粷鐨刢lassname姝e垯琛ㄨ揪寮 - - private Set privilegeIncludes; //鐗规壒绗﹀悎鏉′欢鐨刢lassname - - private Set privilegeExcludes;//鐗规壒鎷掔粷鏉′欢鐨刢lassname - - private List ors; //鎴栧叧绯荤殑鍏朵粬ClassFilter - - private List ands;//涓庡叧绯荤殑鍏朵粬ClassFilter - - private AnyValue conf; //鍩烘湰閰嶇疆淇℃伅, 褰撶鍚堟潯浠舵椂灏哻onf鐨勫睘鎬ц祴鍊煎埌FilterEntry涓幓銆 - - private final ClassLoader classLoader; - - public ClassFilter(RedkaleClassLoader classLoader, Class annotationClass, Class superClass, Class[] excludeSuperClasses) { - this(classLoader, annotationClass, superClass, excludeSuperClasses, null); - } - - public ClassFilter(RedkaleClassLoader classLoader, Class annotationClass, Class superClass, Class[] excludeSuperClasses, AnyValue conf) { - this.annotationClass = annotationClass; - this.superClass = superClass; - this.excludeSuperClasses = excludeSuperClasses; - this.conf = conf; - this.classLoader = classLoader == null ? Thread.currentThread().getContextClassLoader() : classLoader; - } - - public static ClassFilter create(RedkaleClassLoader classLoader, Class[] excludeSuperClasses, String includeregs, String excluderegs, Set includeValues, Set excludeValues) { - ClassFilter filter = new ClassFilter(classLoader, null, null, excludeSuperClasses); - filter.setIncludePatterns(includeregs == null ? null : includeregs.split(";")); - filter.setExcludePatterns(excluderegs == null ? null : excluderegs.split(";")); - filter.setPrivilegeIncludes(includeValues); - filter.setPrivilegeExcludes(excludeValues); - return filter; - } - - public ClassFilter or(ClassFilter filter) { - if (ors == null) ors = new ArrayList<>(); - ors.add(filter); - return this; - } - - public ClassFilter and(ClassFilter filter) { - if (ands == null) ands = new ArrayList<>(); - ands.add(filter); - return this; - } - - /** - * 鑾峰彇绗﹀悎鏉′欢鐨刢lass闆嗗悎 - * - * @return Set<FilterEntry<T>> - */ - public final Set> getFilterEntrys() { - HashSet> set = new HashSet<>(); - set.addAll(entrys); - if (ors != null) ors.forEach(f -> set.addAll(f.getFilterEntrys())); - if (ands != null) ands.forEach(f -> set.addAll(f.getFilterEntrys())); - return set; - } - - /** - * 鑾峰彇棰勭暀鐨刢lass闆嗗悎 - * - * @return Set<FilterEntry<T>> - */ - public final Set> getFilterExpectEntrys() { - HashSet> set = new HashSet<>(); - set.addAll(expectEntrys); - if (ors != null) ors.forEach(f -> set.addAll(f.getFilterExpectEntrys())); - if (ands != null) ands.forEach(f -> set.addAll(f.getFilterExpectEntrys())); - return set; - } - - /** - * 鑾峰彇鎵鏈夌殑class闆嗗悎 - * - * @return Set<FilterEntry<T>> - */ - public final Set> getAllFilterEntrys() { - HashSet> rs = new HashSet<>(); - rs.addAll(getFilterEntrys()); - rs.addAll(getFilterExpectEntrys()); - return rs; - } - - /** - * 鑷姩鎵弿鍦拌繃婊ゆ寚瀹氱殑class - * - * @param property AnyValue - * @param clazzname String - * @param url URL - */ - @SuppressWarnings("unchecked") - public final void filter(AnyValue property, String clazzname, URL url) { - filter(property, clazzname, true, url); - } - - /** - * 杩囨护鎸囧畾鐨刢lass - * - * @param property application.xml涓搴攃lass鑺傜偣涓嬬殑property灞炴ч」 - * @param clazzname class鍚嶇О - * @param autoscan 涓簍rue琛ㄧず鑷姩鎵弿鐨勶紝 false琛ㄧず鏄捐憲璋冪敤filter锛 AutoLoad鐨勬敞瑙e皢琚拷鐣 - */ - public final void filter(AnyValue property, String clazzname, boolean autoscan) { - filter(property, clazzname, autoscan, null); - } - - /** - * 杩囨护鎸囧畾鐨刢lass - * - * @param property application.xml涓搴攃lass鑺傜偣涓嬬殑property灞炴ч」 - * @param clazzname class鍚嶇О - * @param autoscan 涓簍rue琛ㄧず鑷姩鎵弿鐨勶紝 false琛ㄧず鏄捐憲璋冪敤filter锛 AutoLoad鐨勬敞瑙e皢琚拷鐣 - * @param url URL - */ - public final void filter(AnyValue property, String clazzname, boolean autoscan, URL url) { - boolean r = accept0(property, clazzname); - ClassFilter cf = r ? this : null; - if (r && ands != null) { - for (ClassFilter filter : ands) { - if (!filter.accept(property, clazzname)) return; - } - } - if (!r && ors != null) { - for (ClassFilter filter : ors) { - if (filter.accept(filter.conf, clazzname)) { - cf = filter; - property = cf.conf; - break; - } - } - } - if (cf == null || clazzname.startsWith("sun.") || clazzname.contains("module-info")) return; - try { - Class clazz = classLoader.loadClass(clazzname); - if (!cf.accept(property, clazz, autoscan)) return; - if (cf.conf != null) { - if (property == null) { - property = cf.conf; - } else if (property instanceof DefaultAnyValue) { - ((DefaultAnyValue) property).addAllStringSet(cf.conf); - } else { - DefaultAnyValue dav = new DefaultAnyValue(); - dav.addAllStringSet(property); - dav.addAllStringSet(cf.conf); - property = dav; - } - } - - AutoLoad auto = (AutoLoad) clazz.getAnnotation(AutoLoad.class); - if ((expectPredicate != null && expectPredicate.test(clazzname)) || (autoscan && auto != null && !auto.value())) { //鑷姩鎵弿涓旇鏍囪涓篅AutoLoad(false)鐨 - expectEntrys.add(new FilterEntry(clazz, autoscan, true, property)); - } else { - entrys.add(new FilterEntry(clazz, autoscan, false, property)); - } - } catch (Throwable cfe) { - if (finest && !clazzname.startsWith("sun.") && !clazzname.startsWith("javax.") - && !clazzname.startsWith("com.sun.") && !clazzname.startsWith("jdk.") && !clazzname.startsWith("META-INF") - && !clazzname.startsWith("com.mysql.") && !clazzname.startsWith("com.microsoft.") && !clazzname.startsWith("freemarker.") - && !clazzname.startsWith("org.redkale") && (clazzname.contains("Service") || clazzname.contains("Servlet"))) { - //&& (!(cfe instanceof NoClassDefFoundError) || (cfe instanceof UnsupportedClassVersionError) || ((NoClassDefFoundError) cfe).getMessage().startsWith("java.lang.NoClassDefFoundError: java"))) { - logger.log(Level.FINEST, ClassFilter.class.getSimpleName() + " filter error for class: " + clazzname + (url == null ? "" : (" in " + url)), cfe); - } - } - } - - /** - * 鍒ゆ柇class鏄惁鏈夋晥 - * - * @param classname String - * - * @return boolean - */ - public boolean accept(String classname) { - return accept(null, classname); - } - - /** - * 鍒ゆ柇class鏄惁鏈夋晥 - * - * @param property AnyValue - * @param classname String - * - * @return boolean - */ - public boolean accept(AnyValue property, String classname) { - boolean r = accept0(property, classname); - if (r && ands != null) { - for (ClassFilter filter : ands) { - if (!filter.accept(property, classname)) return false; - } - } - if (!r && ors != null) { - for (ClassFilter filter : ors) { - if (filter.accept(filter.conf, classname)) return true; - } - } - return r; - } - - private boolean accept0(AnyValue property, String classname) { - if (this.refused) return false; - if (this.privilegeIncludes != null && this.privilegeIncludes.contains(classname)) return true; - if (this.privilegeExcludes != null && this.privilegeExcludes.contains(classname)) return false; - if (classname.startsWith("java.") || classname.startsWith("javax.")) return false; - if (excludePatterns != null) { - for (Pattern reg : excludePatterns) { - if (reg.matcher(classname).matches()) return false; - } - } - if (includePatterns != null) { - for (Pattern reg : includePatterns) { - if (reg.matcher(classname).matches()) return true; - } - } - return includePatterns == null; - } - - /** - * 鍒ゆ柇class鏄惁鏈夋晥 - * - * @param property AnyValue - * @param clazz Class - * @param autoscan boolean - * - * @return boolean - */ - @SuppressWarnings("unchecked") - public boolean accept(AnyValue property, Class clazz, boolean autoscan) { - if (this.refused || !Modifier.isPublic(clazz.getModifiers())) return false; - if (annotationClass != null && clazz.getAnnotation(annotationClass) == null) return false; - boolean rs = superClass == null || (clazz != superClass && superClass.isAssignableFrom(clazz)); - if (rs && this.excludeSuperClasses != null && this.excludeSuperClasses.length > 0) { - for (Class c : this.excludeSuperClasses) { - if (c != null && (clazz == c || c.isAssignableFrom(clazz))) return false; - } - } - return rs; - } - - public static Pattern[] toPattern(String[] regs) { - if (regs == null || regs.length == 0) return null; - int i = 0; - Pattern[] rs = new Pattern[regs.length]; - for (String reg : regs) { - if (reg == null || reg.trim().isEmpty()) continue; - rs[i++] = Pattern.compile(reg.trim()); - } - if (i == 0) return null; - if (i == rs.length) return rs; - Pattern[] ps = new Pattern[i]; - System.arraycopy(rs, 0, ps, 0, i); - return ps; - } - - public void setSuperClass(Class superClass) { - this.superClass = superClass; - } - - public Class getSuperClass() { - return superClass; - } - - public Class[] getExcludeSuperClasses() { - return excludeSuperClasses; - } - - public void setExcludeSuperClasses(Class[] excludeSuperClasses) { - this.excludeSuperClasses = excludeSuperClasses; - } - - public void setAnnotationClass(Class annotationClass) { - this.annotationClass = annotationClass; - } - - public Pattern[] getIncludePatterns() { - return includePatterns; - } - - public void setIncludePatterns(String[] includePatterns) { - this.includePatterns = toPattern(includePatterns); - } - - public Pattern[] getExcludePatterns() { - return excludePatterns; - } - - public void setExcludePatterns(String[] excludePatterns) { - this.excludePatterns = toPattern(excludePatterns); - } - - public Class getAnnotationClass() { - return annotationClass; - } - - public boolean isRefused() { - return refused; - } - - public void setRefused(boolean refused) { - this.refused = refused; - } - - public Predicate getExpectPredicate() { - return expectPredicate; - } - - public void setExpectPredicate(Predicate predicate) { - this.expectPredicate = predicate; - } - - public Set getPrivilegeIncludes() { - return privilegeIncludes; - } - - public void setPrivilegeIncludes(Set privilegeIncludes) { - this.privilegeIncludes = privilegeIncludes == null || privilegeIncludes.isEmpty() ? null : privilegeIncludes; - } - - public Set getPrivilegeExcludes() { - return privilegeExcludes; - } - - public void setPrivilegeExcludes(Set privilegeExcludes) { - this.privilegeExcludes = privilegeExcludes == null || privilegeExcludes.isEmpty() ? null : privilegeExcludes; - - } - - /** - * 瀛樻斁绗﹀悎鏉′欢鐨刢lass涓巆lass鎸囧畾鐨勫睘鎬ч」 - * - * @param 娉涘瀷 - */ - public static final class FilterEntry { - - private final HashSet groups = new LinkedHashSet<>(); - - private final String name; - - private final Class type; - - private final AnyValue property; - - private final boolean autoload; - - private final boolean expect; - - public FilterEntry(Class type, AnyValue property) { - this(type, false, false, property); - } - - public FilterEntry(Class type, final boolean autoload, boolean expect, AnyValue property) { - this.type = type; - String str = property == null ? null : property.getValue("groups"); - if (str != null) { - str = str.trim(); - if (str.endsWith(";")) str = str.substring(0, str.length() - 1); - } - if (str != null) this.groups.addAll(Arrays.asList(str.split(";"))); - this.property = property; - this.autoload = autoload; - this.expect = expect; - this.name = property == null ? "" : property.getValue("name", ""); - } - - @Override - public String toString() { - return this.getClass().getSimpleName() + "[thread=" + Thread.currentThread().getName() - + ", type=" + this.type.getSimpleName() + ", name=" + name + ", groups=" + this.groups + "]"; - } - - @Override - public int hashCode() { - return this.type.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; - return (this.type == ((FilterEntry) obj).type && this.groups.equals(((FilterEntry) obj).groups) && this.name.equals(((FilterEntry) obj).name)); - } - - public Class getType() { - return type; - } - - public String getName() { - return name; - } - - public AnyValue getProperty() { - return property; - } - - public boolean containsGroup(String group) { - return groups != null && groups.contains(group); - } - - public boolean isEmptyGroups() { - return groups == null || groups.isEmpty(); - } - - public HashSet getGroups() { - return groups; - } - - public boolean isAutoload() { - return autoload; - } - - public boolean isExpect() { - return expect; - } - } - - /** - * class鍔犺浇绫 - */ - public static class Loader { - - protected static final Logger logger = Logger.getLogger(Loader.class.getName()); - - protected static final ConcurrentMap> cache = new ConcurrentHashMap<>(); - - public static void close() { - cache.clear(); - } - - /** - * 鍔犺浇褰撳墠绾跨▼鐨刢lasspath鎵弿鎵鏈塩lass杩涜杩囨护 - * - * @param excludeFile 涓嶉渶瑕佹壂鎻忕殑鏂囦欢澶癸紝 鍙互涓簄ull - * @param loader RedkaleClassloader锛 涓嶅彲涓簄ull - * @param excludeRegs 鍖呭惈姝ゅ叧閿瓧鐨勬枃浠跺皢琚烦杩囷紝 鍙互涓簄ull - * @param filters 杩囨护鍣 - * - * @throws IOException 寮傚父 - */ - public static void load(final File excludeFile, RedkaleClassLoader loader, final String[] excludeRegs, final ClassFilter... filters) throws IOException { - List urlfiles = new ArrayList<>(2); - List urljares = new ArrayList<>(2); - final URL exurl = excludeFile != null ? excludeFile.toURI().toURL() : null; - final Pattern[] excludePatterns = toPattern(excludeRegs); - for (URL url : loader.getAllURLs()) { - if (exurl != null && exurl.sameFile(url)) continue; - if (excludePatterns != null && url != RedkaleClassLoader.URL_NONE) { - boolean skip = false; - for (Pattern p : excludePatterns) { - if (p.matcher(url.toString()).matches()) { - skip = true; - break; - } - } - if (skip) continue; - } - if (url.getPath().endsWith(".jar")) { - urljares.add(url); - } else { - urlfiles.add(url); - } - } - List files = new ArrayList<>(); - boolean debug = logger.isLoggable(Level.FINEST); - StringBuilder debugstr = new StringBuilder(); - for (final URL url : urljares) { - Set classes = cache.get(url); - if (classes == null) { - classes = new LinkedHashSet<>(); - try (JarFile jar = new JarFile(URLDecoder.decode(url.getFile(), StandardCharsets.UTF_8))) { - Enumeration it = jar.entries(); - while (it.hasMoreElements()) { - String entryname = it.nextElement().getName().replace('/', '.'); - if (entryname.endsWith(".class") && entryname.indexOf('$') < 0) { - String classname = entryname.substring(0, entryname.length() - 6); - if (classname.startsWith("javax.") || classname.startsWith("com.sun.")) continue; - //甯歌鐨刯ar璺宠繃 - if (classname.startsWith("com.redkaledyn.")) break; //redkale鍔ㄦ佺敓鎴愮殑绫 - if (classname.startsWith("com.mysql.")) break; - if (classname.startsWith("org.mariadb.")) break; - if (classname.startsWith("oracle.jdbc.")) break; - if (classname.startsWith("org.postgresql.")) break; - if (classname.startsWith("com.microsoft.sqlserver.")) break; - classes.add(classname); - if (debug) debugstr.append(classname).append("\r\n"); - for (final ClassFilter filter : filters) { - if (filter != null) filter.filter(null, classname, url); - } - } - } - } - cache.put(url, classes); - } else { - for (String classname : classes) { - for (final ClassFilter filter : filters) { - if (filter != null) filter.filter(null, classname, url); - } - } - } - } - for (final URL url : urlfiles) { - Set classes = cache.get(url); - if (classes == null) { - classes = new LinkedHashSet<>(); - final Set cs = classes; - if (url == RedkaleClassLoader.URL_NONE) loader.forEachCacheClass(v -> cs.add(v)); - if (cs.isEmpty()) { - files.clear(); - File root = new File(url.getFile()); - String rootpath = root.getPath(); - loadClassFiles(excludeFile, root, files); - for (File f : files) { - String classname = f.getPath().substring(rootpath.length() + 1, f.getPath().length() - 6).replace(File.separatorChar, '.'); - if (classname.startsWith("javax.") || classname.startsWith("com.sun.")) continue; - classes.add(classname); - if (debug) debugstr.append(classname).append("\r\n"); - for (final ClassFilter filter : filters) { - if (filter != null) filter.filter(null, classname, url); - } - } - } else { - for (String classname : classes) { - for (final ClassFilter filter : filters) { - if (filter != null) filter.filter(null, classname, url); - } - } - } - cache.put(url, classes); - } else { - for (String classname : classes) { - for (final ClassFilter filter : filters) { - if (filter != null) filter.filter(null, classname, url); - } - } - } - } - //if (debug) logger.log(Level.INFO, "scan classes: \r\n{0}", debugstr); - } - - private static void loadClassFiles(File exclude, File root, List files) { - if (root.isFile() && root.getName().endsWith(".class")) { - files.add(root); - } else if (root.isDirectory()) { - if (exclude != null && exclude.equals(root)) return; - File[] lfs = root.listFiles(); - if (lfs == null) throw new RuntimeException("File(" + root + ") cannot listFiles()"); - for (File f : lfs) { - loadClassFiles(exclude, f, files); - } - } - } - } -} +/* + * 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.boot; + +import java.io.*; +import java.lang.annotation.*; +import java.lang.reflect.Modifier; +import java.net.*; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.concurrent.*; +import java.util.function.Predicate; +import java.util.jar.*; +import java.util.logging.*; +import java.util.regex.*; +import org.redkale.util.*; +import org.redkale.util.AnyValue.DefaultAnyValue; + +/** + * class杩囨护鍣紝 绗﹀悎鏉′欢鐨刢lass浼氫繚鐣欎笅鏉ュ瓨鍏ilterEntry銆 + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param 娉涘瀷 + */ +@SuppressWarnings("unchecked") +public final class ClassFilter { + + private static final Logger logger = Logger.getLogger(ClassFilter.class.getName()); //鏃ュ織瀵硅薄 + + private static final boolean finest = logger.isLoggable(Level.FINEST); //鏃ュ織绾у埆 + + private final Set> entrys = new HashSet<>(); //绗﹀悎鏉′欢鐨勭粨鏋 + + private final Set> expectEntrys = new HashSet<>(); //鍑嗗绗﹀悎鏉′欢鐨勭粨鏋 + + private Predicate expectPredicate; + + private boolean refused; //鏄惁鎷掔粷鎵鏈夋暟鎹,璁剧疆true锛屽垯鍏朵粬瑙勫垯澶辨晥,閮芥槸鎷掔粷. + + private Class superClass; //绗﹀悎鐨勭埗绫诲瀷銆備笉涓虹┖鏃讹紝鎵弿缁撴灉鐨刢lass蹇呴』鏄痵uperClass鐨勫瓙绫 + + private Class[] excludeSuperClasses; //涓嶇鍚堢殑鐖剁被鍨嬨 + + private Class annotationClass;//绗﹀悎鐨勬敞瑙c備笉涓虹┖鏃讹紝鎵弿缁撴灉鐨刢lass蹇呴』鍖呭惈璇ユ敞瑙 + + private Pattern[] includePatterns; //绗﹀悎鐨刢lassname姝e垯琛ㄨ揪寮 + + private Pattern[] excludePatterns;//鎷掔粷鐨刢lassname姝e垯琛ㄨ揪寮 + + private Set privilegeIncludes; //鐗规壒绗﹀悎鏉′欢鐨刢lassname + + private Set privilegeExcludes;//鐗规壒鎷掔粷鏉′欢鐨刢lassname + + private List ors; //鎴栧叧绯荤殑鍏朵粬ClassFilter + + private List ands;//涓庡叧绯荤殑鍏朵粬ClassFilter + + private AnyValue conf; //鍩烘湰閰嶇疆淇℃伅, 褰撶鍚堟潯浠舵椂灏哻onf鐨勫睘鎬ц祴鍊煎埌FilterEntry涓幓銆 + + private final ClassLoader classLoader; + + public ClassFilter(RedkaleClassLoader classLoader, Class annotationClass, Class superClass, Class[] excludeSuperClasses) { + this(classLoader, annotationClass, superClass, excludeSuperClasses, null); + } + + public ClassFilter(RedkaleClassLoader classLoader, Class annotationClass, Class superClass, Class[] excludeSuperClasses, AnyValue conf) { + this.annotationClass = annotationClass; + this.superClass = superClass; + this.excludeSuperClasses = excludeSuperClasses; + this.conf = conf; + this.classLoader = classLoader == null ? Thread.currentThread().getContextClassLoader() : classLoader; + } + + public static ClassFilter create(RedkaleClassLoader classLoader, Class[] excludeSuperClasses, String includeregs, String excluderegs, Set includeValues, Set excludeValues) { + ClassFilter filter = new ClassFilter(classLoader, null, null, excludeSuperClasses); + filter.setIncludePatterns(includeregs == null ? null : includeregs.split(";")); + filter.setExcludePatterns(excluderegs == null ? null : excluderegs.split(";")); + filter.setPrivilegeIncludes(includeValues); + filter.setPrivilegeExcludes(excludeValues); + return filter; + } + + public ClassFilter or(ClassFilter filter) { + if (ors == null) ors = new ArrayList<>(); + ors.add(filter); + return this; + } + + public ClassFilter and(ClassFilter filter) { + if (ands == null) ands = new ArrayList<>(); + ands.add(filter); + return this; + } + + /** + * 鑾峰彇绗﹀悎鏉′欢鐨刢lass闆嗗悎 + * + * @return Set<FilterEntry<T>> + */ + public final Set> getFilterEntrys() { + HashSet> set = new HashSet<>(); + set.addAll(entrys); + if (ors != null) ors.forEach(f -> set.addAll(f.getFilterEntrys())); + if (ands != null) ands.forEach(f -> set.addAll(f.getFilterEntrys())); + return set; + } + + /** + * 鑾峰彇棰勭暀鐨刢lass闆嗗悎 + * + * @return Set<FilterEntry<T>> + */ + public final Set> getFilterExpectEntrys() { + HashSet> set = new HashSet<>(); + set.addAll(expectEntrys); + if (ors != null) ors.forEach(f -> set.addAll(f.getFilterExpectEntrys())); + if (ands != null) ands.forEach(f -> set.addAll(f.getFilterExpectEntrys())); + return set; + } + + /** + * 鑾峰彇鎵鏈夌殑class闆嗗悎 + * + * @return Set<FilterEntry<T>> + */ + public final Set> getAllFilterEntrys() { + HashSet> rs = new HashSet<>(); + rs.addAll(getFilterEntrys()); + rs.addAll(getFilterExpectEntrys()); + return rs; + } + + /** + * 鑷姩鎵弿鍦拌繃婊ゆ寚瀹氱殑class + * + * @param property AnyValue + * @param clazzname String + * @param url URL + */ + @SuppressWarnings("unchecked") + public final void filter(AnyValue property, String clazzname, URL url) { + filter(property, clazzname, true, url); + } + + /** + * 杩囨护鎸囧畾鐨刢lass + * + * @param property application.xml涓搴攃lass鑺傜偣涓嬬殑property灞炴ч」 + * @param clazzname class鍚嶇О + * @param autoscan 涓簍rue琛ㄧず鑷姩鎵弿鐨勶紝 false琛ㄧず鏄捐憲璋冪敤filter锛 AutoLoad鐨勬敞瑙e皢琚拷鐣 + */ + public final void filter(AnyValue property, String clazzname, boolean autoscan) { + filter(property, clazzname, autoscan, null); + } + + /** + * 杩囨护鎸囧畾鐨刢lass + * + * @param property application.xml涓搴攃lass鑺傜偣涓嬬殑property灞炴ч」 + * @param clazzname class鍚嶇О + * @param autoscan 涓簍rue琛ㄧず鑷姩鎵弿鐨勶紝 false琛ㄧず鏄捐憲璋冪敤filter锛 AutoLoad鐨勬敞瑙e皢琚拷鐣 + * @param url URL + */ + public final void filter(AnyValue property, String clazzname, boolean autoscan, URL url) { + boolean r = accept0(property, clazzname); + ClassFilter cf = r ? this : null; + if (r && ands != null) { + for (ClassFilter filter : ands) { + if (!filter.accept(property, clazzname)) return; + } + } + if (!r && ors != null) { + for (ClassFilter filter : ors) { + if (filter.accept(filter.conf, clazzname)) { + cf = filter; + property = cf.conf; + break; + } + } + } + if (cf == null || clazzname.startsWith("sun.") || clazzname.contains("module-info")) return; + try { + Class clazz = classLoader.loadClass(clazzname); + if (!cf.accept(property, clazz, autoscan)) return; + if (cf.conf != null) { + if (property == null) { + property = cf.conf; + } else if (property instanceof DefaultAnyValue) { + ((DefaultAnyValue) property).addAllStringSet(cf.conf); + } else { + DefaultAnyValue dav = new DefaultAnyValue(); + dav.addAllStringSet(property); + dav.addAllStringSet(cf.conf); + property = dav; + } + } + + AutoLoad auto = (AutoLoad) clazz.getAnnotation(AutoLoad.class); + if ((expectPredicate != null && expectPredicate.test(clazzname)) || (autoscan && auto != null && !auto.value())) { //鑷姩鎵弿涓旇鏍囪涓篅AutoLoad(false)鐨 + expectEntrys.add(new FilterEntry(clazz, autoscan, true, property)); + } else { + entrys.add(new FilterEntry(clazz, autoscan, false, property)); + } + } catch (Throwable cfe) { + if (finest && !clazzname.startsWith("sun.") && !clazzname.startsWith("javax.") + && !clazzname.startsWith("com.sun.") && !clazzname.startsWith("jdk.") && !clazzname.startsWith("META-INF") + && !clazzname.startsWith("com.mysql.") && !clazzname.startsWith("com.microsoft.") && !clazzname.startsWith("freemarker.") + && !clazzname.startsWith("org.redkale") && (clazzname.contains("Service") || clazzname.contains("Servlet"))) { + //&& (!(cfe instanceof NoClassDefFoundError) || (cfe instanceof UnsupportedClassVersionError) || ((NoClassDefFoundError) cfe).getMessage().startsWith("java.lang.NoClassDefFoundError: java"))) { + logger.log(Level.FINEST, ClassFilter.class.getSimpleName() + " filter error for class: " + clazzname + (url == null ? "" : (" in " + url)), cfe); + } + } + } + + /** + * 鍒ゆ柇class鏄惁鏈夋晥 + * + * @param classname String + * + * @return boolean + */ + public boolean accept(String classname) { + return accept(null, classname); + } + + /** + * 鍒ゆ柇class鏄惁鏈夋晥 + * + * @param property AnyValue + * @param classname String + * + * @return boolean + */ + public boolean accept(AnyValue property, String classname) { + boolean r = accept0(property, classname); + if (r && ands != null) { + for (ClassFilter filter : ands) { + if (!filter.accept(property, classname)) return false; + } + } + if (!r && ors != null) { + for (ClassFilter filter : ors) { + if (filter.accept(filter.conf, classname)) return true; + } + } + return r; + } + + private boolean accept0(AnyValue property, String classname) { + if (this.refused) return false; + if (this.privilegeIncludes != null && this.privilegeIncludes.contains(classname)) return true; + if (this.privilegeExcludes != null && this.privilegeExcludes.contains(classname)) return false; + if (classname.startsWith("java.") || classname.startsWith("javax.")) return false; + if (excludePatterns != null) { + for (Pattern reg : excludePatterns) { + if (reg.matcher(classname).matches()) return false; + } + } + if (includePatterns != null) { + for (Pattern reg : includePatterns) { + if (reg.matcher(classname).matches()) return true; + } + } + return includePatterns == null; + } + + /** + * 鍒ゆ柇class鏄惁鏈夋晥 + * + * @param property AnyValue + * @param clazz Class + * @param autoscan boolean + * + * @return boolean + */ + @SuppressWarnings("unchecked") + public boolean accept(AnyValue property, Class clazz, boolean autoscan) { + if (this.refused || !Modifier.isPublic(clazz.getModifiers())) return false; + if (annotationClass != null && clazz.getAnnotation(annotationClass) == null) return false; + boolean rs = superClass == null || (clazz != superClass && superClass.isAssignableFrom(clazz)); + if (rs && this.excludeSuperClasses != null && this.excludeSuperClasses.length > 0) { + for (Class c : this.excludeSuperClasses) { + if (c != null && (clazz == c || c.isAssignableFrom(clazz))) return false; + } + } + return rs; + } + + public static Pattern[] toPattern(String[] regs) { + if (regs == null || regs.length == 0) return null; + int i = 0; + Pattern[] rs = new Pattern[regs.length]; + for (String reg : regs) { + if (reg == null || reg.trim().isEmpty()) continue; + rs[i++] = Pattern.compile(reg.trim()); + } + if (i == 0) return null; + if (i == rs.length) return rs; + Pattern[] ps = new Pattern[i]; + System.arraycopy(rs, 0, ps, 0, i); + return ps; + } + + public void setSuperClass(Class superClass) { + this.superClass = superClass; + } + + public Class getSuperClass() { + return superClass; + } + + public Class[] getExcludeSuperClasses() { + return excludeSuperClasses; + } + + public void setExcludeSuperClasses(Class[] excludeSuperClasses) { + this.excludeSuperClasses = excludeSuperClasses; + } + + public void setAnnotationClass(Class annotationClass) { + this.annotationClass = annotationClass; + } + + public Pattern[] getIncludePatterns() { + return includePatterns; + } + + public void setIncludePatterns(String[] includePatterns) { + this.includePatterns = toPattern(includePatterns); + } + + public Pattern[] getExcludePatterns() { + return excludePatterns; + } + + public void setExcludePatterns(String[] excludePatterns) { + this.excludePatterns = toPattern(excludePatterns); + } + + public Class getAnnotationClass() { + return annotationClass; + } + + public boolean isRefused() { + return refused; + } + + public void setRefused(boolean refused) { + this.refused = refused; + } + + public Predicate getExpectPredicate() { + return expectPredicate; + } + + public void setExpectPredicate(Predicate predicate) { + this.expectPredicate = predicate; + } + + public Set getPrivilegeIncludes() { + return privilegeIncludes; + } + + public void setPrivilegeIncludes(Set privilegeIncludes) { + this.privilegeIncludes = privilegeIncludes == null || privilegeIncludes.isEmpty() ? null : privilegeIncludes; + } + + public Set getPrivilegeExcludes() { + return privilegeExcludes; + } + + public void setPrivilegeExcludes(Set privilegeExcludes) { + this.privilegeExcludes = privilegeExcludes == null || privilegeExcludes.isEmpty() ? null : privilegeExcludes; + + } + + /** + * 瀛樻斁绗﹀悎鏉′欢鐨刢lass涓巆lass鎸囧畾鐨勫睘鎬ч」 + * + * @param 娉涘瀷 + */ + public static final class FilterEntry { + + private final HashSet groups = new LinkedHashSet<>(); + + private final String name; + + private final Class type; + + private final AnyValue property; + + private final boolean autoload; + + private final boolean expect; + + public FilterEntry(Class type, AnyValue property) { + this(type, false, false, property); + } + + public FilterEntry(Class type, final boolean autoload, boolean expect, AnyValue property) { + this.type = type; + String str = property == null ? null : property.getValue("groups"); + if (str != null) { + str = str.trim(); + if (str.endsWith(";")) str = str.substring(0, str.length() - 1); + } + if (str != null) this.groups.addAll(Arrays.asList(str.split(";"))); + this.property = property; + this.autoload = autoload; + this.expect = expect; + this.name = property == null ? "" : property.getValue("name", ""); + } + + @Override + public String toString() { + return this.getClass().getSimpleName() + "[thread=" + Thread.currentThread().getName() + + ", type=" + this.type.getSimpleName() + ", name=" + name + ", groups=" + this.groups + "]"; + } + + @Override + public int hashCode() { + return this.type.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + return (this.type == ((FilterEntry) obj).type && this.groups.equals(((FilterEntry) obj).groups) && this.name.equals(((FilterEntry) obj).name)); + } + + public Class getType() { + return type; + } + + public String getName() { + return name; + } + + public AnyValue getProperty() { + return property; + } + + public boolean containsGroup(String group) { + return groups != null && groups.contains(group); + } + + public boolean isEmptyGroups() { + return groups == null || groups.isEmpty(); + } + + public HashSet getGroups() { + return groups; + } + + public boolean isAutoload() { + return autoload; + } + + public boolean isExpect() { + return expect; + } + } + + /** + * class鍔犺浇绫 + */ + public static class Loader { + + protected static final Logger logger = Logger.getLogger(Loader.class.getName()); + + protected static final ConcurrentMap> cache = new ConcurrentHashMap<>(); + + public static void close() { + cache.clear(); + } + + /** + * 鍔犺浇褰撳墠绾跨▼鐨刢lasspath鎵弿鎵鏈塩lass杩涜杩囨护 + * + * @param excludeFile 涓嶉渶瑕佹壂鎻忕殑鏂囦欢澶癸紝 鍙互涓簄ull + * @param loader RedkaleClassloader锛 涓嶅彲涓簄ull + * @param excludeRegs 鍖呭惈姝ゅ叧閿瓧鐨勬枃浠跺皢琚烦杩囷紝 鍙互涓簄ull + * @param filters 杩囨护鍣 + * + * @throws IOException 寮傚父 + */ + public static void load(final File excludeFile, RedkaleClassLoader loader, final String[] excludeRegs, final ClassFilter... filters) throws IOException { + List urlfiles = new ArrayList<>(2); + List urljares = new ArrayList<>(2); + final URL exurl = excludeFile != null ? excludeFile.toURI().toURL() : null; + final Pattern[] excludePatterns = toPattern(excludeRegs); + for (URL url : loader.getAllURLs()) { + if (exurl != null && exurl.sameFile(url)) continue; + if (excludePatterns != null && url != RedkaleClassLoader.URL_NONE) { + boolean skip = false; + for (Pattern p : excludePatterns) { + if (p.matcher(url.toString()).matches()) { + skip = true; + break; + } + } + if (skip) continue; + } + if (url.getPath().endsWith(".jar")) { + urljares.add(url); + } else { + urlfiles.add(url); + } + } + List files = new ArrayList<>(); + boolean debug = logger.isLoggable(Level.FINEST); + StringBuilder debugstr = new StringBuilder(); + for (final URL url : urljares) { + Set classes = cache.get(url); + if (classes == null) { + classes = new LinkedHashSet<>(); + try (JarFile jar = new JarFile(URLDecoder.decode(url.getFile(), StandardCharsets.UTF_8))) { + Enumeration it = jar.entries(); + while (it.hasMoreElements()) { + String entryname = it.nextElement().getName().replace('/', '.'); + if (entryname.endsWith(".class") && entryname.indexOf('$') < 0) { + String classname = entryname.substring(0, entryname.length() - 6); + if (classname.startsWith("javax.") || classname.startsWith("com.sun.")) continue; + //甯歌鐨刯ar璺宠繃 + if (classname.startsWith("com.redkaledyn.")) break; //redkale鍔ㄦ佺敓鎴愮殑绫 + if (classname.startsWith("com.mysql.")) break; + if (classname.startsWith("org.mariadb.")) break; + if (classname.startsWith("oracle.jdbc.")) break; + if (classname.startsWith("org.postgresql.")) break; + if (classname.startsWith("com.microsoft.sqlserver.")) break; + classes.add(classname); + if (debug) debugstr.append(classname).append("\r\n"); + for (final ClassFilter filter : filters) { + if (filter != null) filter.filter(null, classname, url); + } + } + } + } + cache.put(url, classes); + } else { + for (String classname : classes) { + for (final ClassFilter filter : filters) { + if (filter != null) filter.filter(null, classname, url); + } + } + } + } + for (final URL url : urlfiles) { + Set classes = cache.get(url); + if (classes == null) { + classes = new LinkedHashSet<>(); + final Set cs = classes; + if (url == RedkaleClassLoader.URL_NONE) loader.forEachCacheClass(v -> cs.add(v)); + if (cs.isEmpty()) { + files.clear(); + File root = new File(url.getFile()); + String rootpath = root.getPath(); + loadClassFiles(excludeFile, root, files); + for (File f : files) { + String classname = f.getPath().substring(rootpath.length() + 1, f.getPath().length() - 6).replace(File.separatorChar, '.'); + if (classname.startsWith("javax.") || classname.startsWith("com.sun.")) continue; + classes.add(classname); + if (debug) debugstr.append(classname).append("\r\n"); + for (final ClassFilter filter : filters) { + if (filter != null) filter.filter(null, classname, url); + } + } + } else { + for (String classname : classes) { + for (final ClassFilter filter : filters) { + if (filter != null) filter.filter(null, classname, url); + } + } + } + cache.put(url, classes); + } else { + for (String classname : classes) { + for (final ClassFilter filter : filters) { + if (filter != null) filter.filter(null, classname, url); + } + } + } + } + //if (debug) logger.log(Level.INFO, "scan classes: \r\n{0}", debugstr); + } + + private static void loadClassFiles(File exclude, File root, List files) { + if (root.isFile() && root.getName().endsWith(".class")) { + files.add(root); + } else if (root.isDirectory()) { + if (exclude != null && exclude.equals(root)) return; + File[] lfs = root.listFiles(); + if (lfs == null) throw new RuntimeException("File(" + root + ") cannot listFiles()"); + for (File f : lfs) { + loadClassFiles(exclude, f, files); + } + } + } + } +} diff --git a/src/main/java/org/redkale/boot/LoggingFileHandler.java b/src/main/java/org/redkale/boot/LoggingFileHandler.java index e5f616faf..32fc1c8f0 100644 --- a/src/main/java/org/redkale/boot/LoggingFileHandler.java +++ b/src/main/java/org/redkale/boot/LoggingFileHandler.java @@ -1,372 +1,372 @@ -/* - * 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.boot; - -import org.redkale.util.RedkaleClassLoader; - -import java.io.*; -import java.nio.file.*; -import static java.nio.file.StandardCopyOption.*; -import java.time.*; -import java.util.*; -import java.util.concurrent.*; -import java.util.concurrent.atomic.*; -import java.util.logging.*; -import java.util.logging.Formatter; -import java.util.regex.Pattern; - -/** - * 鑷畾涔夌殑鏃ュ織杈撳嚭绫 - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@SuppressWarnings("unchecked") -public class LoggingFileHandler extends Handler { - - //public static final String FORMATTER_FORMAT = "%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%tL %4$s %2$s%n%5$s%6$s%n"; - public static final String FORMATTER_FORMAT = "%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%tL %4$s %2$s\r\n%5$s%6$s\r\n"; - - /** - * SNCP鐨勬棩蹇楄緭鍑篐andler - */ - public static class LoggingSncpFileHandler extends LoggingFileHandler { - - @Override - public String getPrefix() { - return "sncp-"; - } - } - - /** - * 榛樿鐨勬棩蹇楁椂闂存牸寮忓寲绫 - * 涓嶴impleFormatter鐨勫尯鍒湪浜巐evel涓嶄娇鐢ㄦ湰鍦板寲 - * - */ - public static class LoggingFormater extends Formatter { - - @Override - public String format(LogRecord log) { - String source; - if (log.getSourceClassName() != null) { - source = log.getSourceClassName(); - if (log.getSourceMethodName() != null) { - source += " " + log.getSourceMethodName(); - } - } else { - source = log.getLoggerName(); - } - String message = formatMessage(log); - String throwable = ""; - if (log.getThrown() != null) { - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw) { - @Override - public void println() { - super.print("\r\n"); - } - }; - pw.println(); - log.getThrown().printStackTrace(pw); - pw.close(); - throwable = sw.toString(); - } - return String.format(FORMATTER_FORMAT, - System.currentTimeMillis(), - source, - log.getLoggerName(), - log.getLevel().getName(), - message, - throwable); - } - } - - public static void initDebugLogConfig() { - try { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - final PrintStream ps = new PrintStream(out); - ps.println("handlers = java.util.logging.ConsoleHandler"); - ps.println(".level = FINEST"); - ps.println("jdk.level = INFO"); - ps.println("sun.level = INFO"); - ps.println("com.sun.level = INFO"); - ps.println("javax.level = INFO"); - ps.println("java.util.logging.ConsoleHandler.level = FINEST"); - ps.println("java.util.logging.ConsoleHandler.formatter = " + LoggingFileHandler.LoggingFormater.class.getName()); - LogManager.getLogManager().readConfiguration(new ByteArrayInputStream(out.toByteArray())); - } catch (Exception e) { - } - } - - protected final LinkedBlockingQueue logqueue = new LinkedBlockingQueue(); - - private String pattern; - - private String unusual; //涓嶄负null琛ㄧず灏 WARNING銆丼EVERE 绾у埆鐨勬棩蹇楀啓鍏ュ崟鐙殑鏂囦欢涓 - - private int limit; //鏂囦欢澶у皬闄愬埗 - - private final AtomicInteger logindex = new AtomicInteger(); - - private final AtomicInteger logunusualindex = new AtomicInteger(); - - private int count = 1; //鏂囦欢闄愬埗 - - private long tomorrow; - - private boolean append; - - private Pattern denyreg; - - private final AtomicLong loglength = new AtomicLong(); - - private final AtomicLong logunusuallength = new AtomicLong(); - - private File logfile; - - private File logunusualfile; - - private OutputStream logstream; - - private OutputStream logunusualstream; - - public LoggingFileHandler() { - updateTomorrow(); - configure(); - open(); - } - - private void updateTomorrow() { - Calendar cal = Calendar.getInstance(); - cal.set(Calendar.HOUR_OF_DAY, 0); - cal.set(Calendar.MINUTE, 0); - cal.set(Calendar.SECOND, 0); - cal.set(Calendar.MILLISECOND, 0); - cal.add(Calendar.DAY_OF_YEAR, 1); - long t = cal.getTimeInMillis(); - if (this.tomorrow != t) logindex.set(0); - this.tomorrow = t; - } - - private void open() { - final String name = "Redkale-Logging-" + getClass().getSimpleName() + "-Thread"; - new Thread() { - { - setName(name); - setDaemon(true); - } - - @Override - public void run() { - while (true) { - try { - LogRecord log = logqueue.take(); - final boolean bigger = (limit > 0 && limit <= loglength.get()); - final boolean changeday = tomorrow <= log.getMillis(); - if (bigger || changeday) { - updateTomorrow(); - if (logstream != null) { - logstream.close(); - if (bigger) { - for (int i = Math.min(count - 2, logindex.get() - 1); i > 0; i--) { - File greater = new File(logfile.getPath() + "." + i); - if (greater.exists()) Files.move(greater.toPath(), new File(logfile.getPath() + "." + (i + 1)).toPath(), REPLACE_EXISTING, ATOMIC_MOVE); - } - Files.move(logfile.toPath(), new File(logfile.getPath() + ".1").toPath(), REPLACE_EXISTING, ATOMIC_MOVE); - } else { - if (logfile.exists() && logfile.length() < 1) logfile.delete(); - } - logstream = null; - } - } - if (unusual != null && changeday && logunusualstream != null) { - logunusualstream.close(); - if (limit > 0 && limit <= logunusuallength.get()) { - for (int i = Math.min(count - 2, logunusualindex.get() - 1); i > 0; i--) { - File greater = new File(logunusualfile.getPath() + "." + i); - if (greater.exists()) Files.move(greater.toPath(), new File(logunusualfile.getPath() + "." + (i + 1)).toPath(), REPLACE_EXISTING, ATOMIC_MOVE); - } - Files.move(logunusualfile.toPath(), new File(logunusualfile.getPath() + ".1").toPath(), REPLACE_EXISTING, ATOMIC_MOVE); - } else { - if (logunusualfile.exists() && logunusualfile.length() < 1) logunusualfile.delete(); - } - logunusualstream = null; - } - if (logstream == null) { - logindex.incrementAndGet(); - java.time.LocalDate date = LocalDate.now(); - logfile = new File(pattern.replace("%m", String.valueOf((date.getYear() * 100 + date.getMonthValue()))).replace("%d", String.valueOf((date.getYear() * 10000 + date.getMonthValue() * 100 + date.getDayOfMonth())))); - logfile.getParentFile().mkdirs(); - loglength.set(logfile.length()); - logstream = new FileOutputStream(logfile, append); - } - if (unusual != null && logunusualstream == null) { - logunusualindex.incrementAndGet(); - java.time.LocalDate date = LocalDate.now(); - logunusualfile = new File(unusual.replace("%m", String.valueOf((date.getYear() * 100 + date.getMonthValue()))).replace("%d", String.valueOf((date.getYear() * 10000 + date.getMonthValue() * 100 + date.getDayOfMonth())))); - logunusualfile.getParentFile().mkdirs(); - logunusuallength.set(logunusualfile.length()); - logunusualstream = new FileOutputStream(logunusualfile, append); - } - //----------------------鍐欐棩蹇------------------------- - String message = getFormatter().format(log); - String encoding = getEncoding(); - byte[] bytes = encoding == null ? message.getBytes() : message.getBytes(encoding); - logstream.write(bytes); - loglength.addAndGet(bytes.length); - if (unusual != null && (log.getLevel() == Level.WARNING || log.getLevel() == Level.SEVERE)) { - logunusualstream.write(bytes); - logunusuallength.addAndGet(bytes.length); - } - } catch (Exception e) { - ErrorManager err = getErrorManager(); - if (err != null) err.error(null, e, ErrorManager.WRITE_FAILURE); - } - } - - } - }.start(); - } - - public String getPrefix() { - return ""; - } - - private void configure() { - LogManager manager = LogManager.getLogManager(); - String cname = LoggingFileHandler.class.getName(); - this.pattern = manager.getProperty(cname + ".pattern"); - if (this.pattern == null) { - this.pattern = "logs-%m/" + getPrefix() + "log-%d.log"; - } else { - int pos = this.pattern.lastIndexOf('/'); - if (pos > 0) { - this.pattern = this.pattern.substring(0, pos + 1) + getPrefix() + this.pattern.substring(pos + 1); - } else { - this.pattern = getPrefix() + this.pattern; - } - } - String unusualstr = manager.getProperty(cname + ".unusual"); - if (unusualstr != null) { - int pos = unusualstr.lastIndexOf('/'); - if (pos > 0) { - this.unusual = unusualstr.substring(0, pos + 1) + getPrefix() + unusualstr.substring(pos + 1); - } else { - this.unusual = getPrefix() + unusualstr; - } - } - String limitstr = manager.getProperty(cname + ".limit"); - try { - if (limitstr != null) { - limitstr = limitstr.toUpperCase(); - boolean g = limitstr.indexOf('G') > 0; - boolean m = limitstr.indexOf('M') > 0; - boolean k = limitstr.indexOf('K') > 0; - int ls = Math.abs(Integer.decode(limitstr.replace("G", "").replace("M", "").replace("K", "").replace("B", ""))); - if (g) { - ls *= 1024 * 1024 * 1024; - } else if (m) { - ls *= 1024 * 1024; - } else if (k) { - ls *= 1024; - } - this.limit = ls; - } - } catch (Exception e) { - } - String countstr = manager.getProperty(cname + ".count"); - try { - if (countstr != null) this.count = Math.max(1, Math.abs(Integer.decode(countstr))); - } catch (Exception e) { - } - String appendstr = manager.getProperty(cname + ".append"); - try { - if (appendstr != null) this.append = "true".equalsIgnoreCase(appendstr) || "1".equals(appendstr); - } catch (Exception e) { - } - String levelstr = manager.getProperty(cname + ".level"); - try { - if (levelstr != null) { - Level l = Level.parse(levelstr); - setLevel(l != null ? l : Level.ALL); - } - } catch (Exception e) { - } - String filterstr = manager.getProperty(cname + ".filter"); - try { - if (filterstr != null) { - Class clz = ClassLoader.getSystemClassLoader().loadClass(filterstr); - RedkaleClassLoader.putReflectionDeclaredConstructors(clz, clz.getName()); - setFilter((Filter) clz.getDeclaredConstructor().newInstance()); - } - } catch (Exception e) { - } - String formatterstr = manager.getProperty(cname + ".formatter"); - try { - if (formatterstr != null) { - Class clz = ClassLoader.getSystemClassLoader().loadClass(formatterstr); - RedkaleClassLoader.putReflectionDeclaredConstructors(clz, clz.getName()); - setFormatter((Formatter) clz.getDeclaredConstructor().newInstance()); - } - } catch (Exception e) { - } - if (getFormatter() == null) setFormatter(new SimpleFormatter()); - - String encodingstr = manager.getProperty(cname + ".encoding"); - try { - if (encodingstr != null) setEncoding(encodingstr); - } catch (Exception e) { - } - - String denyregstr = manager.getProperty(cname + ".denyreg"); - try { - if (denyregstr != null && !denyregstr.trim().isEmpty()) { - denyreg = Pattern.compile(denyregstr); - } - } catch (Exception e) { - } - } - - @Override - public void publish(LogRecord log) { - final String sourceClassName = log.getSourceClassName(); - if (sourceClassName == null || true) { - StackTraceElement[] ses = new Throwable().getStackTrace(); - for (int i = 2; i < ses.length; i++) { - if (ses[i].getClassName().startsWith("java.util.logging")) continue; - log.setSourceClassName('[' + Thread.currentThread().getName() + "] " + ses[i].getClassName()); - log.setSourceMethodName(ses[i].getMethodName()); - break; - } - } else { - log.setSourceClassName('[' + Thread.currentThread().getName() + "] " + sourceClassName); - } - if (denyreg != null && denyreg.matcher(log.getMessage()).find()) return; - logqueue.offer(log); - } - - @Override - public void flush() { - try { - if (logstream != null) logstream.flush(); - } catch (Exception e) { - ErrorManager err = getErrorManager(); - if (err != null) err.error(null, e, ErrorManager.FLUSH_FAILURE); - } - } - - @Override - public void close() throws SecurityException { - try { - if (logstream != null) logstream.close(); - } catch (Exception e) { - ErrorManager err = getErrorManager(); - if (err != null) err.error(null, e, ErrorManager.CLOSE_FAILURE); - } - } - -} +/* + * 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.boot; + +import org.redkale.util.RedkaleClassLoader; + +import java.io.*; +import java.nio.file.*; +import static java.nio.file.StandardCopyOption.*; +import java.time.*; +import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.*; +import java.util.logging.*; +import java.util.logging.Formatter; +import java.util.regex.Pattern; + +/** + * 鑷畾涔夌殑鏃ュ織杈撳嚭绫 + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@SuppressWarnings("unchecked") +public class LoggingFileHandler extends Handler { + + //public static final String FORMATTER_FORMAT = "%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%tL %4$s %2$s%n%5$s%6$s%n"; + public static final String FORMATTER_FORMAT = "%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%tL %4$s %2$s\r\n%5$s%6$s\r\n"; + + /** + * SNCP鐨勬棩蹇楄緭鍑篐andler + */ + public static class LoggingSncpFileHandler extends LoggingFileHandler { + + @Override + public String getPrefix() { + return "sncp-"; + } + } + + /** + * 榛樿鐨勬棩蹇楁椂闂存牸寮忓寲绫 + * 涓嶴impleFormatter鐨勫尯鍒湪浜巐evel涓嶄娇鐢ㄦ湰鍦板寲 + * + */ + public static class LoggingFormater extends Formatter { + + @Override + public String format(LogRecord log) { + String source; + if (log.getSourceClassName() != null) { + source = log.getSourceClassName(); + if (log.getSourceMethodName() != null) { + source += " " + log.getSourceMethodName(); + } + } else { + source = log.getLoggerName(); + } + String message = formatMessage(log); + String throwable = ""; + if (log.getThrown() != null) { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw) { + @Override + public void println() { + super.print("\r\n"); + } + }; + pw.println(); + log.getThrown().printStackTrace(pw); + pw.close(); + throwable = sw.toString(); + } + return String.format(FORMATTER_FORMAT, + System.currentTimeMillis(), + source, + log.getLoggerName(), + log.getLevel().getName(), + message, + throwable); + } + } + + public static void initDebugLogConfig() { + try { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + final PrintStream ps = new PrintStream(out); + ps.println("handlers = java.util.logging.ConsoleHandler"); + ps.println(".level = FINEST"); + ps.println("jdk.level = INFO"); + ps.println("sun.level = INFO"); + ps.println("com.sun.level = INFO"); + ps.println("javax.level = INFO"); + ps.println("java.util.logging.ConsoleHandler.level = FINEST"); + ps.println("java.util.logging.ConsoleHandler.formatter = " + LoggingFileHandler.LoggingFormater.class.getName()); + LogManager.getLogManager().readConfiguration(new ByteArrayInputStream(out.toByteArray())); + } catch (Exception e) { + } + } + + protected final LinkedBlockingQueue logqueue = new LinkedBlockingQueue(); + + private String pattern; + + private String unusual; //涓嶄负null琛ㄧず灏 WARNING銆丼EVERE 绾у埆鐨勬棩蹇楀啓鍏ュ崟鐙殑鏂囦欢涓 + + private int limit; //鏂囦欢澶у皬闄愬埗 + + private final AtomicInteger logindex = new AtomicInteger(); + + private final AtomicInteger logunusualindex = new AtomicInteger(); + + private int count = 1; //鏂囦欢闄愬埗 + + private long tomorrow; + + private boolean append; + + private Pattern denyreg; + + private final AtomicLong loglength = new AtomicLong(); + + private final AtomicLong logunusuallength = new AtomicLong(); + + private File logfile; + + private File logunusualfile; + + private OutputStream logstream; + + private OutputStream logunusualstream; + + public LoggingFileHandler() { + updateTomorrow(); + configure(); + open(); + } + + private void updateTomorrow() { + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.HOUR_OF_DAY, 0); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.MILLISECOND, 0); + cal.add(Calendar.DAY_OF_YEAR, 1); + long t = cal.getTimeInMillis(); + if (this.tomorrow != t) logindex.set(0); + this.tomorrow = t; + } + + private void open() { + final String name = "Redkale-Logging-" + getClass().getSimpleName() + "-Thread"; + new Thread() { + { + setName(name); + setDaemon(true); + } + + @Override + public void run() { + while (true) { + try { + LogRecord log = logqueue.take(); + final boolean bigger = (limit > 0 && limit <= loglength.get()); + final boolean changeday = tomorrow <= log.getMillis(); + if (bigger || changeday) { + updateTomorrow(); + if (logstream != null) { + logstream.close(); + if (bigger) { + for (int i = Math.min(count - 2, logindex.get() - 1); i > 0; i--) { + File greater = new File(logfile.getPath() + "." + i); + if (greater.exists()) Files.move(greater.toPath(), new File(logfile.getPath() + "." + (i + 1)).toPath(), REPLACE_EXISTING, ATOMIC_MOVE); + } + Files.move(logfile.toPath(), new File(logfile.getPath() + ".1").toPath(), REPLACE_EXISTING, ATOMIC_MOVE); + } else { + if (logfile.exists() && logfile.length() < 1) logfile.delete(); + } + logstream = null; + } + } + if (unusual != null && changeday && logunusualstream != null) { + logunusualstream.close(); + if (limit > 0 && limit <= logunusuallength.get()) { + for (int i = Math.min(count - 2, logunusualindex.get() - 1); i > 0; i--) { + File greater = new File(logunusualfile.getPath() + "." + i); + if (greater.exists()) Files.move(greater.toPath(), new File(logunusualfile.getPath() + "." + (i + 1)).toPath(), REPLACE_EXISTING, ATOMIC_MOVE); + } + Files.move(logunusualfile.toPath(), new File(logunusualfile.getPath() + ".1").toPath(), REPLACE_EXISTING, ATOMIC_MOVE); + } else { + if (logunusualfile.exists() && logunusualfile.length() < 1) logunusualfile.delete(); + } + logunusualstream = null; + } + if (logstream == null) { + logindex.incrementAndGet(); + java.time.LocalDate date = LocalDate.now(); + logfile = new File(pattern.replace("%m", String.valueOf((date.getYear() * 100 + date.getMonthValue()))).replace("%d", String.valueOf((date.getYear() * 10000 + date.getMonthValue() * 100 + date.getDayOfMonth())))); + logfile.getParentFile().mkdirs(); + loglength.set(logfile.length()); + logstream = new FileOutputStream(logfile, append); + } + if (unusual != null && logunusualstream == null) { + logunusualindex.incrementAndGet(); + java.time.LocalDate date = LocalDate.now(); + logunusualfile = new File(unusual.replace("%m", String.valueOf((date.getYear() * 100 + date.getMonthValue()))).replace("%d", String.valueOf((date.getYear() * 10000 + date.getMonthValue() * 100 + date.getDayOfMonth())))); + logunusualfile.getParentFile().mkdirs(); + logunusuallength.set(logunusualfile.length()); + logunusualstream = new FileOutputStream(logunusualfile, append); + } + //----------------------鍐欐棩蹇------------------------- + String message = getFormatter().format(log); + String encoding = getEncoding(); + byte[] bytes = encoding == null ? message.getBytes() : message.getBytes(encoding); + logstream.write(bytes); + loglength.addAndGet(bytes.length); + if (unusual != null && (log.getLevel() == Level.WARNING || log.getLevel() == Level.SEVERE)) { + logunusualstream.write(bytes); + logunusuallength.addAndGet(bytes.length); + } + } catch (Exception e) { + ErrorManager err = getErrorManager(); + if (err != null) err.error(null, e, ErrorManager.WRITE_FAILURE); + } + } + + } + }.start(); + } + + public String getPrefix() { + return ""; + } + + private void configure() { + LogManager manager = LogManager.getLogManager(); + String cname = LoggingFileHandler.class.getName(); + this.pattern = manager.getProperty(cname + ".pattern"); + if (this.pattern == null) { + this.pattern = "logs-%m/" + getPrefix() + "log-%d.log"; + } else { + int pos = this.pattern.lastIndexOf('/'); + if (pos > 0) { + this.pattern = this.pattern.substring(0, pos + 1) + getPrefix() + this.pattern.substring(pos + 1); + } else { + this.pattern = getPrefix() + this.pattern; + } + } + String unusualstr = manager.getProperty(cname + ".unusual"); + if (unusualstr != null) { + int pos = unusualstr.lastIndexOf('/'); + if (pos > 0) { + this.unusual = unusualstr.substring(0, pos + 1) + getPrefix() + unusualstr.substring(pos + 1); + } else { + this.unusual = getPrefix() + unusualstr; + } + } + String limitstr = manager.getProperty(cname + ".limit"); + try { + if (limitstr != null) { + limitstr = limitstr.toUpperCase(); + boolean g = limitstr.indexOf('G') > 0; + boolean m = limitstr.indexOf('M') > 0; + boolean k = limitstr.indexOf('K') > 0; + int ls = Math.abs(Integer.decode(limitstr.replace("G", "").replace("M", "").replace("K", "").replace("B", ""))); + if (g) { + ls *= 1024 * 1024 * 1024; + } else if (m) { + ls *= 1024 * 1024; + } else if (k) { + ls *= 1024; + } + this.limit = ls; + } + } catch (Exception e) { + } + String countstr = manager.getProperty(cname + ".count"); + try { + if (countstr != null) this.count = Math.max(1, Math.abs(Integer.decode(countstr))); + } catch (Exception e) { + } + String appendstr = manager.getProperty(cname + ".append"); + try { + if (appendstr != null) this.append = "true".equalsIgnoreCase(appendstr) || "1".equals(appendstr); + } catch (Exception e) { + } + String levelstr = manager.getProperty(cname + ".level"); + try { + if (levelstr != null) { + Level l = Level.parse(levelstr); + setLevel(l != null ? l : Level.ALL); + } + } catch (Exception e) { + } + String filterstr = manager.getProperty(cname + ".filter"); + try { + if (filterstr != null) { + Class clz = ClassLoader.getSystemClassLoader().loadClass(filterstr); + RedkaleClassLoader.putReflectionDeclaredConstructors(clz, clz.getName()); + setFilter((Filter) clz.getDeclaredConstructor().newInstance()); + } + } catch (Exception e) { + } + String formatterstr = manager.getProperty(cname + ".formatter"); + try { + if (formatterstr != null) { + Class clz = ClassLoader.getSystemClassLoader().loadClass(formatterstr); + RedkaleClassLoader.putReflectionDeclaredConstructors(clz, clz.getName()); + setFormatter((Formatter) clz.getDeclaredConstructor().newInstance()); + } + } catch (Exception e) { + } + if (getFormatter() == null) setFormatter(new SimpleFormatter()); + + String encodingstr = manager.getProperty(cname + ".encoding"); + try { + if (encodingstr != null) setEncoding(encodingstr); + } catch (Exception e) { + } + + String denyregstr = manager.getProperty(cname + ".denyreg"); + try { + if (denyregstr != null && !denyregstr.trim().isEmpty()) { + denyreg = Pattern.compile(denyregstr); + } + } catch (Exception e) { + } + } + + @Override + public void publish(LogRecord log) { + final String sourceClassName = log.getSourceClassName(); + if (sourceClassName == null || true) { + StackTraceElement[] ses = new Throwable().getStackTrace(); + for (int i = 2; i < ses.length; i++) { + if (ses[i].getClassName().startsWith("java.util.logging")) continue; + log.setSourceClassName('[' + Thread.currentThread().getName() + "] " + ses[i].getClassName()); + log.setSourceMethodName(ses[i].getMethodName()); + break; + } + } else { + log.setSourceClassName('[' + Thread.currentThread().getName() + "] " + sourceClassName); + } + if (denyreg != null && denyreg.matcher(log.getMessage()).find()) return; + logqueue.offer(log); + } + + @Override + public void flush() { + try { + if (logstream != null) logstream.flush(); + } catch (Exception e) { + ErrorManager err = getErrorManager(); + if (err != null) err.error(null, e, ErrorManager.FLUSH_FAILURE); + } + } + + @Override + public void close() throws SecurityException { + try { + if (logstream != null) logstream.close(); + } catch (Exception e) { + ErrorManager err = getErrorManager(); + if (err != null) err.error(null, e, ErrorManager.CLOSE_FAILURE); + } + } + +} diff --git a/src/main/java/org/redkale/boot/NodeInterceptor.java b/src/main/java/org/redkale/boot/NodeInterceptor.java index 138e41743..a6edf764b 100644 --- a/src/main/java/org/redkale/boot/NodeInterceptor.java +++ b/src/main/java/org/redkale/boot/NodeInterceptor.java @@ -1,38 +1,38 @@ -/* - * 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.boot; - -/** - * NodeServer鐨勬嫤鎴被 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public class NodeInterceptor { - - /** * - * Server.start涔嬪墠璋冪敤
- * NodeServer.start鐨勯儴缃叉槸鍏堟墽琛孨odeInterceptor.preStart锛屽啀鎵ц Server.start 鏂规硶 - * - * @param server NodeServer - */ - public void preStart(NodeServer server) { - - } - - /** - * Server.shutdown涔嬪墠璋冪敤
- * NodeServer.shutdown鐨勯儴缃叉槸鍏堟墽琛孨odeInterceptor.preShutdown锛屽啀鎵ц Server.sshutdown 鏂规硶 - * - * @param server NodeServer - */ - public void preShutdown(NodeServer server) { - - } - -} +/* + * 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.boot; + +/** + * NodeServer鐨勬嫤鎴被 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public class NodeInterceptor { + + /** * + * Server.start涔嬪墠璋冪敤
+ * NodeServer.start鐨勯儴缃叉槸鍏堟墽琛孨odeInterceptor.preStart锛屽啀鎵ц Server.start 鏂规硶 + * + * @param server NodeServer + */ + public void preStart(NodeServer server) { + + } + + /** + * Server.shutdown涔嬪墠璋冪敤
+ * NodeServer.shutdown鐨勯儴缃叉槸鍏堟墽琛孨odeInterceptor.preShutdown锛屽啀鎵ц Server.sshutdown 鏂规硶 + * + * @param server NodeServer + */ + public void preShutdown(NodeServer server) { + + } + +} diff --git a/src/main/java/org/redkale/boot/NodeProtocol.java b/src/main/java/org/redkale/boot/NodeProtocol.java index ab72e3cef..f37f8da57 100644 --- a/src/main/java/org/redkale/boot/NodeProtocol.java +++ b/src/main/java/org/redkale/boot/NodeProtocol.java @@ -1,24 +1,24 @@ -/* - * 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.boot; - -import java.lang.annotation.*; - -/** - * 鏍规嵁application.xml涓殑server鑺傜偣涓殑protocol鍊兼潵閫傞厤Server鐨勫姞杞介昏緫, 鍙兘娉ㄨВ鍦∟odeServer瀛愮被涓 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@Target({ElementType.TYPE}) -@Retention(RetentionPolicy.RUNTIME) -@Documented -public @interface NodeProtocol { - - String value(); -} +/* + * 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.boot; + +import java.lang.annotation.*; + +/** + * 鏍规嵁application.xml涓殑server鑺傜偣涓殑protocol鍊兼潵閫傞厤Server鐨勫姞杞介昏緫, 鍙兘娉ㄨВ鍦∟odeServer瀛愮被涓 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface NodeProtocol { + + String value(); +} diff --git a/src/main/java/org/redkale/boot/NodeSncpServer.java b/src/main/java/org/redkale/boot/NodeSncpServer.java index ef2e1e173..293d0d3de 100644 --- a/src/main/java/org/redkale/boot/NodeSncpServer.java +++ b/src/main/java/org/redkale/boot/NodeSncpServer.java @@ -1,125 +1,125 @@ -/* - * 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.boot; - -import java.lang.reflect.Modifier; -import java.net.*; -import java.util.*; -import java.util.logging.Level; -import org.redkale.boot.ClassFilter.FilterEntry; -import org.redkale.mq.MessageAgent; -import org.redkale.net.*; -import org.redkale.net.sncp.*; -import org.redkale.service.*; -import org.redkale.util.*; -import org.redkale.util.AnyValue.DefaultAnyValue; - -/** - * SNCP Server鑺傜偣鐨勯厤缃甋erver - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@NodeProtocol("SNCP") -public class NodeSncpServer extends NodeServer { - - protected final SncpServer sncpServer; - - private NodeSncpServer(Application application, AnyValue serconf) { - super(application, createServer(application, serconf)); - this.sncpServer = (SncpServer) this.server; - this.consumer = sncpServer == null || application.isSingletonMode() ? null : (agent, x) -> {//singleton妯″紡涓嬩笉鐢熸垚SncpServlet - if (x.getClass().getAnnotation(Local.class) != null) return; //鏈湴妯″紡鐨凷ervice涓嶇敓鎴怱ncpServlet - SncpDynServlet servlet = sncpServer.addSncpServlet(x); - dynServletMap.put(x, servlet); - if (agent != null) agent.putService(this, x, servlet); - }; - } - - public static NodeServer createNodeServer(Application application, AnyValue serconf) { - return new NodeSncpServer(application, serconf); - } - - private static Server createServer(Application application, AnyValue serconf) { - return new SncpServer(application, application.getStartTime(), serconf, application.getResourceFactory().createChild()); - } - - @Override - public InetSocketAddress getSocketAddress() { - return sncpServer == null ? null : sncpServer.getSocketAddress(); - } - - public void consumerAccept(MessageAgent messageAgent, Service service) { - if (this.consumer != null) this.consumer.accept(messageAgent, service); - } - - @Override - public void init(AnyValue config) throws Exception { - super.init(config); - //------------------------------------------------------------------- - if (sncpServer == null) return; //璋冭瘯鏃秙erver鎵嶅彲鑳戒负null - final StringBuilder sb = logger.isLoggable(Level.FINE) ? new StringBuilder() : null; - final String localThreadName = "[" + Thread.currentThread().getName() + "] "; - List servlets = sncpServer.getSncpServlets(); - Collections.sort(servlets); - for (SncpServlet en : servlets) { - if (sb != null) sb.append(localThreadName).append(" Load ").append(en).append(LINE_SEPARATOR); - } - if (sb != null && sb.length() > 0) logger.log(Level.FINE, sb.toString()); - } - - @Override - public boolean isSNCP() { - return true; - } - - public SncpServer getSncpServer() { - return sncpServer; - } - - @Override - protected void loadFilter(ClassFilter filterFilter, ClassFilter otherFilter) throws Exception { - if (sncpServer != null) loadSncpFilter(this.serverConf.getAnyValue("fliters"), filterFilter); - } - - @SuppressWarnings("unchecked") - protected void loadSncpFilter(final AnyValue servletsConf, final ClassFilter classFilter) throws Exception { - final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null; - final String localThreadName = "[" + Thread.currentThread().getName() + "] "; - List> list = new ArrayList(classFilter.getFilterEntrys()); - for (FilterEntry en : list) { - Class clazz = (Class) en.getType(); - if (Modifier.isAbstract(clazz.getModifiers())) continue; - RedkaleClassLoader.putReflectionDeclaredConstructors(clazz, clazz.getName()); - final SncpFilter filter = clazz.getDeclaredConstructor().newInstance(); - resourceFactory.inject(filter, this); - DefaultAnyValue filterConf = (DefaultAnyValue) en.getProperty(); - this.sncpServer.addSncpFilter(filter, filterConf); - if (sb != null) sb.append(localThreadName).append(" Load ").append(clazz.getName()).append(LINE_SEPARATOR); - } - if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString()); - } - - @Override - protected void loadServlet(ClassFilter servletFilter, ClassFilter otherFilter) throws Exception { - RedkaleClassLoader.putReflectionPublicClasses(SncpServlet.class.getName()); - RedkaleClassLoader.putReflectionPublicClasses(SncpDynServlet.class.getName()); - } - - @Override - @SuppressWarnings("unchecked") - protected ClassFilter createFilterClassFilter() { - return createClassFilter(null, null, SncpFilter.class, new Class[]{org.redkale.watch.WatchFilter.class}, null, "filters", "filter"); - } - - @Override - protected ClassFilter createServletClassFilter() { - return null; - } - -} +/* + * 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.boot; + +import java.lang.reflect.Modifier; +import java.net.*; +import java.util.*; +import java.util.logging.Level; +import org.redkale.boot.ClassFilter.FilterEntry; +import org.redkale.mq.MessageAgent; +import org.redkale.net.*; +import org.redkale.net.sncp.*; +import org.redkale.service.*; +import org.redkale.util.*; +import org.redkale.util.AnyValue.DefaultAnyValue; + +/** + * SNCP Server鑺傜偣鐨勯厤缃甋erver + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@NodeProtocol("SNCP") +public class NodeSncpServer extends NodeServer { + + protected final SncpServer sncpServer; + + private NodeSncpServer(Application application, AnyValue serconf) { + super(application, createServer(application, serconf)); + this.sncpServer = (SncpServer) this.server; + this.consumer = sncpServer == null || application.isSingletonMode() ? null : (agent, x) -> {//singleton妯″紡涓嬩笉鐢熸垚SncpServlet + if (x.getClass().getAnnotation(Local.class) != null) return; //鏈湴妯″紡鐨凷ervice涓嶇敓鎴怱ncpServlet + SncpDynServlet servlet = sncpServer.addSncpServlet(x); + dynServletMap.put(x, servlet); + if (agent != null) agent.putService(this, x, servlet); + }; + } + + public static NodeServer createNodeServer(Application application, AnyValue serconf) { + return new NodeSncpServer(application, serconf); + } + + private static Server createServer(Application application, AnyValue serconf) { + return new SncpServer(application, application.getStartTime(), serconf, application.getResourceFactory().createChild()); + } + + @Override + public InetSocketAddress getSocketAddress() { + return sncpServer == null ? null : sncpServer.getSocketAddress(); + } + + public void consumerAccept(MessageAgent messageAgent, Service service) { + if (this.consumer != null) this.consumer.accept(messageAgent, service); + } + + @Override + public void init(AnyValue config) throws Exception { + super.init(config); + //------------------------------------------------------------------- + if (sncpServer == null) return; //璋冭瘯鏃秙erver鎵嶅彲鑳戒负null + final StringBuilder sb = logger.isLoggable(Level.FINE) ? new StringBuilder() : null; + final String localThreadName = "[" + Thread.currentThread().getName() + "] "; + List servlets = sncpServer.getSncpServlets(); + Collections.sort(servlets); + for (SncpServlet en : servlets) { + if (sb != null) sb.append(localThreadName).append(" Load ").append(en).append(LINE_SEPARATOR); + } + if (sb != null && sb.length() > 0) logger.log(Level.FINE, sb.toString()); + } + + @Override + public boolean isSNCP() { + return true; + } + + public SncpServer getSncpServer() { + return sncpServer; + } + + @Override + protected void loadFilter(ClassFilter filterFilter, ClassFilter otherFilter) throws Exception { + if (sncpServer != null) loadSncpFilter(this.serverConf.getAnyValue("fliters"), filterFilter); + } + + @SuppressWarnings("unchecked") + protected void loadSncpFilter(final AnyValue servletsConf, final ClassFilter classFilter) throws Exception { + final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null; + final String localThreadName = "[" + Thread.currentThread().getName() + "] "; + List> list = new ArrayList(classFilter.getFilterEntrys()); + for (FilterEntry en : list) { + Class clazz = (Class) en.getType(); + if (Modifier.isAbstract(clazz.getModifiers())) continue; + RedkaleClassLoader.putReflectionDeclaredConstructors(clazz, clazz.getName()); + final SncpFilter filter = clazz.getDeclaredConstructor().newInstance(); + resourceFactory.inject(filter, this); + DefaultAnyValue filterConf = (DefaultAnyValue) en.getProperty(); + this.sncpServer.addSncpFilter(filter, filterConf); + if (sb != null) sb.append(localThreadName).append(" Load ").append(clazz.getName()).append(LINE_SEPARATOR); + } + if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString()); + } + + @Override + protected void loadServlet(ClassFilter servletFilter, ClassFilter otherFilter) throws Exception { + RedkaleClassLoader.putReflectionPublicClasses(SncpServlet.class.getName()); + RedkaleClassLoader.putReflectionPublicClasses(SncpDynServlet.class.getName()); + } + + @Override + @SuppressWarnings("unchecked") + protected ClassFilter createFilterClassFilter() { + return createClassFilter(null, null, SncpFilter.class, new Class[]{org.redkale.watch.WatchFilter.class}, null, "filters", "filter"); + } + + @Override + protected ClassFilter createServletClassFilter() { + return null; + } + +} diff --git a/src/main/java/org/redkale/boot/NodeWatchServer.java b/src/main/java/org/redkale/boot/NodeWatchServer.java index 67760a416..b7ea1f695 100644 --- a/src/main/java/org/redkale/boot/NodeWatchServer.java +++ b/src/main/java/org/redkale/boot/NodeWatchServer.java @@ -1,53 +1,53 @@ -/* - * 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.boot; - -import java.lang.annotation.Annotation; -import org.redkale.net.*; -import org.redkale.net.http.*; -import org.redkale.service.Service; -import org.redkale.util.AnyValue; -import org.redkale.watch.*; - -/** - * - * @author zhangjx - */ -@NodeProtocol("WATCH") -public class NodeWatchServer extends NodeHttpServer { - - public NodeWatchServer(Application application, AnyValue serconf) { - super(application, serconf); - } - - @Override - @SuppressWarnings("unchecked") - protected ClassFilter createServiceClassFilter() { - return createClassFilter(this.sncpGroup, null, WatchService.class, null, Annotation.class, "services", "service"); - } - - @Override - @SuppressWarnings("unchecked") - protected ClassFilter createFilterClassFilter() { - return createClassFilter(null, null, WatchFilter.class, null, null, "filters", "filter"); - } - - @Override - @SuppressWarnings("unchecked") - protected ClassFilter createServletClassFilter() { - return createClassFilter(null, WebServlet.class, WatchServlet.class, null, null, "servlets", "servlet"); - } - - @Override - protected ClassFilter createOtherClassFilter() { - return null; - } - - @Override - public boolean isWATCH() { - return true; - } -} +/* + * 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.boot; + +import java.lang.annotation.Annotation; +import org.redkale.net.*; +import org.redkale.net.http.*; +import org.redkale.service.Service; +import org.redkale.util.AnyValue; +import org.redkale.watch.*; + +/** + * + * @author zhangjx + */ +@NodeProtocol("WATCH") +public class NodeWatchServer extends NodeHttpServer { + + public NodeWatchServer(Application application, AnyValue serconf) { + super(application, serconf); + } + + @Override + @SuppressWarnings("unchecked") + protected ClassFilter createServiceClassFilter() { + return createClassFilter(this.sncpGroup, null, WatchService.class, null, Annotation.class, "services", "service"); + } + + @Override + @SuppressWarnings("unchecked") + protected ClassFilter createFilterClassFilter() { + return createClassFilter(null, null, WatchFilter.class, null, null, "filters", "filter"); + } + + @Override + @SuppressWarnings("unchecked") + protected ClassFilter createServletClassFilter() { + return createClassFilter(null, WebServlet.class, WatchServlet.class, null, null, "servlets", "servlet"); + } + + @Override + protected ClassFilter createOtherClassFilter() { + return null; + } + + @Override + public boolean isWATCH() { + return true; + } +} diff --git a/src/main/java/org/redkale/boot/PrepareCompiler.java b/src/main/java/org/redkale/boot/PrepareCompiler.java index ed91febcc..7a1c0efca 100644 --- a/src/main/java/org/redkale/boot/PrepareCompiler.java +++ b/src/main/java/org/redkale/boot/PrepareCompiler.java @@ -1,86 +1,86 @@ -/* - * 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.boot; - -import java.lang.reflect.Modifier; -import javax.persistence.Entity; -import org.redkale.boot.ClassFilter.FilterEntry; -import org.redkale.convert.Decodeable; -import org.redkale.convert.bson.BsonFactory; -import org.redkale.convert.json.*; -import org.redkale.source.*; -import org.redkale.util.*; - -/** - * 鎵ц涓娆pplication.run鎻愬墠鑾峰彇鎵鏈夊姩鎬佺被 - * - * @author zhangjx - * @since 2.5.0 - */ -public class PrepareCompiler { - -// public static void main(String[] args) throws Exception { -// new PrepareCompiler().run(); -// } - public Application run() throws Exception { - final Application application = new Application(false, true, Application.loadAppConfig()); - application.init(); - for (ApplicationListener listener : application.listeners) { - listener.preStart(application); - } - for (ApplicationListener listener : application.listeners) { - listener.preCompile(application); - } - application.start(); - final boolean hasSncp = application.getNodeServers().stream().filter(v -> v instanceof NodeSncpServer).findFirst().isPresent(); - final String[] exlibs = (application.excludelibs != null ? (application.excludelibs + ";") : "").split(";"); - - final ClassFilter entityFilter = new ClassFilter(application.getClassLoader(), Entity.class, Object.class, (Class[]) null); - final ClassFilter beanFilter = new ClassFilter(application.getClassLoader(), Bean.class, Object.class, (Class[]) null); - final ClassFilter filterFilter = new ClassFilter(application.getClassLoader(), null, FilterBean.class, (Class[]) null); - - ClassFilter.Loader.load(application.getHome(), application.getClassLoader(), exlibs, entityFilter, beanFilter, filterFilter); - - for (FilterEntry en : entityFilter.getFilterEntrys()) { - Class clz = en.getType(); - if (clz.isInterface() || Modifier.isAbstract(clz.getModifiers())) continue; - try { - application.dataSources.forEach(source -> source.compile(clz)); - JsonFactory.root().loadEncoder(clz); - if (hasSncp) BsonFactory.root().loadEncoder(clz); - Decodeable decoder = JsonFactory.root().loadDecoder(clz); - if (hasSncp) BsonFactory.root().loadDecoder(clz); - decoder.convertFrom(new JsonReader("{}")); - } catch (Exception e) { //JsonFactory.loadDecoder鍙兘浼氬け璐ワ紝鍥犱负class鍙兘鍖呭惈鎶借薄绫诲瓧娈,濡侰olumnValue.value瀛楁 - } - } - for (FilterEntry en : beanFilter.getFilterEntrys()) { - Class clz = en.getType(); - if (clz.isInterface() || Modifier.isAbstract(clz.getModifiers())) continue; - try { - JsonFactory.root().loadEncoder(clz); - if (hasSncp) BsonFactory.root().loadEncoder(clz); - Decodeable decoder = JsonFactory.root().loadDecoder(clz); - if (hasSncp) BsonFactory.root().loadDecoder(clz); - decoder.convertFrom(new JsonReader("{}")); - } catch (Exception e) { //JsonFactory.loadDecoder鍙兘浼氬け璐ワ紝鍥犱负class鍙兘鍖呭惈鎶借薄绫诲瓧娈,濡侰olumnValue.value瀛楁 - } - } - for (FilterEntry en : filterFilter.getFilterEntrys()) { - Class clz = en.getType(); - if (clz.isInterface() || Modifier.isAbstract(clz.getModifiers())) continue; - try { - FilterNodeBean.load(clz); - } catch (Exception e) { - } - } - for (ApplicationListener listener : application.listeners) { - listener.postCompile(application); - } - application.shutdown(); - return application; - } -} +/* + * 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.boot; + +import java.lang.reflect.Modifier; +import javax.persistence.Entity; +import org.redkale.boot.ClassFilter.FilterEntry; +import org.redkale.convert.Decodeable; +import org.redkale.convert.bson.BsonFactory; +import org.redkale.convert.json.*; +import org.redkale.source.*; +import org.redkale.util.*; + +/** + * 鎵ц涓娆pplication.run鎻愬墠鑾峰彇鎵鏈夊姩鎬佺被 + * + * @author zhangjx + * @since 2.5.0 + */ +public class PrepareCompiler { + +// public static void main(String[] args) throws Exception { +// new PrepareCompiler().run(); +// } + public Application run() throws Exception { + final Application application = new Application(false, true, Application.loadAppConfig()); + application.init(); + for (ApplicationListener listener : application.listeners) { + listener.preStart(application); + } + for (ApplicationListener listener : application.listeners) { + listener.preCompile(application); + } + application.start(); + final boolean hasSncp = application.getNodeServers().stream().filter(v -> v instanceof NodeSncpServer).findFirst().isPresent(); + final String[] exlibs = (application.excludelibs != null ? (application.excludelibs + ";") : "").split(";"); + + final ClassFilter entityFilter = new ClassFilter(application.getClassLoader(), Entity.class, Object.class, (Class[]) null); + final ClassFilter beanFilter = new ClassFilter(application.getClassLoader(), Bean.class, Object.class, (Class[]) null); + final ClassFilter filterFilter = new ClassFilter(application.getClassLoader(), null, FilterBean.class, (Class[]) null); + + ClassFilter.Loader.load(application.getHome(), application.getClassLoader(), exlibs, entityFilter, beanFilter, filterFilter); + + for (FilterEntry en : entityFilter.getFilterEntrys()) { + Class clz = en.getType(); + if (clz.isInterface() || Modifier.isAbstract(clz.getModifiers())) continue; + try { + application.dataSources.forEach(source -> source.compile(clz)); + JsonFactory.root().loadEncoder(clz); + if (hasSncp) BsonFactory.root().loadEncoder(clz); + Decodeable decoder = JsonFactory.root().loadDecoder(clz); + if (hasSncp) BsonFactory.root().loadDecoder(clz); + decoder.convertFrom(new JsonReader("{}")); + } catch (Exception e) { //JsonFactory.loadDecoder鍙兘浼氬け璐ワ紝鍥犱负class鍙兘鍖呭惈鎶借薄绫诲瓧娈,濡侰olumnValue.value瀛楁 + } + } + for (FilterEntry en : beanFilter.getFilterEntrys()) { + Class clz = en.getType(); + if (clz.isInterface() || Modifier.isAbstract(clz.getModifiers())) continue; + try { + JsonFactory.root().loadEncoder(clz); + if (hasSncp) BsonFactory.root().loadEncoder(clz); + Decodeable decoder = JsonFactory.root().loadDecoder(clz); + if (hasSncp) BsonFactory.root().loadDecoder(clz); + decoder.convertFrom(new JsonReader("{}")); + } catch (Exception e) { //JsonFactory.loadDecoder鍙兘浼氬け璐ワ紝鍥犱负class鍙兘鍖呭惈鎶借薄绫诲瓧娈,濡侰olumnValue.value瀛楁 + } + } + for (FilterEntry en : filterFilter.getFilterEntrys()) { + Class clz = en.getType(); + if (clz.isInterface() || Modifier.isAbstract(clz.getModifiers())) continue; + try { + FilterNodeBean.load(clz); + } catch (Exception e) { + } + } + for (ApplicationListener listener : application.listeners) { + listener.postCompile(application); + } + application.shutdown(); + return application; + } +} diff --git a/src/main/java/org/redkale/boot/apidoc-template.html b/src/main/java/org/redkale/boot/apidoc-template.html index fa0c5cdc5..755dfc2e7 100644 --- a/src/main/java/org/redkale/boot/apidoc-template.html +++ b/src/main/java/org/redkale/boot/apidoc-template.html @@ -1,110 +1,110 @@ - - - - 鎺ュ彛鏂囨。(apidoc鐢熸垚) - - - - - - - - - + + + + 鎺ュ彛鏂囨。(apidoc鐢熸垚) + + + + + + + + + diff --git a/src/main/java/org/redkale/boot/package-info.java b/src/main/java/org/redkale/boot/package-info.java index 4e9f60058..2b9eae06d 100644 --- a/src/main/java/org/redkale/boot/package-info.java +++ b/src/main/java/org/redkale/boot/package-info.java @@ -1,4 +1,4 @@ -/** - * 鎻愪緵Redkale鏈嶅姟鍣ㄧ殑鍚姩銆佸垵濮嬪寲鍜屽姞杞藉姛鑳 - */ -package org.redkale.boot; +/** + * 鎻愪緵Redkale鏈嶅姟鍣ㄧ殑鍚姩銆佸垵濮嬪寲鍜屽姞杞藉姛鑳 + */ +package org.redkale.boot; diff --git a/src/main/java/org/redkale/boot/watch/AbstractWatchService.java b/src/main/java/org/redkale/boot/watch/AbstractWatchService.java index 673d7d781..29d385c2e 100644 --- a/src/main/java/org/redkale/boot/watch/AbstractWatchService.java +++ b/src/main/java/org/redkale/boot/watch/AbstractWatchService.java @@ -1,23 +1,23 @@ -/* - * 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.boot.watch; - -import org.redkale.service.AbstractService; -import org.redkale.util.Comment; -import org.redkale.watch.WatchService; - -/** - * - * @author zhangjx - */ -public abstract class AbstractWatchService extends AbstractService implements WatchService { - - @Comment("缂哄皯鍙傛暟") - public static final int RET_WATCH_PARAMS_ILLEGAL = 1600_0001; - - @Comment("鎵ц寮傚父") - public static final int RET_WATCH_RUN_EXCEPTION = 1600_0002; -} +/* + * 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.boot.watch; + +import org.redkale.service.AbstractService; +import org.redkale.util.Comment; +import org.redkale.watch.WatchService; + +/** + * + * @author zhangjx + */ +public abstract class AbstractWatchService extends AbstractService implements WatchService { + + @Comment("缂哄皯鍙傛暟") + public static final int RET_WATCH_PARAMS_ILLEGAL = 1600_0001; + + @Comment("鎵ц寮傚父") + public static final int RET_WATCH_RUN_EXCEPTION = 1600_0002; +} diff --git a/src/main/java/org/redkale/boot/watch/FilterWatchService.java b/src/main/java/org/redkale/boot/watch/FilterWatchService.java index e5c24137f..039edbef2 100644 --- a/src/main/java/org/redkale/boot/watch/FilterWatchService.java +++ b/src/main/java/org/redkale/boot/watch/FilterWatchService.java @@ -1,80 +1,80 @@ -/* - * 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.boot.watch; - -import java.io.IOException; -import java.util.List; -import javax.annotation.Resource; -import org.redkale.boot.*; -import org.redkale.net.http.*; -import org.redkale.service.RetResult; -import org.redkale.util.Comment; - -/** - * - * @author zhangjx - */ -@RestService(name = "filter", catalog = "watch", repair = false) -public class FilterWatchService extends AbstractWatchService { - - @Comment("Filter绫诲悕涓嶅瓨鍦") - public static final int RET_FILTER_TYPE_NOT_EXISTS = 1601_0002; - - @Comment("Filter绫诲悕涓嶅悎娉") - public static final int RET_FILTER_TYPE_ILLEGAL = 1601_0003; - - @Comment("Filter绫诲悕宸插瓨鍦") - public static final int RET_FILTER_EXISTS = 1601_0004; - - @Comment("Filter鐨凧AR鍖呬笉瀛樺湪") - public static final int RET_FILTER_JAR_ILLEGAL = 1601_0005; - - @Resource - protected Application application; - - @RestMapping(name = "addFilter", auth = false, comment = "鍔ㄦ佸鍔燜ilter") - public RetResult addFilter(@RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameReg = "\\.jar$") byte[] jar, - @RestParam(name = "server", comment = "Server鑺傜偣鍚") final String serverName, - @RestParam(name = "type", comment = "Filter绫诲悕") final String filterType) throws IOException { - if (filterType == null) return new RetResult(RET_FILTER_TYPE_NOT_EXISTS, "Not found Filter Type (" + filterType + ")"); - if (jar == null) return new RetResult(RET_FILTER_JAR_ILLEGAL, "Not found jar file"); - List nodes = application.getNodeServers(); - for (NodeServer node : nodes) { - if (node.getServer().containsFilter(filterType)) return new RetResult(RET_FILTER_EXISTS, "Filter(" + filterType + ") exists"); - } - return RetResult.success(); - } - - @RestMapping(name = "test1", auth = false, comment = "棰勭暀") - public RetResult test1() { - return RetResult.success(); - } - - @RestMapping(name = "test2", auth = false, comment = "棰勭暀") - public RetResult test2() { - return RetResult.success(); - } - - @RestMapping(name = "test3", auth = false, comment = "棰勭暀") - public RetResult test3() { - return RetResult.success(); - } - - @RestMapping(name = "test4", auth = false, comment = "棰勭暀") - public RetResult test4() { - return RetResult.success(); - } - - @RestMapping(name = "test5", auth = false, comment = "棰勭暀") - public RetResult test5() { - return RetResult.success(); - } - - @RestMapping(name = "test6", auth = false, comment = "棰勭暀") - public RetResult test6() { - return RetResult.success(); - } -} +/* + * 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.boot.watch; + +import java.io.IOException; +import java.util.List; +import javax.annotation.Resource; +import org.redkale.boot.*; +import org.redkale.net.http.*; +import org.redkale.service.RetResult; +import org.redkale.util.Comment; + +/** + * + * @author zhangjx + */ +@RestService(name = "filter", catalog = "watch", repair = false) +public class FilterWatchService extends AbstractWatchService { + + @Comment("Filter绫诲悕涓嶅瓨鍦") + public static final int RET_FILTER_TYPE_NOT_EXISTS = 1601_0002; + + @Comment("Filter绫诲悕涓嶅悎娉") + public static final int RET_FILTER_TYPE_ILLEGAL = 1601_0003; + + @Comment("Filter绫诲悕宸插瓨鍦") + public static final int RET_FILTER_EXISTS = 1601_0004; + + @Comment("Filter鐨凧AR鍖呬笉瀛樺湪") + public static final int RET_FILTER_JAR_ILLEGAL = 1601_0005; + + @Resource + protected Application application; + + @RestMapping(name = "addFilter", auth = false, comment = "鍔ㄦ佸鍔燜ilter") + public RetResult addFilter(@RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameReg = "\\.jar$") byte[] jar, + @RestParam(name = "server", comment = "Server鑺傜偣鍚") final String serverName, + @RestParam(name = "type", comment = "Filter绫诲悕") final String filterType) throws IOException { + if (filterType == null) return new RetResult(RET_FILTER_TYPE_NOT_EXISTS, "Not found Filter Type (" + filterType + ")"); + if (jar == null) return new RetResult(RET_FILTER_JAR_ILLEGAL, "Not found jar file"); + List nodes = application.getNodeServers(); + for (NodeServer node : nodes) { + if (node.getServer().containsFilter(filterType)) return new RetResult(RET_FILTER_EXISTS, "Filter(" + filterType + ") exists"); + } + return RetResult.success(); + } + + @RestMapping(name = "test1", auth = false, comment = "棰勭暀") + public RetResult test1() { + return RetResult.success(); + } + + @RestMapping(name = "test2", auth = false, comment = "棰勭暀") + public RetResult test2() { + return RetResult.success(); + } + + @RestMapping(name = "test3", auth = false, comment = "棰勭暀") + public RetResult test3() { + return RetResult.success(); + } + + @RestMapping(name = "test4", auth = false, comment = "棰勭暀") + public RetResult test4() { + return RetResult.success(); + } + + @RestMapping(name = "test5", auth = false, comment = "棰勭暀") + public RetResult test5() { + return RetResult.success(); + } + + @RestMapping(name = "test6", auth = false, comment = "棰勭暀") + public RetResult test6() { + return RetResult.success(); + } +} diff --git a/src/main/java/org/redkale/boot/watch/ServerWatchService.java b/src/main/java/org/redkale/boot/watch/ServerWatchService.java index 1e2c2cf1e..80e7476c9 100644 --- a/src/main/java/org/redkale/boot/watch/ServerWatchService.java +++ b/src/main/java/org/redkale/boot/watch/ServerWatchService.java @@ -1,104 +1,104 @@ -/* - * 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.boot.watch; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.util.*; -import java.util.stream.Stream; -import javax.annotation.Resource; -import org.redkale.boot.*; -import org.redkale.net.Server; -import org.redkale.net.http.*; -import org.redkale.service.RetResult; -import org.redkale.util.Comment; - -/** - * - * @author zhangjx - */ -@RestService(name = "server", catalog = "watch", repair = false) -public class ServerWatchService extends AbstractWatchService { - - @Comment("涓嶅瓨鍦ㄧ殑Server鑺傜偣") - public static final int RET_SERVER_NOT_EXISTS = 1602_0001; - - @Comment("鏇存敼Server鐩戝惉鍦板潃绔彛澶辫触") - public static final int RET_SERVER_CHANGEPORT_ERROR = 1602_0002; - - @Resource - protected Application application; - - @RestMapping(name = "info", comment = "鍗曚釜Server淇℃伅鏌ヨ") - public RetResult info(@RestParam(name = "#port:") final int port) { - Stream stream = application.getNodeServers().stream(); - NodeServer node = stream.filter(ns -> ns.getServer().getSocketAddress().getPort() == port).findFirst().orElse(null); - if (node == null) return new RetResult(RET_SERVER_NOT_EXISTS, "Server(port=" + port + ") not found"); - return new RetResult(formatToMap(node)); - } - - @RestMapping(name = "infos", comment = "Server淇℃伅鏌ヨ") - public RetResult infos() { - Map rs = new LinkedHashMap<>(); - for (NodeServer ns : application.getNodeServers()) { - Server server = ns.getServer(); - rs.put("" + server.getSocketAddress().getPort(), formatToMap(ns)); - } - return new RetResult(rs); - } - - @RestMapping(name = "changeAddress", comment = "鏇存敼Server鐨勭洃鍚湴鍧鍜岀鍙") - public RetResult changeAddress(@RestParam(name = "#port:") final int oldport, - @RestParam(name = "#newhost:") final String newhost, @RestParam(name = "#newport:") final int newport) { - if (oldport < 1) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `oldport`"); - if (newport < 1) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `newport`"); - Stream stream = application.getNodeServers().stream(); - NodeServer node = stream.filter(ns -> ns.getServer().getSocketAddress().getPort() == oldport).findFirst().orElse(null); - if (node == null) return new RetResult(RET_SERVER_NOT_EXISTS, "Server(port=" + oldport + ") not found"); - final Server server = node.getServer(); - InetSocketAddress newAddr = new InetSocketAddress(newhost == null || newhost.isEmpty() ? server.getSocketAddress().getHostString() : newhost, newport); - try { - server.changeAddress(application, newAddr); - } catch (IOException e) { - e.printStackTrace(); - return new RetResult(RET_SERVER_CHANGEPORT_ERROR, "changeaddress error"); - } - return RetResult.success(); - } - - private Map formatToMap(NodeServer node) { - Server server = node.getServer(); - Map rs = new LinkedHashMap<>(); - String protocol = server.getNetprotocol(); - if (node instanceof NodeSncpServer) { - protocol += "/SNCP"; - } else if (node instanceof NodeWatchServer) { - protocol += "/WATCH"; - } else if (node instanceof NodeHttpServer) { - protocol += "/HTTP"; - } else { - NodeProtocol np = node.getClass().getAnnotation(NodeProtocol.class); - protocol += "/" + np.value(); - } - rs.put("name", server.getName()); - rs.put("protocol", protocol); - rs.put("address", server.getSocketAddress()); - rs.put("backlog", server.getBacklog()); - rs.put("bufferCapacity", server.getBufferCapacity()); - rs.put("bufferPoolSize", server.getBufferPoolSize()); - rs.put("charset", server.getCharset() == null ? "UTF-8" : server.getCharset().name()); - rs.put("maxbody", server.getMaxbody()); - rs.put("maxconns", server.getMaxconns()); - rs.put("serverStartTime", server.getServerStartTime()); - rs.put("responsePoolSize", server.getResponsePoolSize()); - rs.put("readTimeoutSeconds", server.getReadTimeoutSeconds()); - rs.put("writeTimeoutSeconds", server.getWriteTimeoutSeconds()); - rs.put("createConnectionCount", server.getCreateConnectionCount()); - rs.put("livingConnectionCount", server.getLivingConnectionCount()); - rs.put("closedConnectionCount", server.getClosedConnectionCount()); - return rs; - } -} +/* + * 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.boot.watch; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.util.*; +import java.util.stream.Stream; +import javax.annotation.Resource; +import org.redkale.boot.*; +import org.redkale.net.Server; +import org.redkale.net.http.*; +import org.redkale.service.RetResult; +import org.redkale.util.Comment; + +/** + * + * @author zhangjx + */ +@RestService(name = "server", catalog = "watch", repair = false) +public class ServerWatchService extends AbstractWatchService { + + @Comment("涓嶅瓨鍦ㄧ殑Server鑺傜偣") + public static final int RET_SERVER_NOT_EXISTS = 1602_0001; + + @Comment("鏇存敼Server鐩戝惉鍦板潃绔彛澶辫触") + public static final int RET_SERVER_CHANGEPORT_ERROR = 1602_0002; + + @Resource + protected Application application; + + @RestMapping(name = "info", comment = "鍗曚釜Server淇℃伅鏌ヨ") + public RetResult info(@RestParam(name = "#port:") final int port) { + Stream stream = application.getNodeServers().stream(); + NodeServer node = stream.filter(ns -> ns.getServer().getSocketAddress().getPort() == port).findFirst().orElse(null); + if (node == null) return new RetResult(RET_SERVER_NOT_EXISTS, "Server(port=" + port + ") not found"); + return new RetResult(formatToMap(node)); + } + + @RestMapping(name = "infos", comment = "Server淇℃伅鏌ヨ") + public RetResult infos() { + Map rs = new LinkedHashMap<>(); + for (NodeServer ns : application.getNodeServers()) { + Server server = ns.getServer(); + rs.put("" + server.getSocketAddress().getPort(), formatToMap(ns)); + } + return new RetResult(rs); + } + + @RestMapping(name = "changeAddress", comment = "鏇存敼Server鐨勭洃鍚湴鍧鍜岀鍙") + public RetResult changeAddress(@RestParam(name = "#port:") final int oldport, + @RestParam(name = "#newhost:") final String newhost, @RestParam(name = "#newport:") final int newport) { + if (oldport < 1) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `oldport`"); + if (newport < 1) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `newport`"); + Stream stream = application.getNodeServers().stream(); + NodeServer node = stream.filter(ns -> ns.getServer().getSocketAddress().getPort() == oldport).findFirst().orElse(null); + if (node == null) return new RetResult(RET_SERVER_NOT_EXISTS, "Server(port=" + oldport + ") not found"); + final Server server = node.getServer(); + InetSocketAddress newAddr = new InetSocketAddress(newhost == null || newhost.isEmpty() ? server.getSocketAddress().getHostString() : newhost, newport); + try { + server.changeAddress(application, newAddr); + } catch (IOException e) { + e.printStackTrace(); + return new RetResult(RET_SERVER_CHANGEPORT_ERROR, "changeaddress error"); + } + return RetResult.success(); + } + + private Map formatToMap(NodeServer node) { + Server server = node.getServer(); + Map rs = new LinkedHashMap<>(); + String protocol = server.getNetprotocol(); + if (node instanceof NodeSncpServer) { + protocol += "/SNCP"; + } else if (node instanceof NodeWatchServer) { + protocol += "/WATCH"; + } else if (node instanceof NodeHttpServer) { + protocol += "/HTTP"; + } else { + NodeProtocol np = node.getClass().getAnnotation(NodeProtocol.class); + protocol += "/" + np.value(); + } + rs.put("name", server.getName()); + rs.put("protocol", protocol); + rs.put("address", server.getSocketAddress()); + rs.put("backlog", server.getBacklog()); + rs.put("bufferCapacity", server.getBufferCapacity()); + rs.put("bufferPoolSize", server.getBufferPoolSize()); + rs.put("charset", server.getCharset() == null ? "UTF-8" : server.getCharset().name()); + rs.put("maxbody", server.getMaxbody()); + rs.put("maxconns", server.getMaxconns()); + rs.put("serverStartTime", server.getServerStartTime()); + rs.put("responsePoolSize", server.getResponsePoolSize()); + rs.put("readTimeoutSeconds", server.getReadTimeoutSeconds()); + rs.put("writeTimeoutSeconds", server.getWriteTimeoutSeconds()); + rs.put("createConnectionCount", server.getCreateConnectionCount()); + rs.put("livingConnectionCount", server.getLivingConnectionCount()); + rs.put("closedConnectionCount", server.getClosedConnectionCount()); + return rs; + } +} diff --git a/src/main/java/org/redkale/boot/watch/ServiceWatchService.java b/src/main/java/org/redkale/boot/watch/ServiceWatchService.java index 27fe661a8..4872d0f79 100644 --- a/src/main/java/org/redkale/boot/watch/ServiceWatchService.java +++ b/src/main/java/org/redkale/boot/watch/ServiceWatchService.java @@ -1,199 +1,199 @@ -/* - * 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.boot.watch; - -import java.lang.reflect.*; -import java.util.*; -import javax.annotation.Resource; -import org.redkale.boot.*; -import org.redkale.convert.json.JsonConvert; -import org.redkale.net.http.*; -import org.redkale.service.RetResult; -import org.redkale.util.*; - -/** - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@RestService(name = "service", catalog = "watch", repair = false) -public class ServiceWatchService extends AbstractWatchService { - - @Comment("娌℃湁鎵惧埌鐩爣Service") - public static final int RET_SERVICE_DEST_NOT_EXISTS = 1603_0001; - - @Resource - protected Application application; - - @RestConvert(type = void.class) - @RestMapping(name = "setField", auth = false, comment = "璁剧疆Service涓寚瀹氬瓧娈电殑鍐呭") - public RetResult setField(@RestParam(name = "name", comment = "Service鐨勮祫婧愬悕") String name, - @RestParam(name = "type", comment = "Service鐨勭被鍚") String type, - @RestParam(name = "field", comment = "瀛楁鍚") String field, - @RestParam(name = "value", comment = "瀛楁鍊") String value) { - if (name == null) name = ""; - if (type == null) type = ""; - if (field == null) field = ""; - type = type.trim(); - field = field.trim(); - if (type.isEmpty()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `type`"); - if (field.isEmpty()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `field`"); - Object dest = findService(name, type); - Class clazz = dest.getClass(); - Throwable t = null; - try { - Field fieldObj = null; - do { - try { - fieldObj = clazz.getDeclaredField(field); - break; - } catch (Exception e) { - if (t == null) t = e; - } - } while ((clazz = clazz.getSuperclass()) != Object.class); - if (fieldObj == null) return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + String.valueOf(t) + ")"); - fieldObj.setAccessible(true); - fieldObj.set(dest, JsonConvert.root().convertFrom(fieldObj.getGenericType(), value)); - return RetResult.success(); - } catch (Throwable t2) { - return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + t2.toString() + ")"); - } - } - - @RestConvert(type = void.class) - @RestMapping(name = "getField", auth = false, comment = "鏌ヨService涓寚瀹氬瓧娈电殑鍐呭") - public RetResult getField(@RestParam(name = "name", comment = "Service鐨勮祫婧愬悕") String name, - @RestParam(name = "type", comment = "Service鐨勭被鍚") String type, - @RestParam(name = "field", comment = "瀛楁鍚") String field) { - if (name == null) name = ""; - if (type == null) type = ""; - if (field == null) field = ""; - type = type.trim(); - field = field.trim(); - if (type.isEmpty()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `type`"); - if (field.isEmpty()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `field`"); - Object dest = findService(name, type); - Class clazz = dest.getClass(); - Throwable t = null; - try { - Field fieldObj = null; - do { - try { - fieldObj = clazz.getDeclaredField(field); - break; - } catch (Exception e) { - if (t == null) t = e; - } - } while ((clazz = clazz.getSuperclass()) != Object.class); - if (fieldObj == null) return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + String.valueOf(t) + ")"); - fieldObj.setAccessible(true); - return new RetResult(fieldObj.get(dest)); - } catch (Throwable t2) { - return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + t2.toString() + ")"); - } - } - - @RestConvert(type = void.class) - @RestMapping(name = "runMethod", auth = false, comment = "璋冪敤Service涓寚瀹氭柟娉") - public RetResult runMethod(@RestParam(name = "name", comment = "Service鐨勮祫婧愬悕") String name, - @RestParam(name = "type", comment = "Service鐨勭被鍚") String type, - @RestParam(name = "method", comment = "Service鐨勬柟娉曞悕") String method, - @RestParam(name = "params", comment = "鏂规硶鐨勫弬鏁板") List params, - @RestParam(name = "paramtypes", comment = "鏂规硶鐨勫弬鏁版暟鎹被鍨") List paramtypes) { - if (name == null) name = ""; - if (type == null) type = ""; - if (method == null) method = ""; - type = type.trim(); - method = method.trim(); - if (type.isEmpty()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `type`"); - if (method.isEmpty()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `method`"); - Object dest = findService(name, type); - Class clazz = dest.getClass(); - Throwable t = null; - final int paramcount = params == null ? 0 : params.size(); - if (paramtypes != null && paramcount != paramtypes.size()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "params.size not equals to paramtypes.size"); - try { - Method methodObj = null; - do { - try { - for (Method m : clazz.getDeclaredMethods()) { - if (m.getName().equals(method) && m.getParameterCount() == paramcount) { - boolean flag = true; - if (paramtypes != null) { - Class[] pts = m.getParameterTypes(); - for (int i = 0; i < pts.length; i++) { - if (!pts[i].getName().endsWith(paramtypes.get(i))) { - flag = false; - break; - } - } - } - if (flag) { - methodObj = m; - break; - } - } - } - if (methodObj != null) break; - } catch (Exception e) { - if (t == null) t = e; - } - } while ((clazz = clazz.getSuperclass()) != Object.class); - if (methodObj == null) return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + (t == null ? ("not found method(" + method + ")") : String.valueOf(t)) + ")"); - methodObj.setAccessible(true); - if (paramcount < 1) return new RetResult(methodObj.invoke(dest)); - Object[] paramObjs = new Object[paramcount]; - Type[] pts = methodObj.getGenericParameterTypes(); - for (int i = 0; i < paramObjs.length; i++) { - paramObjs[i] = JsonConvert.root().convertFrom(pts[i], params.get(i)); - } - return new RetResult(methodObj.invoke(dest, paramObjs)); - } catch (Throwable t2) { - return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + t2.toString() + ")"); - } - } - - protected Object findService(String name, String type) { - Object dest = null; - for (NodeServer ns : application.getNodeServers()) { - ResourceFactory resFactory = ns.getResourceFactory(); - List list = resFactory.query((n, s) -> name.equals(n) && s != null && s.getClass().getName().endsWith(type)); - if (list == null || list.isEmpty()) continue; - dest = list.get(0); - } - if (dest == null) return new RetResult(RET_SERVICE_DEST_NOT_EXISTS, "not found servie (name=" + name + ", type=" + type + ")"); - return dest; - } - - @RestMapping(name = "loadService", auth = false, comment = "鍔ㄦ佸鍔燬ervice") - public RetResult loadService(@RestParam(name = "type", comment = "Service鐨勭被鍚") String type, - @RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameReg = "\\.jar$") byte[] jar) { - //寰呭紑鍙 - return RetResult.success(); - } - - @RestMapping(name = "reloadService", auth = false, comment = "閲嶆柊鍔犺浇Service") - public RetResult reloadService(@RestParam(name = "name", comment = "Service鐨勮祫婧愬悕") String name, - @RestParam(name = "type", comment = "Service鐨勭被鍚") String type) { - //寰呭紑鍙 - return RetResult.success(); - } - - @RestMapping(name = "stopService", auth = false, comment = "鍔ㄦ佸仠姝ervice") - public RetResult stopService(@RestParam(name = "name", comment = "Service鐨勮祫婧愬悕") String name, - @RestParam(name = "type", comment = "Service鐨勭被鍚") String type) { - //寰呭紑鍙 - return RetResult.success(); - } - - @RestMapping(name = "findService", auth = false, comment = "鏌ユ壘Service") - public RetResult find(@RestParam(name = "name", comment = "Service鐨勮祫婧愬悕") String name, - @RestParam(name = "type", comment = "Service鐨勭被鍚") String type) { - //寰呭紑鍙 - return RetResult.success(); - } -} +/* + * 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.boot.watch; + +import java.lang.reflect.*; +import java.util.*; +import javax.annotation.Resource; +import org.redkale.boot.*; +import org.redkale.convert.json.JsonConvert; +import org.redkale.net.http.*; +import org.redkale.service.RetResult; +import org.redkale.util.*; + +/** + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@RestService(name = "service", catalog = "watch", repair = false) +public class ServiceWatchService extends AbstractWatchService { + + @Comment("娌℃湁鎵惧埌鐩爣Service") + public static final int RET_SERVICE_DEST_NOT_EXISTS = 1603_0001; + + @Resource + protected Application application; + + @RestConvert(type = void.class) + @RestMapping(name = "setField", auth = false, comment = "璁剧疆Service涓寚瀹氬瓧娈电殑鍐呭") + public RetResult setField(@RestParam(name = "name", comment = "Service鐨勮祫婧愬悕") String name, + @RestParam(name = "type", comment = "Service鐨勭被鍚") String type, + @RestParam(name = "field", comment = "瀛楁鍚") String field, + @RestParam(name = "value", comment = "瀛楁鍊") String value) { + if (name == null) name = ""; + if (type == null) type = ""; + if (field == null) field = ""; + type = type.trim(); + field = field.trim(); + if (type.isEmpty()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `type`"); + if (field.isEmpty()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `field`"); + Object dest = findService(name, type); + Class clazz = dest.getClass(); + Throwable t = null; + try { + Field fieldObj = null; + do { + try { + fieldObj = clazz.getDeclaredField(field); + break; + } catch (Exception e) { + if (t == null) t = e; + } + } while ((clazz = clazz.getSuperclass()) != Object.class); + if (fieldObj == null) return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + String.valueOf(t) + ")"); + fieldObj.setAccessible(true); + fieldObj.set(dest, JsonConvert.root().convertFrom(fieldObj.getGenericType(), value)); + return RetResult.success(); + } catch (Throwable t2) { + return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + t2.toString() + ")"); + } + } + + @RestConvert(type = void.class) + @RestMapping(name = "getField", auth = false, comment = "鏌ヨService涓寚瀹氬瓧娈电殑鍐呭") + public RetResult getField(@RestParam(name = "name", comment = "Service鐨勮祫婧愬悕") String name, + @RestParam(name = "type", comment = "Service鐨勭被鍚") String type, + @RestParam(name = "field", comment = "瀛楁鍚") String field) { + if (name == null) name = ""; + if (type == null) type = ""; + if (field == null) field = ""; + type = type.trim(); + field = field.trim(); + if (type.isEmpty()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `type`"); + if (field.isEmpty()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `field`"); + Object dest = findService(name, type); + Class clazz = dest.getClass(); + Throwable t = null; + try { + Field fieldObj = null; + do { + try { + fieldObj = clazz.getDeclaredField(field); + break; + } catch (Exception e) { + if (t == null) t = e; + } + } while ((clazz = clazz.getSuperclass()) != Object.class); + if (fieldObj == null) return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + String.valueOf(t) + ")"); + fieldObj.setAccessible(true); + return new RetResult(fieldObj.get(dest)); + } catch (Throwable t2) { + return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + t2.toString() + ")"); + } + } + + @RestConvert(type = void.class) + @RestMapping(name = "runMethod", auth = false, comment = "璋冪敤Service涓寚瀹氭柟娉") + public RetResult runMethod(@RestParam(name = "name", comment = "Service鐨勮祫婧愬悕") String name, + @RestParam(name = "type", comment = "Service鐨勭被鍚") String type, + @RestParam(name = "method", comment = "Service鐨勬柟娉曞悕") String method, + @RestParam(name = "params", comment = "鏂规硶鐨勫弬鏁板") List params, + @RestParam(name = "paramtypes", comment = "鏂规硶鐨勫弬鏁版暟鎹被鍨") List paramtypes) { + if (name == null) name = ""; + if (type == null) type = ""; + if (method == null) method = ""; + type = type.trim(); + method = method.trim(); + if (type.isEmpty()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `type`"); + if (method.isEmpty()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `method`"); + Object dest = findService(name, type); + Class clazz = dest.getClass(); + Throwable t = null; + final int paramcount = params == null ? 0 : params.size(); + if (paramtypes != null && paramcount != paramtypes.size()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "params.size not equals to paramtypes.size"); + try { + Method methodObj = null; + do { + try { + for (Method m : clazz.getDeclaredMethods()) { + if (m.getName().equals(method) && m.getParameterCount() == paramcount) { + boolean flag = true; + if (paramtypes != null) { + Class[] pts = m.getParameterTypes(); + for (int i = 0; i < pts.length; i++) { + if (!pts[i].getName().endsWith(paramtypes.get(i))) { + flag = false; + break; + } + } + } + if (flag) { + methodObj = m; + break; + } + } + } + if (methodObj != null) break; + } catch (Exception e) { + if (t == null) t = e; + } + } while ((clazz = clazz.getSuperclass()) != Object.class); + if (methodObj == null) return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + (t == null ? ("not found method(" + method + ")") : String.valueOf(t)) + ")"); + methodObj.setAccessible(true); + if (paramcount < 1) return new RetResult(methodObj.invoke(dest)); + Object[] paramObjs = new Object[paramcount]; + Type[] pts = methodObj.getGenericParameterTypes(); + for (int i = 0; i < paramObjs.length; i++) { + paramObjs[i] = JsonConvert.root().convertFrom(pts[i], params.get(i)); + } + return new RetResult(methodObj.invoke(dest, paramObjs)); + } catch (Throwable t2) { + return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + t2.toString() + ")"); + } + } + + protected Object findService(String name, String type) { + Object dest = null; + for (NodeServer ns : application.getNodeServers()) { + ResourceFactory resFactory = ns.getResourceFactory(); + List list = resFactory.query((n, s) -> name.equals(n) && s != null && s.getClass().getName().endsWith(type)); + if (list == null || list.isEmpty()) continue; + dest = list.get(0); + } + if (dest == null) return new RetResult(RET_SERVICE_DEST_NOT_EXISTS, "not found servie (name=" + name + ", type=" + type + ")"); + return dest; + } + + @RestMapping(name = "loadService", auth = false, comment = "鍔ㄦ佸鍔燬ervice") + public RetResult loadService(@RestParam(name = "type", comment = "Service鐨勭被鍚") String type, + @RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameReg = "\\.jar$") byte[] jar) { + //寰呭紑鍙 + return RetResult.success(); + } + + @RestMapping(name = "reloadService", auth = false, comment = "閲嶆柊鍔犺浇Service") + public RetResult reloadService(@RestParam(name = "name", comment = "Service鐨勮祫婧愬悕") String name, + @RestParam(name = "type", comment = "Service鐨勭被鍚") String type) { + //寰呭紑鍙 + return RetResult.success(); + } + + @RestMapping(name = "stopService", auth = false, comment = "鍔ㄦ佸仠姝ervice") + public RetResult stopService(@RestParam(name = "name", comment = "Service鐨勮祫婧愬悕") String name, + @RestParam(name = "type", comment = "Service鐨勭被鍚") String type) { + //寰呭紑鍙 + return RetResult.success(); + } + + @RestMapping(name = "findService", auth = false, comment = "鏌ユ壘Service") + public RetResult find(@RestParam(name = "name", comment = "Service鐨勮祫婧愬悕") String name, + @RestParam(name = "type", comment = "Service鐨勭被鍚") String type) { + //寰呭紑鍙 + return RetResult.success(); + } +} diff --git a/src/main/java/org/redkale/boot/watch/ServletWatchService.java b/src/main/java/org/redkale/boot/watch/ServletWatchService.java index 53bf28a3b..1b7fa095c 100644 --- a/src/main/java/org/redkale/boot/watch/ServletWatchService.java +++ b/src/main/java/org/redkale/boot/watch/ServletWatchService.java @@ -1,39 +1,39 @@ -/* - * 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.boot.watch; - -import javax.annotation.Resource; -import org.redkale.boot.Application; -import org.redkale.net.TransportFactory; -import org.redkale.net.http.*; - -/** - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@RestService(name = "servlet", catalog = "watch", repair = false) -public class ServletWatchService extends AbstractWatchService { - - @Resource - protected Application application; - - @Resource - protected TransportFactory transportFactory; -// -// @RestMapping(name = "loadServlet", auth = false, comment = "鍔ㄦ佸鍔燬ervlet") -// public RetResult loadServlet(String type, @RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameReg = "\\.jar$") byte[] jar) { -// //寰呭紑鍙 -// return RetResult.success(); -// } -// -// @RestMapping(name = "stopServlet", auth = false, comment = "鍔ㄦ佸仠姝ervlet") -// public RetResult stopServlet(String type) { -// //寰呭紑鍙 -// return RetResult.success(); -// } -} +/* + * 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.boot.watch; + +import javax.annotation.Resource; +import org.redkale.boot.Application; +import org.redkale.net.TransportFactory; +import org.redkale.net.http.*; + +/** + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@RestService(name = "servlet", catalog = "watch", repair = false) +public class ServletWatchService extends AbstractWatchService { + + @Resource + protected Application application; + + @Resource + protected TransportFactory transportFactory; +// +// @RestMapping(name = "loadServlet", auth = false, comment = "鍔ㄦ佸鍔燬ervlet") +// public RetResult loadServlet(String type, @RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameReg = "\\.jar$") byte[] jar) { +// //寰呭紑鍙 +// return RetResult.success(); +// } +// +// @RestMapping(name = "stopServlet", auth = false, comment = "鍔ㄦ佸仠姝ervlet") +// public RetResult stopServlet(String type) { +// //寰呭紑鍙 +// return RetResult.success(); +// } +} diff --git a/src/main/java/org/redkale/boot/watch/TransportWatchService.java b/src/main/java/org/redkale/boot/watch/TransportWatchService.java index 9fad7757c..c849c94ac 100644 --- a/src/main/java/org/redkale/boot/watch/TransportWatchService.java +++ b/src/main/java/org/redkale/boot/watch/TransportWatchService.java @@ -1,140 +1,140 @@ -/* - * 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.boot.watch; - -import java.io.IOException; -import java.net.*; -import java.nio.channels.AsynchronousSocketChannel; -import java.util.List; -import java.util.concurrent.TimeUnit; -import javax.annotation.Resource; -import org.redkale.boot.Application; -import org.redkale.net.*; -import org.redkale.net.http.*; -import org.redkale.net.sncp.*; -import org.redkale.service.*; -import org.redkale.util.*; -import org.redkale.util.AnyValue.DefaultAnyValue; - -/** - * - * @author zhangjx - */ -@RestService(name = "transport", catalog = "watch", repair = false) -public class TransportWatchService extends AbstractWatchService { - - @Comment("涓嶅瓨鍦ㄧ殑Group鑺傜偣") - public static final int RET_TRANSPORT_GROUP_NOT_EXISTS = 1606_0001; - - @Comment("闈炴硶鐨凬ode鑺傜偣IP鍦板潃") - public static final int RET_TRANSPORT_ADDR_ILLEGAL = 1606_0002; - - @Comment("Node鑺傜偣IP鍦板潃宸插瓨鍦") - public static final int RET_TRANSPORT_ADDR_EXISTS = 1606_0003; - - @Resource - protected Application application; - - @Resource - protected TransportFactory transportFactory; - - @RestMapping(name = "listnodes", auth = false, comment = "鑾峰彇鎵鏈塏ode鑺傜偣") - public List listNodes() { - return transportFactory.getGroupInfos(); - } - - @RestMapping(name = "addnode", auth = false, comment = "鍔ㄦ佸鍔犳寚瀹欸roup鐨凬ode鑺傜偣") - public RetResult addNode(@RestParam(name = "group", comment = "Group鑺傜偣鍚") final String group, - @RestParam(name = "addr", comment = "鑺傜偣IP") final String addr, - @RestParam(name = "port", comment = "鑺傜偣绔彛") final int port) throws IOException { - InetSocketAddress address; - try { - address = new InetSocketAddress(addr, port); - AsynchronousSocketChannel channel = AsynchronousSocketChannel.open(); - channel.connect(address).get(2, TimeUnit.SECONDS); //杩炴帴瓒呮椂2绉 - channel.close(); - } catch (Exception e) { - return new RetResult(RET_TRANSPORT_ADDR_ILLEGAL, "InetSocketAddress(addr=" + addr + ", port=" + port + ") is illegal or cannot connect"); - } - if (transportFactory.findGroupName(address) != null) return new RetResult(RET_TRANSPORT_ADDR_ILLEGAL, "InetSocketAddress(addr=" + addr + ", port=" + port + ") is exists"); - synchronized (this) { - if (transportFactory.findGroupInfo(group) == null) { - return new RetResult(RET_TRANSPORT_GROUP_NOT_EXISTS, "not found group (" + group + ")"); - } - transportFactory.addGroupInfo(group, address); - for (Service service : transportFactory.getServices()) { - if (!Sncp.isSncpDyn(service)) continue; - SncpClient client = Sncp.getSncpClient(service); - if (Sncp.isRemote(service)) { - if (client.getRemoteGroups() != null && client.getRemoteGroups().contains(group)) { - client.getRemoteGroupTransport().addRemoteAddresses(address); - } - } - } - DefaultAnyValue node = DefaultAnyValue.create("addr", addr).addValue("port", port); - for (AnyValue groupconf : application.getAppConfig().getAnyValue("resources").getAnyValues("group")) { - if (group.equals(groupconf.getValue("name"))) { - ((DefaultAnyValue) groupconf).addValue("node", node); - break; - } - } - //application.restoreConfig(); - } - return RetResult.success(); - } - - @RestMapping(name = "removenode", auth = false, comment = "鍔ㄦ佸垹闄ゆ寚瀹欸roup鐨凬ode鑺傜偣") - public RetResult removeNode(@RestParam(name = "group", comment = "Group鑺傜偣鍚") final String group, - @RestParam(name = "addr", comment = "鑺傜偣IP") final String addr, - @RestParam(name = "port", comment = "鑺傜偣绔彛") final int port) throws IOException { - if (group == null) return new RetResult(RET_TRANSPORT_GROUP_NOT_EXISTS, "not found group (" + group + ")"); - final InetSocketAddress address = new InetSocketAddress(addr, port); - if (!group.equals(transportFactory.findGroupName(address))) return new RetResult(RET_TRANSPORT_ADDR_ILLEGAL, "InetSocketAddress(addr=" + addr + ", port=" + port + ") not belong to group(" + group + ")"); - synchronized (this) { - if (transportFactory.findGroupInfo(group) == null) { - return new RetResult(RET_TRANSPORT_GROUP_NOT_EXISTS, "not found group (" + group + ")"); - } - transportFactory.removeGroupInfo(group, address); - for (Service service : transportFactory.getServices()) { - if (!Sncp.isSncpDyn(service)) continue; - SncpClient client = Sncp.getSncpClient(service); - if (Sncp.isRemote(service)) { - if (client.getRemoteGroups() != null && client.getRemoteGroups().contains(group)) { - client.getRemoteGroupTransport().removeRemoteAddresses(address); - } - } - } - for (AnyValue groupconf : application.getAppConfig().getAnyValue("resources").getAnyValues("group")) { - if (group.equals(groupconf.getValue("name"))) { - ((DefaultAnyValue) groupconf).removeValue("node", DefaultAnyValue.create("addr", addr).addValue("port", port)); - break; - } - } - //application.restoreConfig(); - } - return RetResult.success(); - } - - @RestMapping(name = "test1", auth = false, comment = "棰勭暀") - public RetResult test1() { - return RetResult.success(); - } - - @RestMapping(name = "test2", auth = false, comment = "棰勭暀") - public RetResult test2() { - return RetResult.success(); - } - - @RestMapping(name = "test3", auth = false, comment = "棰勭暀") - public RetResult test3() { - return RetResult.success(); - } - - @RestMapping(name = "test4", auth = false, comment = "棰勭暀") - public RetResult test4() { - return RetResult.success(); - } -} +/* + * 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.boot.watch; + +import java.io.IOException; +import java.net.*; +import java.nio.channels.AsynchronousSocketChannel; +import java.util.List; +import java.util.concurrent.TimeUnit; +import javax.annotation.Resource; +import org.redkale.boot.Application; +import org.redkale.net.*; +import org.redkale.net.http.*; +import org.redkale.net.sncp.*; +import org.redkale.service.*; +import org.redkale.util.*; +import org.redkale.util.AnyValue.DefaultAnyValue; + +/** + * + * @author zhangjx + */ +@RestService(name = "transport", catalog = "watch", repair = false) +public class TransportWatchService extends AbstractWatchService { + + @Comment("涓嶅瓨鍦ㄧ殑Group鑺傜偣") + public static final int RET_TRANSPORT_GROUP_NOT_EXISTS = 1606_0001; + + @Comment("闈炴硶鐨凬ode鑺傜偣IP鍦板潃") + public static final int RET_TRANSPORT_ADDR_ILLEGAL = 1606_0002; + + @Comment("Node鑺傜偣IP鍦板潃宸插瓨鍦") + public static final int RET_TRANSPORT_ADDR_EXISTS = 1606_0003; + + @Resource + protected Application application; + + @Resource + protected TransportFactory transportFactory; + + @RestMapping(name = "listnodes", auth = false, comment = "鑾峰彇鎵鏈塏ode鑺傜偣") + public List listNodes() { + return transportFactory.getGroupInfos(); + } + + @RestMapping(name = "addnode", auth = false, comment = "鍔ㄦ佸鍔犳寚瀹欸roup鐨凬ode鑺傜偣") + public RetResult addNode(@RestParam(name = "group", comment = "Group鑺傜偣鍚") final String group, + @RestParam(name = "addr", comment = "鑺傜偣IP") final String addr, + @RestParam(name = "port", comment = "鑺傜偣绔彛") final int port) throws IOException { + InetSocketAddress address; + try { + address = new InetSocketAddress(addr, port); + AsynchronousSocketChannel channel = AsynchronousSocketChannel.open(); + channel.connect(address).get(2, TimeUnit.SECONDS); //杩炴帴瓒呮椂2绉 + channel.close(); + } catch (Exception e) { + return new RetResult(RET_TRANSPORT_ADDR_ILLEGAL, "InetSocketAddress(addr=" + addr + ", port=" + port + ") is illegal or cannot connect"); + } + if (transportFactory.findGroupName(address) != null) return new RetResult(RET_TRANSPORT_ADDR_ILLEGAL, "InetSocketAddress(addr=" + addr + ", port=" + port + ") is exists"); + synchronized (this) { + if (transportFactory.findGroupInfo(group) == null) { + return new RetResult(RET_TRANSPORT_GROUP_NOT_EXISTS, "not found group (" + group + ")"); + } + transportFactory.addGroupInfo(group, address); + for (Service service : transportFactory.getServices()) { + if (!Sncp.isSncpDyn(service)) continue; + SncpClient client = Sncp.getSncpClient(service); + if (Sncp.isRemote(service)) { + if (client.getRemoteGroups() != null && client.getRemoteGroups().contains(group)) { + client.getRemoteGroupTransport().addRemoteAddresses(address); + } + } + } + DefaultAnyValue node = DefaultAnyValue.create("addr", addr).addValue("port", port); + for (AnyValue groupconf : application.getAppConfig().getAnyValue("resources").getAnyValues("group")) { + if (group.equals(groupconf.getValue("name"))) { + ((DefaultAnyValue) groupconf).addValue("node", node); + break; + } + } + //application.restoreConfig(); + } + return RetResult.success(); + } + + @RestMapping(name = "removenode", auth = false, comment = "鍔ㄦ佸垹闄ゆ寚瀹欸roup鐨凬ode鑺傜偣") + public RetResult removeNode(@RestParam(name = "group", comment = "Group鑺傜偣鍚") final String group, + @RestParam(name = "addr", comment = "鑺傜偣IP") final String addr, + @RestParam(name = "port", comment = "鑺傜偣绔彛") final int port) throws IOException { + if (group == null) return new RetResult(RET_TRANSPORT_GROUP_NOT_EXISTS, "not found group (" + group + ")"); + final InetSocketAddress address = new InetSocketAddress(addr, port); + if (!group.equals(transportFactory.findGroupName(address))) return new RetResult(RET_TRANSPORT_ADDR_ILLEGAL, "InetSocketAddress(addr=" + addr + ", port=" + port + ") not belong to group(" + group + ")"); + synchronized (this) { + if (transportFactory.findGroupInfo(group) == null) { + return new RetResult(RET_TRANSPORT_GROUP_NOT_EXISTS, "not found group (" + group + ")"); + } + transportFactory.removeGroupInfo(group, address); + for (Service service : transportFactory.getServices()) { + if (!Sncp.isSncpDyn(service)) continue; + SncpClient client = Sncp.getSncpClient(service); + if (Sncp.isRemote(service)) { + if (client.getRemoteGroups() != null && client.getRemoteGroups().contains(group)) { + client.getRemoteGroupTransport().removeRemoteAddresses(address); + } + } + } + for (AnyValue groupconf : application.getAppConfig().getAnyValue("resources").getAnyValues("group")) { + if (group.equals(groupconf.getValue("name"))) { + ((DefaultAnyValue) groupconf).removeValue("node", DefaultAnyValue.create("addr", addr).addValue("port", port)); + break; + } + } + //application.restoreConfig(); + } + return RetResult.success(); + } + + @RestMapping(name = "test1", auth = false, comment = "棰勭暀") + public RetResult test1() { + return RetResult.success(); + } + + @RestMapping(name = "test2", auth = false, comment = "棰勭暀") + public RetResult test2() { + return RetResult.success(); + } + + @RestMapping(name = "test3", auth = false, comment = "棰勭暀") + public RetResult test3() { + return RetResult.success(); + } + + @RestMapping(name = "test4", auth = false, comment = "棰勭暀") + public RetResult test4() { + return RetResult.success(); + } +} diff --git a/src/main/java/org/redkale/cluster/CacheClusterAgent.java b/src/main/java/org/redkale/cluster/CacheClusterAgent.java index aafdc0ae3..9dcc2bfb9 100644 --- a/src/main/java/org/redkale/cluster/CacheClusterAgent.java +++ b/src/main/java/org/redkale/cluster/CacheClusterAgent.java @@ -1,327 +1,327 @@ -/* - * 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.cluster; - -import java.net.*; -import java.util.*; -import java.util.concurrent.*; -import java.util.logging.Level; -import javax.annotation.Resource; -import org.redkale.boot.*; -import org.redkale.convert.json.JsonConvert; -import org.redkale.service.Service; -import org.redkale.source.CacheSource; -import org.redkale.util.*; - -/** - * 浣跨敤CacheSource瀹炵幇鐨勭涓夋柟鏈嶅姟鍙戠幇绠$悊鎺ュ彛cluster - * - * - * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * - * @since 2.3.0 - */ -public class CacheClusterAgent extends ClusterAgent implements Resourcable { - - @Resource(name = "$") - private CacheSource source; - - private String sourceName; - - protected int ttls = 10; //瀹氭椂妫鏌ョ殑绉掓暟 - - protected ScheduledThreadPoolExecutor scheduler; - - //鍙兘琚獺ttpMessageClient鐢ㄥ埌鐨勬湇鍔 key: servicename - protected final ConcurrentHashMap> httpAddressMap = new ConcurrentHashMap<>(); - - //鍙兘琚玬qtp鐢ㄥ埌鐨勬湇鍔 key: servicename - protected final ConcurrentHashMap> mqtpAddressMap = new ConcurrentHashMap<>(); - - @Override - public void init(AnyValue config) { - super.init(config); - this.sourceName = getSourceName(); - - AnyValue[] properties = config.getAnyValues("property"); - for (AnyValue property : properties) { - if ("ttls".equalsIgnoreCase(property.getValue("name"))) { - this.ttls = Integer.parseInt(property.getValue("value", "").trim()); - if (this.ttls < 5) this.ttls = 10; - } - } - } - - @Override - public void destroy(AnyValue config) { - if (scheduler != null) scheduler.shutdownNow(); - } - - public String getSourceName() { - AnyValue[] properties = config.getAnyValues("property"); - for (AnyValue property : properties) { - if ("source".equalsIgnoreCase(property.getValue("name")) - && property.getValue("value") != null) { - this.sourceName = property.getValue("value"); - return this.sourceName; - } - } - return null; - } - - @Override - public String resourceName() { - return sourceName; - } - - @Override //ServiceLoader鏃跺垽鏂厤缃槸鍚︾鍚堝綋鍓嶅疄鐜扮被 - public boolean acceptsConf(AnyValue config) { - if (config == null) return false; - AnyValue[] properties = config.getAnyValues("property"); - if (properties == null || properties.length == 0) return false; - for (AnyValue property : properties) { - if ("source".equalsIgnoreCase(property.getValue("name")) - && property.getValue("value") != null) return true; - } - return false; - } - - @Override - public void start() { - if (this.scheduler == null) { - this.scheduler = new ScheduledThreadPoolExecutor(4, (Runnable r) -> { - final Thread t = new Thread(r, "Redkale-" + CacheClusterAgent.class.getSimpleName() + "-Task-Thread"); - t.setDaemon(true); - return t; - }); - - this.scheduler.scheduleAtFixedRate(() -> { - try { - checkApplicationHealth(); - checkHttpAddressHealth(); - loadMqtpAddressHealth(); - localEntrys.values().stream().filter(e -> !e.canceled).forEach(entry -> { - checkLocalHealth(entry); - }); - remoteEntrys.values().stream().filter(entry -> "SNCP".equalsIgnoreCase(entry.protocol)).forEach(entry -> { - updateSncpTransport(entry); - }); - } catch (Exception e) { - logger.log(Level.SEVERE, "scheduleAtFixedRate check error", e); - } - }, Math.max(2000, ttls * 1000), Math.max(2000, ttls * 1000), TimeUnit.MILLISECONDS); - } - } - - protected void loadMqtpAddressHealth() { - List keys = source.queryKeysStartsWith("cluster.mqtp:"); - keys.forEach(servicename -> { - try { - this.mqtpAddressMap.put(servicename, queryAddress(servicename).get(3, TimeUnit.SECONDS)); - } catch (Exception e) { - logger.log(Level.SEVERE, "loadMqtpAddressHealth check " + servicename + " error", e); - } - }); - } - - protected void checkHttpAddressHealth() { - try { - this.httpAddressMap.keySet().stream().forEach(servicename -> { - try { - this.httpAddressMap.put(servicename, queryAddress(servicename).get(3, TimeUnit.SECONDS)); - } catch (Exception e) { - logger.log(Level.SEVERE, "checkHttpAddressHealth check " + servicename + " error", e); - } - }); - } catch (Exception ex) { - logger.log(Level.SEVERE, "checkHttpAddressHealth check error", ex); - } - } - - protected void checkLocalHealth(final ClusterEntry entry) { - AddressEntry newaddr = new AddressEntry(); - newaddr.addr = entry.address; - newaddr.nodeid = this.nodeid; - newaddr.time = System.currentTimeMillis(); - source.hset(entry.checkname, entry.checkid, AddressEntry.class, newaddr); - } - - @Override //鑾峰彇MQTP鐨凥TTP杩滅▼鏈嶅姟鐨勫彲鐢╥p鍒楄〃, key = servicename鐨勫悗鍗婃 - public CompletableFuture>> queryMqtpAddress(String protocol, String module, String resname) { - final Map> rsmap = new ConcurrentHashMap<>(); - final String servicenamprefix = generateHttpServiceName(protocol, module, null) + ":"; - mqtpAddressMap.keySet().stream().filter(k -> k.startsWith(servicenamprefix)) - .forEach(sn -> rsmap.put(sn.substring(servicenamprefix.length()), mqtpAddressMap.get(sn))); - return CompletableFuture.completedFuture(rsmap); - } - - @Override //鑾峰彇HTTP杩滅▼鏈嶅姟鐨勫彲鐢╥p鍒楄〃 - public CompletableFuture> queryHttpAddress(String protocol, String module, String resname) { - final String servicename = generateHttpServiceName(protocol, module, resname); - Collection rs = httpAddressMap.get(servicename); - if (rs != null) return CompletableFuture.completedFuture(rs); - return queryAddress(servicename).thenApply(t -> { - httpAddressMap.put(servicename, t); - return t; - }); - } - - @Override - protected CompletableFuture> queryAddress(final ClusterEntry entry) { - return queryAddress(entry.servicename); - } - - private CompletableFuture> queryAddress(final String servicename) { - final CompletableFuture> future = source.hmapAsync(servicename, AddressEntry.class, 0, 10000); - return future.thenApply(map -> { - final Set set = new HashSet<>(); - map.forEach((n, v) -> { - if (v != null && (System.currentTimeMillis() - v.time) / 1000 < ttls) set.add(v.addr); - }); - return set; - }); - } - - protected boolean isApplicationHealth() { - String servicename = generateApplicationServiceName(); - String serviceid = generateApplicationServiceId(); - AddressEntry entry = (AddressEntry) source.hget(servicename, serviceid, AddressEntry.class); - return entry != null && (System.currentTimeMillis() - entry.time) / 1000 < ttls; - } - - protected void checkApplicationHealth() { - String checkname = generateApplicationServiceName(); - String checkid = generateApplicationCheckId(); - AddressEntry entry = new AddressEntry(); - entry.addr = this.appAddress; - entry.nodeid = this.nodeid; - entry.time = System.currentTimeMillis(); - source.hset(checkname, checkid, AddressEntry.class, entry); - } - - @Override - public void register(Application application) { - if (isApplicationHealth()) throw new RuntimeException("application.nodeid=" + nodeid + " exists in cluster"); - deregister(application); - - String serviceid = generateApplicationServiceId(); - String servicename = generateApplicationServiceName(); - AddressEntry entry = new AddressEntry(); - entry.addr = this.appAddress; - entry.nodeid = this.nodeid; - entry.time = System.currentTimeMillis(); - source.hset(servicename, serviceid, AddressEntry.class, entry); - } - - @Override - public void deregister(Application application) { - String servicename = generateApplicationServiceName(); - source.remove(servicename); - } - - @Override - protected ClusterEntry register(NodeServer ns, String protocol, Service service) { - deregister(ns, protocol, service, false); - // - ClusterEntry clusterEntry = new ClusterEntry(ns, protocol, service); - AddressEntry entry = new AddressEntry(); - entry.addr = clusterEntry.address; - entry.nodeid = this.nodeid; - entry.time = System.currentTimeMillis(); - source.hset(clusterEntry.servicename, clusterEntry.serviceid, AddressEntry.class, entry); - return clusterEntry; - } - - @Override - protected void deregister(NodeServer ns, String protocol, Service service) { - deregister(ns, protocol, service, true); - } - - protected void deregister(NodeServer ns, String protocol, Service service, boolean realcanceled) { - String servicename = generateServiceName(ns, protocol, service); - String serviceid = generateServiceId(ns, protocol, service); - ClusterEntry currEntry = null; - for (final ClusterEntry entry : localEntrys.values()) { - if (entry.servicename.equals(servicename) && entry.serviceid.equals(serviceid)) { - currEntry = entry; - break; - } - } - if (currEntry == null) { - for (final ClusterEntry entry : remoteEntrys.values()) { - if (entry.servicename.equals(servicename) && entry.serviceid.equals(serviceid)) { - currEntry = entry; - break; - } - } - } - source.hremove(servicename, serviceid); - if (realcanceled && currEntry != null) currEntry.canceled = true; - if (!"mqtp".equals(protocol) && currEntry != null && currEntry.submqtp) { - deregister(ns, "mqtp", service, realcanceled); - } - } - - @Override - protected String generateApplicationServiceName() { - return "cluster." + super.generateApplicationServiceName(); - } - - @Override - protected String generateServiceName(NodeServer ns, String protocol, Service service) { - return "cluster." + super.generateServiceName(ns, protocol, service); - } - - @Override - public String generateHttpServiceName(String protocol, String module, String resname) { - return "cluster." + super.generateHttpServiceName(protocol, module, resname); - } - - @Override - protected String generateApplicationCheckName() { - return generateApplicationServiceName(); - } - - @Override - protected String generateApplicationCheckId() { - return generateApplicationServiceId(); - } - - @Override - protected String generateCheckName(NodeServer ns, String protocol, Service service) { - return generateServiceName(ns, protocol, service); - } - - @Override - protected String generateCheckId(NodeServer ns, String protocol, Service service) { - return generateServiceId(ns, protocol, service); - } - - public static class AddressEntry { - - public InetSocketAddress addr; - - public int nodeid; - - public long time; - - public AddressEntry() { - } - - public AddressEntry refresh() { - this.time = System.currentTimeMillis(); - return this; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - } - -} +/* + * 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.cluster; + +import java.net.*; +import java.util.*; +import java.util.concurrent.*; +import java.util.logging.Level; +import javax.annotation.Resource; +import org.redkale.boot.*; +import org.redkale.convert.json.JsonConvert; +import org.redkale.service.Service; +import org.redkale.source.CacheSource; +import org.redkale.util.*; + +/** + * 浣跨敤CacheSource瀹炵幇鐨勭涓夋柟鏈嶅姟鍙戠幇绠$悊鎺ュ彛cluster + * + * + * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.3.0 + */ +public class CacheClusterAgent extends ClusterAgent implements Resourcable { + + @Resource(name = "$") + private CacheSource source; + + private String sourceName; + + protected int ttls = 10; //瀹氭椂妫鏌ョ殑绉掓暟 + + protected ScheduledThreadPoolExecutor scheduler; + + //鍙兘琚獺ttpMessageClient鐢ㄥ埌鐨勬湇鍔 key: servicename + protected final ConcurrentHashMap> httpAddressMap = new ConcurrentHashMap<>(); + + //鍙兘琚玬qtp鐢ㄥ埌鐨勬湇鍔 key: servicename + protected final ConcurrentHashMap> mqtpAddressMap = new ConcurrentHashMap<>(); + + @Override + public void init(AnyValue config) { + super.init(config); + this.sourceName = getSourceName(); + + AnyValue[] properties = config.getAnyValues("property"); + for (AnyValue property : properties) { + if ("ttls".equalsIgnoreCase(property.getValue("name"))) { + this.ttls = Integer.parseInt(property.getValue("value", "").trim()); + if (this.ttls < 5) this.ttls = 10; + } + } + } + + @Override + public void destroy(AnyValue config) { + if (scheduler != null) scheduler.shutdownNow(); + } + + public String getSourceName() { + AnyValue[] properties = config.getAnyValues("property"); + for (AnyValue property : properties) { + if ("source".equalsIgnoreCase(property.getValue("name")) + && property.getValue("value") != null) { + this.sourceName = property.getValue("value"); + return this.sourceName; + } + } + return null; + } + + @Override + public String resourceName() { + return sourceName; + } + + @Override //ServiceLoader鏃跺垽鏂厤缃槸鍚︾鍚堝綋鍓嶅疄鐜扮被 + public boolean acceptsConf(AnyValue config) { + if (config == null) return false; + AnyValue[] properties = config.getAnyValues("property"); + if (properties == null || properties.length == 0) return false; + for (AnyValue property : properties) { + if ("source".equalsIgnoreCase(property.getValue("name")) + && property.getValue("value") != null) return true; + } + return false; + } + + @Override + public void start() { + if (this.scheduler == null) { + this.scheduler = new ScheduledThreadPoolExecutor(4, (Runnable r) -> { + final Thread t = new Thread(r, "Redkale-" + CacheClusterAgent.class.getSimpleName() + "-Task-Thread"); + t.setDaemon(true); + return t; + }); + + this.scheduler.scheduleAtFixedRate(() -> { + try { + checkApplicationHealth(); + checkHttpAddressHealth(); + loadMqtpAddressHealth(); + localEntrys.values().stream().filter(e -> !e.canceled).forEach(entry -> { + checkLocalHealth(entry); + }); + remoteEntrys.values().stream().filter(entry -> "SNCP".equalsIgnoreCase(entry.protocol)).forEach(entry -> { + updateSncpTransport(entry); + }); + } catch (Exception e) { + logger.log(Level.SEVERE, "scheduleAtFixedRate check error", e); + } + }, Math.max(2000, ttls * 1000), Math.max(2000, ttls * 1000), TimeUnit.MILLISECONDS); + } + } + + protected void loadMqtpAddressHealth() { + List keys = source.queryKeysStartsWith("cluster.mqtp:"); + keys.forEach(servicename -> { + try { + this.mqtpAddressMap.put(servicename, queryAddress(servicename).get(3, TimeUnit.SECONDS)); + } catch (Exception e) { + logger.log(Level.SEVERE, "loadMqtpAddressHealth check " + servicename + " error", e); + } + }); + } + + protected void checkHttpAddressHealth() { + try { + this.httpAddressMap.keySet().stream().forEach(servicename -> { + try { + this.httpAddressMap.put(servicename, queryAddress(servicename).get(3, TimeUnit.SECONDS)); + } catch (Exception e) { + logger.log(Level.SEVERE, "checkHttpAddressHealth check " + servicename + " error", e); + } + }); + } catch (Exception ex) { + logger.log(Level.SEVERE, "checkHttpAddressHealth check error", ex); + } + } + + protected void checkLocalHealth(final ClusterEntry entry) { + AddressEntry newaddr = new AddressEntry(); + newaddr.addr = entry.address; + newaddr.nodeid = this.nodeid; + newaddr.time = System.currentTimeMillis(); + source.hset(entry.checkname, entry.checkid, AddressEntry.class, newaddr); + } + + @Override //鑾峰彇MQTP鐨凥TTP杩滅▼鏈嶅姟鐨勫彲鐢╥p鍒楄〃, key = servicename鐨勫悗鍗婃 + public CompletableFuture>> queryMqtpAddress(String protocol, String module, String resname) { + final Map> rsmap = new ConcurrentHashMap<>(); + final String servicenamprefix = generateHttpServiceName(protocol, module, null) + ":"; + mqtpAddressMap.keySet().stream().filter(k -> k.startsWith(servicenamprefix)) + .forEach(sn -> rsmap.put(sn.substring(servicenamprefix.length()), mqtpAddressMap.get(sn))); + return CompletableFuture.completedFuture(rsmap); + } + + @Override //鑾峰彇HTTP杩滅▼鏈嶅姟鐨勫彲鐢╥p鍒楄〃 + public CompletableFuture> queryHttpAddress(String protocol, String module, String resname) { + final String servicename = generateHttpServiceName(protocol, module, resname); + Collection rs = httpAddressMap.get(servicename); + if (rs != null) return CompletableFuture.completedFuture(rs); + return queryAddress(servicename).thenApply(t -> { + httpAddressMap.put(servicename, t); + return t; + }); + } + + @Override + protected CompletableFuture> queryAddress(final ClusterEntry entry) { + return queryAddress(entry.servicename); + } + + private CompletableFuture> queryAddress(final String servicename) { + final CompletableFuture> future = source.hmapAsync(servicename, AddressEntry.class, 0, 10000); + return future.thenApply(map -> { + final Set set = new HashSet<>(); + map.forEach((n, v) -> { + if (v != null && (System.currentTimeMillis() - v.time) / 1000 < ttls) set.add(v.addr); + }); + return set; + }); + } + + protected boolean isApplicationHealth() { + String servicename = generateApplicationServiceName(); + String serviceid = generateApplicationServiceId(); + AddressEntry entry = (AddressEntry) source.hget(servicename, serviceid, AddressEntry.class); + return entry != null && (System.currentTimeMillis() - entry.time) / 1000 < ttls; + } + + protected void checkApplicationHealth() { + String checkname = generateApplicationServiceName(); + String checkid = generateApplicationCheckId(); + AddressEntry entry = new AddressEntry(); + entry.addr = this.appAddress; + entry.nodeid = this.nodeid; + entry.time = System.currentTimeMillis(); + source.hset(checkname, checkid, AddressEntry.class, entry); + } + + @Override + public void register(Application application) { + if (isApplicationHealth()) throw new RuntimeException("application.nodeid=" + nodeid + " exists in cluster"); + deregister(application); + + String serviceid = generateApplicationServiceId(); + String servicename = generateApplicationServiceName(); + AddressEntry entry = new AddressEntry(); + entry.addr = this.appAddress; + entry.nodeid = this.nodeid; + entry.time = System.currentTimeMillis(); + source.hset(servicename, serviceid, AddressEntry.class, entry); + } + + @Override + public void deregister(Application application) { + String servicename = generateApplicationServiceName(); + source.remove(servicename); + } + + @Override + protected ClusterEntry register(NodeServer ns, String protocol, Service service) { + deregister(ns, protocol, service, false); + // + ClusterEntry clusterEntry = new ClusterEntry(ns, protocol, service); + AddressEntry entry = new AddressEntry(); + entry.addr = clusterEntry.address; + entry.nodeid = this.nodeid; + entry.time = System.currentTimeMillis(); + source.hset(clusterEntry.servicename, clusterEntry.serviceid, AddressEntry.class, entry); + return clusterEntry; + } + + @Override + protected void deregister(NodeServer ns, String protocol, Service service) { + deregister(ns, protocol, service, true); + } + + protected void deregister(NodeServer ns, String protocol, Service service, boolean realcanceled) { + String servicename = generateServiceName(ns, protocol, service); + String serviceid = generateServiceId(ns, protocol, service); + ClusterEntry currEntry = null; + for (final ClusterEntry entry : localEntrys.values()) { + if (entry.servicename.equals(servicename) && entry.serviceid.equals(serviceid)) { + currEntry = entry; + break; + } + } + if (currEntry == null) { + for (final ClusterEntry entry : remoteEntrys.values()) { + if (entry.servicename.equals(servicename) && entry.serviceid.equals(serviceid)) { + currEntry = entry; + break; + } + } + } + source.hremove(servicename, serviceid); + if (realcanceled && currEntry != null) currEntry.canceled = true; + if (!"mqtp".equals(protocol) && currEntry != null && currEntry.submqtp) { + deregister(ns, "mqtp", service, realcanceled); + } + } + + @Override + protected String generateApplicationServiceName() { + return "cluster." + super.generateApplicationServiceName(); + } + + @Override + protected String generateServiceName(NodeServer ns, String protocol, Service service) { + return "cluster." + super.generateServiceName(ns, protocol, service); + } + + @Override + public String generateHttpServiceName(String protocol, String module, String resname) { + return "cluster." + super.generateHttpServiceName(protocol, module, resname); + } + + @Override + protected String generateApplicationCheckName() { + return generateApplicationServiceName(); + } + + @Override + protected String generateApplicationCheckId() { + return generateApplicationServiceId(); + } + + @Override + protected String generateCheckName(NodeServer ns, String protocol, Service service) { + return generateServiceName(ns, protocol, service); + } + + @Override + protected String generateCheckId(NodeServer ns, String protocol, Service service) { + return generateServiceId(ns, protocol, service); + } + + public static class AddressEntry { + + public InetSocketAddress addr; + + public int nodeid; + + public long time; + + public AddressEntry() { + } + + public AddressEntry refresh() { + this.time = System.currentTimeMillis(); + return this; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + } + +} diff --git a/src/main/java/org/redkale/cluster/ClusterAgent.java b/src/main/java/org/redkale/cluster/ClusterAgent.java index 16991c165..d1af825d3 100644 --- a/src/main/java/org/redkale/cluster/ClusterAgent.java +++ b/src/main/java/org/redkale/cluster/ClusterAgent.java @@ -1,342 +1,342 @@ -/* - * 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.cluster; - -import java.lang.ref.WeakReference; -import java.net.InetSocketAddress; -import java.util.*; -import java.util.concurrent.*; -import java.util.logging.Logger; -import javax.annotation.Resource; -import org.redkale.boot.*; -import static org.redkale.boot.Application.*; -import org.redkale.convert.json.JsonConvert; -import org.redkale.mq.MessageMultiConsumer; -import org.redkale.net.*; -import org.redkale.net.http.*; -import org.redkale.net.sncp.*; -import org.redkale.service.*; -import org.redkale.util.*; - -/** - * 绗笁鏂规湇鍔″彂鐜扮鐞嗘帴鍙luster - * - * - * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * - * @since 2.1.0 - */ -public abstract class ClusterAgent { - - protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); - - @Resource(name = RESNAME_APP_NODEID) - protected int nodeid; - - @Resource(name = RESNAME_APP_NAME) - protected String appName = ""; - - @Resource(name = RESNAME_APP_ADDR) - protected InetSocketAddress appAddress; - - protected String name; - - protected boolean waits; - - protected String[] protocols; //蹇呴』鍏ㄥぇ鍐 - - protected int[] ports; - - protected AnyValue config; - - protected TransportFactory transportFactory; - - protected final ConcurrentHashMap localEntrys = new ConcurrentHashMap<>(); - - protected final ConcurrentHashMap remoteEntrys = new ConcurrentHashMap<>(); - - public void init(AnyValue config) { - this.config = config; - this.name = config.getValue("name", ""); - this.waits = config.getBoolValue("waits", false); - { - String ps = config.getValue("protocols", "").toUpperCase(); - if (ps == null || ps.isEmpty()) ps = "SNCP;HTTP"; - this.protocols = ps.split(";"); - } - String ts = config.getValue("ports", ""); - if (ts != null && !ts.isEmpty()) { - String[] its = ts.split(";"); - List list = new ArrayList<>(); - for (String str : its) { - if (str.trim().isEmpty()) continue; - list.add(Integer.parseInt(str.trim())); - } - if (!list.isEmpty()) this.ports = list.stream().mapToInt(x -> x).toArray(); - } - } - - public void destroy(AnyValue config) { - } - - //ServiceLoader鏃跺垽鏂厤缃槸鍚︾鍚堝綋鍓嶅疄鐜扮被 - public abstract boolean acceptsConf(AnyValue config); - - public boolean containsProtocol(String protocol) { - if (protocol == null || protocol.isEmpty()) return false; - return protocols == null || Utility.contains(protocols, protocol.toUpperCase()); - } - - public boolean containsPort(int port) { - if (ports == null || ports.length == 0) return true; - return Utility.contains(ports, port); - } - - public abstract void register(Application application); - - public abstract void deregister(Application application); - - //娉ㄥ唽鏈嶅姟, 鍦∟odeService璋冪敤Service.init鏂规硶涔嬪墠璋冪敤 - public void register(NodeServer ns, String protocol, Set localServices, Set remoteServices) { - if (localServices.isEmpty()) return; - //娉ㄥ唽鏈湴妯″紡 - for (Service service : localServices) { - if (!canRegister(protocol, service)) continue; - ClusterEntry htentry = register(ns, protocol, service); - localEntrys.put(htentry.serviceid, htentry); - if (protocol.toLowerCase().startsWith("http")) { - MessageMultiConsumer mmc = service.getClass().getAnnotation(MessageMultiConsumer.class); - if (mmc != null) { - ClusterEntry mqentry = register(ns, "mqtp", service); - localEntrys.put(mqentry.serviceid, mqentry); - htentry.submqtp = true; - } - } - } - //杩滅▼妯″紡鍔犺浇IP鍒楄〃, 鍙敮鎸丼NCP鍗忚 - if (ns.isSNCP()) { - for (Service service : remoteServices) { - ClusterEntry entry = new ClusterEntry(ns, protocol, service); - updateSncpTransport(entry); - remoteEntrys.put(entry.serviceid, entry); - } - } - } - - //娉ㄩ攢鏈嶅姟, 鍦∟odeService璋冪敤Service.destroy 鏂规硶涔嬪墠璋冪敤 - public void deregister(NodeServer ns, String protocol, Set localServices, Set remoteServices) { - //娉ㄩ攢鏈湴妯″紡 杩滅▼妯″紡涓嶆敞鍐 - for (Service service : localServices) { - if (!canRegister(protocol, service)) continue; - deregister(ns, protocol, service); - } - afterDeregister(ns, protocol); - } - - protected boolean canRegister(String protocol, Service service) { - if ("SNCP".equalsIgnoreCase(protocol) && service.getClass().getAnnotation(Local.class) != null) return false; - AutoLoad al = service.getClass().getAnnotation(AutoLoad.class); - if (al != null && !al.value() && service.getClass().getAnnotation(Local.class) != null) return false; - if (service instanceof WebSocketNode) { - if (((WebSocketNode) service).getLocalWebSocketEngine() == null) return false; - } - return true; - } - - public void start() { - } - - protected void afterDeregister(NodeServer ns, String protocol) { - if (!this.waits) return; - int s = intervalCheckSeconds(); - if (s > 0) { //鏆傚仠锛屽讥琛ュ叾浠栦緷璧栨湰杩涚▼鏈嶅姟鐨勫懆鏈熷亸宸 - try { - Thread.sleep(s * 1000); - } catch (InterruptedException ex) { - } - logger.info(this.getClass().getSimpleName() + " wait for " + s * 1000 + "ms after deregister"); - } - } - - public int intervalCheckSeconds() { - return 10; - } - - //鑾峰彇MQTP鐨凥TTP杩滅▼鏈嶅姟鐨勫彲鐢╥p鍒楄〃, key = servicename鐨勫悗鍗婃 - public abstract CompletableFuture>> queryMqtpAddress(String protocol, String module, String resname); - - //鑾峰彇HTTP杩滅▼鏈嶅姟鐨勫彲鐢╥p鍒楄〃 - public abstract CompletableFuture> queryHttpAddress(String protocol, String module, String resname); - - //鑾峰彇杩滅▼鏈嶅姟鐨勫彲鐢╥p鍒楄〃 - protected abstract CompletableFuture> queryAddress(ClusterEntry entry); - - //娉ㄥ唽鏈嶅姟 - protected abstract ClusterEntry register(NodeServer ns, String protocol, Service service); - - //娉ㄩ攢鏈嶅姟 - protected abstract void deregister(NodeServer ns, String protocol, Service service); - - //鏍煎紡: protocol:classtype-resourcename - protected void updateSncpTransport(ClusterEntry entry) { - Service service = entry.serviceref.get(); - if (service == null) return; - Collection addrs = ClusterAgent.this.queryAddress(entry).join(); - Sncp.updateTransport(service, transportFactory, Sncp.getResourceType(service).getName() + "-" + Sncp.getResourceName(service), entry.netprotocol, entry.address, null, addrs); - } - - protected String generateApplicationServiceName() { - return "application" + (appName == null || appName.isEmpty() ? "" : ("." + appName)) + ".node" + this.nodeid; - } - - protected String generateApplicationServiceId() { //涓巗ervicename鐩稿悓 - return generateApplicationServiceName(); - } - - protected String generateApplicationCheckName() { - return "check-" + generateApplicationServiceName(); - } - - protected String generateApplicationCheckId() { - return "check-" + generateApplicationServiceId(); - } - - //涔熶細鎻愪緵缁橦ttpMessageClusterAgent閫傜敤 - public String generateHttpServiceName(String protocol, String module, String resname) { - return protocol.toLowerCase() + ":" + module + (resname == null || resname.isEmpty() ? "" : ("-" + resname)); - } - - //鏍煎紡: protocol:classtype-resourcename - protected String generateServiceName(NodeServer ns, String protocol, Service service) { - if (protocol.toLowerCase().startsWith("http")) { //HTTP浣跨敤RestService.name鏂瑰紡鏄负浜嗕笌MessageClient涓殑module淇濇寔涓鑷, 鍥犱负HTTP渚濋潬鐨剈rl涓殑module锛屾棤娉曠煡閬揝ervice绫诲悕 - String resname = Sncp.getResourceName(service); - String module = Rest.getRestModule(service).toLowerCase(); - return protocol.toLowerCase() + ":" + module + (resname.isEmpty() ? "" : ("-" + resname)); - } - if ("mqtp".equalsIgnoreCase(protocol)) { - MessageMultiConsumer mmc = service.getClass().getAnnotation(MessageMultiConsumer.class); - String selfmodule = Rest.getRestModule(service).toLowerCase(); - return protocol.toLowerCase() + ":" + mmc.module() + ":" + selfmodule; - } - if (!Sncp.isSncpDyn(service)) return protocol.toLowerCase() + ":" + service.getClass().getName(); - String resname = Sncp.getResourceName(service); - return protocol.toLowerCase() + ":" + Sncp.getResourceType(service).getName() + (resname.isEmpty() ? "" : ("-" + resname)); - } - - //鏍煎紡: protocol:classtype-resourcename:nodeid - protected String generateServiceId(NodeServer ns, String protocol, Service service) { - return generateServiceName(ns, protocol, service) + ":" + this.nodeid; - } - - protected String generateCheckName(NodeServer ns, String protocol, Service service) { - return "check-" + generateServiceName(ns, protocol, service); - } - - protected String generateCheckId(NodeServer ns, String protocol, Service service) { - return "check-" + generateServiceId(ns, protocol, service); - } - - protected ConcurrentHashMap getLocalEntrys() { - return localEntrys; - } - - protected ConcurrentHashMap getRemoteEntrys() { - return remoteEntrys; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - - public TransportFactory getTransportFactory() { - return transportFactory; - } - - public void setTransportFactory(TransportFactory transportFactory) { - this.transportFactory = transportFactory; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String[] getProtocols() { - return protocols; - } - - public void setProtocols(String[] protocols) { - this.protocols = protocols; - } - - public int[] getPorts() { - return ports; - } - - public void setPorts(int[] ports) { - this.ports = ports; - } - - public AnyValue getConfig() { - return config; - } - - public void setConfig(AnyValue config) { - this.config = config; - } - - public class ClusterEntry { - - public String serviceid; - - public String servicename; - - public String checkid; - - public String checkname; - - public String protocol; - - public String netprotocol; - - public WeakReference serviceref; - - public InetSocketAddress address; - - public boolean canceled; - - public boolean submqtp; - - public ClusterEntry(NodeServer ns, String protocol, Service service) { - this.serviceid = generateServiceId(ns, protocol, service); - this.servicename = generateServiceName(ns, protocol, service); - this.checkid = generateCheckId(ns, protocol, service); - this.checkname = generateCheckName(ns, protocol, service); - this.protocol = protocol; - InetSocketAddress addr = ns.getSocketAddress(); - String host = addr.getHostString(); - if ("0.0.0.0".equals(host)) { - host = appAddress.getHostString(); - addr = new InetSocketAddress(host, addr.getPort()); - } - this.address = addr; - this.serviceref = new WeakReference(service); - Server server = ns.getServer(); - this.netprotocol = server instanceof SncpServer ? ((SncpServer) server).getNetprotocol() : Transport.DEFAULT_NETPROTOCOL; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - } -} +/* + * 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.cluster; + +import java.lang.ref.WeakReference; +import java.net.InetSocketAddress; +import java.util.*; +import java.util.concurrent.*; +import java.util.logging.Logger; +import javax.annotation.Resource; +import org.redkale.boot.*; +import static org.redkale.boot.Application.*; +import org.redkale.convert.json.JsonConvert; +import org.redkale.mq.MessageMultiConsumer; +import org.redkale.net.*; +import org.redkale.net.http.*; +import org.redkale.net.sncp.*; +import org.redkale.service.*; +import org.redkale.util.*; + +/** + * 绗笁鏂规湇鍔″彂鐜扮鐞嗘帴鍙luster + * + * + * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.1.0 + */ +public abstract class ClusterAgent { + + protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); + + @Resource(name = RESNAME_APP_NODEID) + protected int nodeid; + + @Resource(name = RESNAME_APP_NAME) + protected String appName = ""; + + @Resource(name = RESNAME_APP_ADDR) + protected InetSocketAddress appAddress; + + protected String name; + + protected boolean waits; + + protected String[] protocols; //蹇呴』鍏ㄥぇ鍐 + + protected int[] ports; + + protected AnyValue config; + + protected TransportFactory transportFactory; + + protected final ConcurrentHashMap localEntrys = new ConcurrentHashMap<>(); + + protected final ConcurrentHashMap remoteEntrys = new ConcurrentHashMap<>(); + + public void init(AnyValue config) { + this.config = config; + this.name = config.getValue("name", ""); + this.waits = config.getBoolValue("waits", false); + { + String ps = config.getValue("protocols", "").toUpperCase(); + if (ps == null || ps.isEmpty()) ps = "SNCP;HTTP"; + this.protocols = ps.split(";"); + } + String ts = config.getValue("ports", ""); + if (ts != null && !ts.isEmpty()) { + String[] its = ts.split(";"); + List list = new ArrayList<>(); + for (String str : its) { + if (str.trim().isEmpty()) continue; + list.add(Integer.parseInt(str.trim())); + } + if (!list.isEmpty()) this.ports = list.stream().mapToInt(x -> x).toArray(); + } + } + + public void destroy(AnyValue config) { + } + + //ServiceLoader鏃跺垽鏂厤缃槸鍚︾鍚堝綋鍓嶅疄鐜扮被 + public abstract boolean acceptsConf(AnyValue config); + + public boolean containsProtocol(String protocol) { + if (protocol == null || protocol.isEmpty()) return false; + return protocols == null || Utility.contains(protocols, protocol.toUpperCase()); + } + + public boolean containsPort(int port) { + if (ports == null || ports.length == 0) return true; + return Utility.contains(ports, port); + } + + public abstract void register(Application application); + + public abstract void deregister(Application application); + + //娉ㄥ唽鏈嶅姟, 鍦∟odeService璋冪敤Service.init鏂规硶涔嬪墠璋冪敤 + public void register(NodeServer ns, String protocol, Set localServices, Set remoteServices) { + if (localServices.isEmpty()) return; + //娉ㄥ唽鏈湴妯″紡 + for (Service service : localServices) { + if (!canRegister(protocol, service)) continue; + ClusterEntry htentry = register(ns, protocol, service); + localEntrys.put(htentry.serviceid, htentry); + if (protocol.toLowerCase().startsWith("http")) { + MessageMultiConsumer mmc = service.getClass().getAnnotation(MessageMultiConsumer.class); + if (mmc != null) { + ClusterEntry mqentry = register(ns, "mqtp", service); + localEntrys.put(mqentry.serviceid, mqentry); + htentry.submqtp = true; + } + } + } + //杩滅▼妯″紡鍔犺浇IP鍒楄〃, 鍙敮鎸丼NCP鍗忚 + if (ns.isSNCP()) { + for (Service service : remoteServices) { + ClusterEntry entry = new ClusterEntry(ns, protocol, service); + updateSncpTransport(entry); + remoteEntrys.put(entry.serviceid, entry); + } + } + } + + //娉ㄩ攢鏈嶅姟, 鍦∟odeService璋冪敤Service.destroy 鏂规硶涔嬪墠璋冪敤 + public void deregister(NodeServer ns, String protocol, Set localServices, Set remoteServices) { + //娉ㄩ攢鏈湴妯″紡 杩滅▼妯″紡涓嶆敞鍐 + for (Service service : localServices) { + if (!canRegister(protocol, service)) continue; + deregister(ns, protocol, service); + } + afterDeregister(ns, protocol); + } + + protected boolean canRegister(String protocol, Service service) { + if ("SNCP".equalsIgnoreCase(protocol) && service.getClass().getAnnotation(Local.class) != null) return false; + AutoLoad al = service.getClass().getAnnotation(AutoLoad.class); + if (al != null && !al.value() && service.getClass().getAnnotation(Local.class) != null) return false; + if (service instanceof WebSocketNode) { + if (((WebSocketNode) service).getLocalWebSocketEngine() == null) return false; + } + return true; + } + + public void start() { + } + + protected void afterDeregister(NodeServer ns, String protocol) { + if (!this.waits) return; + int s = intervalCheckSeconds(); + if (s > 0) { //鏆傚仠锛屽讥琛ュ叾浠栦緷璧栨湰杩涚▼鏈嶅姟鐨勫懆鏈熷亸宸 + try { + Thread.sleep(s * 1000); + } catch (InterruptedException ex) { + } + logger.info(this.getClass().getSimpleName() + " wait for " + s * 1000 + "ms after deregister"); + } + } + + public int intervalCheckSeconds() { + return 10; + } + + //鑾峰彇MQTP鐨凥TTP杩滅▼鏈嶅姟鐨勫彲鐢╥p鍒楄〃, key = servicename鐨勫悗鍗婃 + public abstract CompletableFuture>> queryMqtpAddress(String protocol, String module, String resname); + + //鑾峰彇HTTP杩滅▼鏈嶅姟鐨勫彲鐢╥p鍒楄〃 + public abstract CompletableFuture> queryHttpAddress(String protocol, String module, String resname); + + //鑾峰彇杩滅▼鏈嶅姟鐨勫彲鐢╥p鍒楄〃 + protected abstract CompletableFuture> queryAddress(ClusterEntry entry); + + //娉ㄥ唽鏈嶅姟 + protected abstract ClusterEntry register(NodeServer ns, String protocol, Service service); + + //娉ㄩ攢鏈嶅姟 + protected abstract void deregister(NodeServer ns, String protocol, Service service); + + //鏍煎紡: protocol:classtype-resourcename + protected void updateSncpTransport(ClusterEntry entry) { + Service service = entry.serviceref.get(); + if (service == null) return; + Collection addrs = ClusterAgent.this.queryAddress(entry).join(); + Sncp.updateTransport(service, transportFactory, Sncp.getResourceType(service).getName() + "-" + Sncp.getResourceName(service), entry.netprotocol, entry.address, null, addrs); + } + + protected String generateApplicationServiceName() { + return "application" + (appName == null || appName.isEmpty() ? "" : ("." + appName)) + ".node" + this.nodeid; + } + + protected String generateApplicationServiceId() { //涓巗ervicename鐩稿悓 + return generateApplicationServiceName(); + } + + protected String generateApplicationCheckName() { + return "check-" + generateApplicationServiceName(); + } + + protected String generateApplicationCheckId() { + return "check-" + generateApplicationServiceId(); + } + + //涔熶細鎻愪緵缁橦ttpMessageClusterAgent閫傜敤 + public String generateHttpServiceName(String protocol, String module, String resname) { + return protocol.toLowerCase() + ":" + module + (resname == null || resname.isEmpty() ? "" : ("-" + resname)); + } + + //鏍煎紡: protocol:classtype-resourcename + protected String generateServiceName(NodeServer ns, String protocol, Service service) { + if (protocol.toLowerCase().startsWith("http")) { //HTTP浣跨敤RestService.name鏂瑰紡鏄负浜嗕笌MessageClient涓殑module淇濇寔涓鑷, 鍥犱负HTTP渚濋潬鐨剈rl涓殑module锛屾棤娉曠煡閬揝ervice绫诲悕 + String resname = Sncp.getResourceName(service); + String module = Rest.getRestModule(service).toLowerCase(); + return protocol.toLowerCase() + ":" + module + (resname.isEmpty() ? "" : ("-" + resname)); + } + if ("mqtp".equalsIgnoreCase(protocol)) { + MessageMultiConsumer mmc = service.getClass().getAnnotation(MessageMultiConsumer.class); + String selfmodule = Rest.getRestModule(service).toLowerCase(); + return protocol.toLowerCase() + ":" + mmc.module() + ":" + selfmodule; + } + if (!Sncp.isSncpDyn(service)) return protocol.toLowerCase() + ":" + service.getClass().getName(); + String resname = Sncp.getResourceName(service); + return protocol.toLowerCase() + ":" + Sncp.getResourceType(service).getName() + (resname.isEmpty() ? "" : ("-" + resname)); + } + + //鏍煎紡: protocol:classtype-resourcename:nodeid + protected String generateServiceId(NodeServer ns, String protocol, Service service) { + return generateServiceName(ns, protocol, service) + ":" + this.nodeid; + } + + protected String generateCheckName(NodeServer ns, String protocol, Service service) { + return "check-" + generateServiceName(ns, protocol, service); + } + + protected String generateCheckId(NodeServer ns, String protocol, Service service) { + return "check-" + generateServiceId(ns, protocol, service); + } + + protected ConcurrentHashMap getLocalEntrys() { + return localEntrys; + } + + protected ConcurrentHashMap getRemoteEntrys() { + return remoteEntrys; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + + public TransportFactory getTransportFactory() { + return transportFactory; + } + + public void setTransportFactory(TransportFactory transportFactory) { + this.transportFactory = transportFactory; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String[] getProtocols() { + return protocols; + } + + public void setProtocols(String[] protocols) { + this.protocols = protocols; + } + + public int[] getPorts() { + return ports; + } + + public void setPorts(int[] ports) { + this.ports = ports; + } + + public AnyValue getConfig() { + return config; + } + + public void setConfig(AnyValue config) { + this.config = config; + } + + public class ClusterEntry { + + public String serviceid; + + public String servicename; + + public String checkid; + + public String checkname; + + public String protocol; + + public String netprotocol; + + public WeakReference serviceref; + + public InetSocketAddress address; + + public boolean canceled; + + public boolean submqtp; + + public ClusterEntry(NodeServer ns, String protocol, Service service) { + this.serviceid = generateServiceId(ns, protocol, service); + this.servicename = generateServiceName(ns, protocol, service); + this.checkid = generateCheckId(ns, protocol, service); + this.checkname = generateCheckName(ns, protocol, service); + this.protocol = protocol; + InetSocketAddress addr = ns.getSocketAddress(); + String host = addr.getHostString(); + if ("0.0.0.0".equals(host)) { + host = appAddress.getHostString(); + addr = new InetSocketAddress(host, addr.getPort()); + } + this.address = addr; + this.serviceref = new WeakReference(service); + Server server = ns.getServer(); + this.netprotocol = server instanceof SncpServer ? ((SncpServer) server).getNetprotocol() : Transport.DEFAULT_NETPROTOCOL; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + } +} diff --git a/src/main/java/org/redkale/cluster/ClusterAgentProvider.java b/src/main/java/org/redkale/cluster/ClusterAgentProvider.java index 8c37523c8..7c5f25de6 100644 --- a/src/main/java/org/redkale/cluster/ClusterAgentProvider.java +++ b/src/main/java/org/redkale/cluster/ClusterAgentProvider.java @@ -1,25 +1,25 @@ -/* - * 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.cluster; - -import org.redkale.util.AnyValue; - -/** - * 鑷畾涔夌殑ClusterAgent鍔犺浇鍣 - * - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @since 2.5.0 - */ -public interface ClusterAgentProvider { - - public boolean acceptsConf(AnyValue config); - - public Class agentClass(); -} +/* + * 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.cluster; + +import org.redkale.util.AnyValue; + +/** + * 鑷畾涔夌殑ClusterAgent鍔犺浇鍣 + * + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @since 2.5.0 + */ +public interface ClusterAgentProvider { + + public boolean acceptsConf(AnyValue config); + + public Class agentClass(); +} diff --git a/src/main/java/org/redkale/convert/AnyDecoder.java b/src/main/java/org/redkale/convert/AnyDecoder.java index b6708e878..b270d86a7 100644 --- a/src/main/java/org/redkale/convert/AnyDecoder.java +++ b/src/main/java/org/redkale/convert/AnyDecoder.java @@ -1,64 +1,64 @@ -/* - * 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.convert; - -import java.lang.reflect.Type; -import java.util.*; -import org.redkale.util.*; -import org.redkale.convert.Reader.ValueType; -import static org.redkale.convert.Reader.ValueType.MAP; - -/** - * 瀵逛笉鏄庣被鍨嬬殑瀵硅薄杩涜鍙嶅簭鍒楀寲銆
- * 娉ㄦ剰: 鐩墠鍙敮鎸佹枃鏈牸寮
- *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public class AnyDecoder implements Decodeable { - - private static final Type collectionObjectType = new TypeToken>() { - }.getType(); - - private static final Type mapObjectType = new TypeToken>() { - }.getType(); - - private static final Creator collectionCreator = Creator.create(ArrayList.class); - - private static final Creator mapCreator = Creator.create(HashMap.class); - - protected final Decodeable stringDecoder; - - protected final CollectionDecoder collectionDecoder; - - protected final MapDecoder mapDecoder; - - public AnyDecoder(final ConvertFactory factory) { - this.stringDecoder = factory.loadDecoder(String.class); - this.collectionDecoder = new CollectionDecoder(factory, collectionObjectType, Object.class, collectionCreator, this); - this.mapDecoder = new MapDecoder(factory, mapObjectType, String.class, Object.class, mapCreator, stringDecoder, this); - } - - @Override - public Object convertFrom(Reader in) { - ValueType vt = in.readType(); - if (vt == null) return null; - switch (vt) { - case ARRAY: - return this.collectionDecoder.convertFrom(in); - case MAP: - return this.mapDecoder.convertFrom(in); - } - return this.stringDecoder.convertFrom(in); - } - - @Override - public Type getType() { - return void.class; - } - -} +/* + * 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.convert; + +import java.lang.reflect.Type; +import java.util.*; +import org.redkale.util.*; +import org.redkale.convert.Reader.ValueType; +import static org.redkale.convert.Reader.ValueType.MAP; + +/** + * 瀵逛笉鏄庣被鍨嬬殑瀵硅薄杩涜鍙嶅簭鍒楀寲銆
+ * 娉ㄦ剰: 鐩墠鍙敮鎸佹枃鏈牸寮
+ *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public class AnyDecoder implements Decodeable { + + private static final Type collectionObjectType = new TypeToken>() { + }.getType(); + + private static final Type mapObjectType = new TypeToken>() { + }.getType(); + + private static final Creator collectionCreator = Creator.create(ArrayList.class); + + private static final Creator mapCreator = Creator.create(HashMap.class); + + protected final Decodeable stringDecoder; + + protected final CollectionDecoder collectionDecoder; + + protected final MapDecoder mapDecoder; + + public AnyDecoder(final ConvertFactory factory) { + this.stringDecoder = factory.loadDecoder(String.class); + this.collectionDecoder = new CollectionDecoder(factory, collectionObjectType, Object.class, collectionCreator, this); + this.mapDecoder = new MapDecoder(factory, mapObjectType, String.class, Object.class, mapCreator, stringDecoder, this); + } + + @Override + public Object convertFrom(Reader in) { + ValueType vt = in.readType(); + if (vt == null) return null; + switch (vt) { + case ARRAY: + return this.collectionDecoder.convertFrom(in); + case MAP: + return this.mapDecoder.convertFrom(in); + } + return this.stringDecoder.convertFrom(in); + } + + @Override + public Type getType() { + return void.class; + } + +} diff --git a/src/main/java/org/redkale/convert/AnyEncoder.java b/src/main/java/org/redkale/convert/AnyEncoder.java index c118fb5f0..310ce4633 100644 --- a/src/main/java/org/redkale/convert/AnyEncoder.java +++ b/src/main/java/org/redkale/convert/AnyEncoder.java @@ -1,73 +1,73 @@ -/* - * 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.convert; - -import java.lang.reflect.Type; -import java.util.concurrent.CompletableFuture; - -/** - * 瀵逛笉鏄庣被鍨嬬殑瀵硅薄杩涜搴忓垪鍖栵紱 BSON搴忓垪鍖栨椂灏嗗璞$殑绫诲悕鍐欏叆Writer锛孞SON鍒欎笉鍐欏叆銆 - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param 搴忓垪鍖栫殑娉涘瀷绫诲瀷 - */ -public final class AnyEncoder implements Encodeable { - - final ConvertFactory factory; - - AnyEncoder(ConvertFactory factory) { - this.factory = factory; - } - - @Override - @SuppressWarnings("unchecked") - public void convertTo(final Writer out, final T value) { - if (value == null) { - out.writeClassName(null); - out.writeNull(); - } else { - Class clazz = value.getClass(); - if (clazz == Object.class) { - out.writeObjectB(value); - out.writeObjectE(value); - return; - } - if (out.needWriteClassName()) out.writeClassName(factory.getEntityAlias(clazz)); - factory.loadEncoder(clazz).convertTo(out, value); - } - } - - @SuppressWarnings("unchecked") - public void convertMapTo(final Writer out, final Object... values) { - if (values == null) { - out.writeNull(); - } else { - int count = values.length - values.length % 2; - if (out.writeMapB(count / 2, (Encodeable) this, (Encodeable) this, values) < 0) { - for (int i = 0; i < count; i += 2) { - if (i > 0) out.writeArrayMark(); - this.convertTo(out, (T) values[i]); - out.writeMapMark(); - Object val = values[i + 1]; - if (val instanceof CompletableFuture) { - this.convertTo(out, (T) ((CompletableFuture) val).join()); - } else { - this.convertTo(out, (T) val); - } - } - } - out.writeMapE(); - } - } - - @Override - public Type getType() { - return Object.class; - } - -} +/* + * 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.convert; + +import java.lang.reflect.Type; +import java.util.concurrent.CompletableFuture; + +/** + * 瀵逛笉鏄庣被鍨嬬殑瀵硅薄杩涜搴忓垪鍖栵紱 BSON搴忓垪鍖栨椂灏嗗璞$殑绫诲悕鍐欏叆Writer锛孞SON鍒欎笉鍐欏叆銆 + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param 搴忓垪鍖栫殑娉涘瀷绫诲瀷 + */ +public final class AnyEncoder implements Encodeable { + + final ConvertFactory factory; + + AnyEncoder(ConvertFactory factory) { + this.factory = factory; + } + + @Override + @SuppressWarnings("unchecked") + public void convertTo(final Writer out, final T value) { + if (value == null) { + out.writeClassName(null); + out.writeNull(); + } else { + Class clazz = value.getClass(); + if (clazz == Object.class) { + out.writeObjectB(value); + out.writeObjectE(value); + return; + } + if (out.needWriteClassName()) out.writeClassName(factory.getEntityAlias(clazz)); + factory.loadEncoder(clazz).convertTo(out, value); + } + } + + @SuppressWarnings("unchecked") + public void convertMapTo(final Writer out, final Object... values) { + if (values == null) { + out.writeNull(); + } else { + int count = values.length - values.length % 2; + if (out.writeMapB(count / 2, (Encodeable) this, (Encodeable) this, values) < 0) { + for (int i = 0; i < count; i += 2) { + if (i > 0) out.writeArrayMark(); + this.convertTo(out, (T) values[i]); + out.writeMapMark(); + Object val = values[i + 1]; + if (val instanceof CompletableFuture) { + this.convertTo(out, (T) ((CompletableFuture) val).join()); + } else { + this.convertTo(out, (T) val); + } + } + } + out.writeMapE(); + } + } + + @Override + public Type getType() { + return Object.class; + } + +} diff --git a/src/main/java/org/redkale/convert/AnyValueDecoder.java b/src/main/java/org/redkale/convert/AnyValueDecoder.java index 52f46d1a4..466665747 100644 --- a/src/main/java/org/redkale/convert/AnyValueDecoder.java +++ b/src/main/java/org/redkale/convert/AnyValueDecoder.java @@ -1,40 +1,40 @@ -/* - * 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.convert; - -import java.lang.reflect.Type; -import org.redkale.util.AnyValue; - -/** - * AnyValue鐨凞ecoder瀹炵幇 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Reader杈撳叆鐨勫瓙绫诲瀷 - * - * @since 2.5.0 - */ -public class AnyValueDecoder implements Decodeable { - - protected final ConvertFactory factory; - - public AnyValueDecoder(final ConvertFactory factory) { - this.factory = factory; - } - - @Override - public AnyValue convertFrom(R in) { - return null; - } - - @Override - public Type getType() { - return AnyValue.class; - } - -} +/* + * 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.convert; + +import java.lang.reflect.Type; +import org.redkale.util.AnyValue; + +/** + * AnyValue鐨凞ecoder瀹炵幇 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * + * @since 2.5.0 + */ +public class AnyValueDecoder implements Decodeable { + + protected final ConvertFactory factory; + + public AnyValueDecoder(final ConvertFactory factory) { + this.factory = factory; + } + + @Override + public AnyValue convertFrom(R in) { + return null; + } + + @Override + public Type getType() { + return AnyValue.class; + } + +} diff --git a/src/main/java/org/redkale/convert/AnyValueEncoder.java b/src/main/java/org/redkale/convert/AnyValueEncoder.java index 93a7f5ecc..728b13cbc 100644 --- a/src/main/java/org/redkale/convert/AnyValueEncoder.java +++ b/src/main/java/org/redkale/convert/AnyValueEncoder.java @@ -1,33 +1,33 @@ -/* - * 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.convert; - -import java.lang.reflect.Type; -import org.redkale.util.AnyValue; - -/** - * AnyValue鐨凟ncoder瀹炵幇 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Writer杈撳嚭鐨勫瓙绫 - * - * @since 2.5.0 - */ -public class AnyValueEncoder implements Encodeable { - - @Override - public void convertTo(W out, AnyValue value) { - } - - @Override - public Type getType() { - return AnyValue.class; - } - -} +/* + * 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.convert; + +import java.lang.reflect.Type; +import org.redkale.util.AnyValue; + +/** + * AnyValue鐨凟ncoder瀹炵幇 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Writer杈撳嚭鐨勫瓙绫 + * + * @since 2.5.0 + */ +public class AnyValueEncoder implements Encodeable { + + @Override + public void convertTo(W out, AnyValue value) { + } + + @Override + public Type getType() { + return AnyValue.class; + } + +} diff --git a/src/main/java/org/redkale/convert/ArrayDecoder.java b/src/main/java/org/redkale/convert/ArrayDecoder.java index 4a3f355ba..19ed88547 100644 --- a/src/main/java/org/redkale/convert/ArrayDecoder.java +++ b/src/main/java/org/redkale/convert/ArrayDecoder.java @@ -1,144 +1,144 @@ -/* - * 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.convert; - -import java.lang.reflect.*; -import java.util.*; - -/** - * 鏁扮粍鐨勫弽搴忓垪鍖栨搷浣滅被
- * 瀵硅薄鏁扮粍鐨勫弽搴忓垪鍖栵紝涓嶅寘鍚玦nt[]銆乴ong[]杩欐牱鐨刾rimitive class鏁扮粍銆
- * 鏀寔涓瀹氱▼搴︾殑娉涘瀷銆
- * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param 鍙嶈В鏋愮殑鏁扮粍鍏冪礌绫诲瀷 - */ -@SuppressWarnings("unchecked") -public class ArrayDecoder implements Decodeable { - - protected final Type type; - - protected final Type componentType; - - protected final Class componentClass; - - protected final Decodeable componentDecoder; - - protected volatile boolean inited = false; - - protected final Object lock = new Object(); - - public ArrayDecoder(final ConvertFactory factory, final Type type) { - this.type = type; - try { - if (type instanceof GenericArrayType) { - Type t = ((GenericArrayType) type).getGenericComponentType(); - this.componentType = t instanceof TypeVariable ? Object.class : t; - } else if ((type instanceof Class) && ((Class) type).isArray()) { - this.componentType = ((Class) type).getComponentType(); - } else { - throw new ConvertException("(" + type + ") is not a array type"); - } - if (this.componentType instanceof ParameterizedType) { - this.componentClass = (Class) ((ParameterizedType) this.componentType).getRawType(); - } else { - this.componentClass = (Class) this.componentType; - } - factory.register(type, this); - this.componentDecoder = factory.loadDecoder(this.componentType); - } finally { - inited = true; - synchronized (lock) { - lock.notifyAll(); - } - } - } - - @Override - public T[] convertFrom(Reader in) { - return convertFrom(in, null); - } - - public T[] convertFrom(Reader in, DeMember member) { - byte[] typevals = new byte[1]; - int len = in.readArrayB(member, typevals, componentDecoder); - int contentLength = -1; - if (len == Reader.SIGN_NULL) return null; - if (len == Reader.SIGN_NOLENBUTBYTES) { - contentLength = in.readMemberContentLength(member, componentDecoder); - len = Reader.SIGN_NOLENGTH; - } - if (this.componentDecoder == null) { - if (!this.inited) { - synchronized (lock) { - try { - lock.wait(); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - } - final Decodeable localdecoder = getComponentDecoder(this.componentDecoder, typevals); - final List result = new ArrayList(); - boolean first = true; - if (len == Reader.SIGN_NOLENGTH) { - int startPosition = in.position(); - while (hasNext(in, member, startPosition, contentLength, first)) { - Reader itemReader = getItemReader(in, member, first); - if (itemReader == null) break; - result.add(readMemberValue(itemReader, member, localdecoder, first)); - first = false; - } - } else { - for (int i = 0; i < len; i++) { - result.add(localdecoder.convertFrom(in)); - } - } - in.readArrayE(); - T[] rs = (T[]) Array.newInstance((Class) this.componentClass, result.size()); - return result.toArray(rs); - } - - protected boolean hasNext(Reader in, DeMember member, int startPosition, int contentLength, boolean first) { - return in.hasNext(startPosition, contentLength); - } - - protected Decodeable getComponentDecoder(Decodeable decoder, byte[] typevals) { - return decoder; - } - - protected Reader getItemReader(Reader in, DeMember member, boolean first) { - return in; - } - - protected T readMemberValue(Reader in, DeMember member, Decodeable decoder, boolean first) { - if (in == null) return null; - return decoder.convertFrom(in); - } - - @Override - public String toString() { - return this.getClass().getSimpleName() + "{componentType:" + this.componentType + ", decoder:" + this.componentDecoder + "}"; - } - - @Override - public Type getType() { - return type; - } - - public Type getComponentType() { - return componentType; - } - - public Decodeable getComponentDecoder() { - return componentDecoder; - } - -} +/* + * 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.convert; + +import java.lang.reflect.*; +import java.util.*; + +/** + * 鏁扮粍鐨勫弽搴忓垪鍖栨搷浣滅被
+ * 瀵硅薄鏁扮粍鐨勫弽搴忓垪鍖栵紝涓嶅寘鍚玦nt[]銆乴ong[]杩欐牱鐨刾rimitive class鏁扮粍銆
+ * 鏀寔涓瀹氱▼搴︾殑娉涘瀷銆
+ * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param 鍙嶈В鏋愮殑鏁扮粍鍏冪礌绫诲瀷 + */ +@SuppressWarnings("unchecked") +public class ArrayDecoder implements Decodeable { + + protected final Type type; + + protected final Type componentType; + + protected final Class componentClass; + + protected final Decodeable componentDecoder; + + protected volatile boolean inited = false; + + protected final Object lock = new Object(); + + public ArrayDecoder(final ConvertFactory factory, final Type type) { + this.type = type; + try { + if (type instanceof GenericArrayType) { + Type t = ((GenericArrayType) type).getGenericComponentType(); + this.componentType = t instanceof TypeVariable ? Object.class : t; + } else if ((type instanceof Class) && ((Class) type).isArray()) { + this.componentType = ((Class) type).getComponentType(); + } else { + throw new ConvertException("(" + type + ") is not a array type"); + } + if (this.componentType instanceof ParameterizedType) { + this.componentClass = (Class) ((ParameterizedType) this.componentType).getRawType(); + } else { + this.componentClass = (Class) this.componentType; + } + factory.register(type, this); + this.componentDecoder = factory.loadDecoder(this.componentType); + } finally { + inited = true; + synchronized (lock) { + lock.notifyAll(); + } + } + } + + @Override + public T[] convertFrom(Reader in) { + return convertFrom(in, null); + } + + public T[] convertFrom(Reader in, DeMember member) { + byte[] typevals = new byte[1]; + int len = in.readArrayB(member, typevals, componentDecoder); + int contentLength = -1; + if (len == Reader.SIGN_NULL) return null; + if (len == Reader.SIGN_NOLENBUTBYTES) { + contentLength = in.readMemberContentLength(member, componentDecoder); + len = Reader.SIGN_NOLENGTH; + } + if (this.componentDecoder == null) { + if (!this.inited) { + synchronized (lock) { + try { + lock.wait(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + final Decodeable localdecoder = getComponentDecoder(this.componentDecoder, typevals); + final List result = new ArrayList(); + boolean first = true; + if (len == Reader.SIGN_NOLENGTH) { + int startPosition = in.position(); + while (hasNext(in, member, startPosition, contentLength, first)) { + Reader itemReader = getItemReader(in, member, first); + if (itemReader == null) break; + result.add(readMemberValue(itemReader, member, localdecoder, first)); + first = false; + } + } else { + for (int i = 0; i < len; i++) { + result.add(localdecoder.convertFrom(in)); + } + } + in.readArrayE(); + T[] rs = (T[]) Array.newInstance((Class) this.componentClass, result.size()); + return result.toArray(rs); + } + + protected boolean hasNext(Reader in, DeMember member, int startPosition, int contentLength, boolean first) { + return in.hasNext(startPosition, contentLength); + } + + protected Decodeable getComponentDecoder(Decodeable decoder, byte[] typevals) { + return decoder; + } + + protected Reader getItemReader(Reader in, DeMember member, boolean first) { + return in; + } + + protected T readMemberValue(Reader in, DeMember member, Decodeable decoder, boolean first) { + if (in == null) return null; + return decoder.convertFrom(in); + } + + @Override + public String toString() { + return this.getClass().getSimpleName() + "{componentType:" + this.componentType + ", decoder:" + this.componentDecoder + "}"; + } + + @Override + public Type getType() { + return type; + } + + public Type getComponentType() { + return componentType; + } + + public Decodeable getComponentDecoder() { + return componentDecoder; + } + +} diff --git a/src/main/java/org/redkale/convert/ArrayEncoder.java b/src/main/java/org/redkale/convert/ArrayEncoder.java index d19447780..8dadd3543 100644 --- a/src/main/java/org/redkale/convert/ArrayEncoder.java +++ b/src/main/java/org/redkale/convert/ArrayEncoder.java @@ -1,133 +1,133 @@ -/* - * 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.convert; - -import java.lang.reflect.*; - -/** - * 鏁扮粍鐨勫簭鍒楀寲鎿嶄綔绫
- * 瀵硅薄鏁扮粍鐨勫簭鍒楀寲锛屼笉鍖呭惈int[]銆乴ong[]杩欐牱鐨刾rimitive class鏁扮粍銆
- * 鏀寔涓瀹氱▼搴︾殑娉涘瀷銆
- * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param 搴忓垪鍖栫殑鏁扮粍鍏冪礌绫诲瀷 - */ -@SuppressWarnings("unchecked") -public class ArrayEncoder implements Encodeable { - - protected final Type type; - - protected final Type componentType; - - protected final Encodeable anyEncoder; - - protected final Encodeable componentEncoder; - - protected final boolean subtypefinal; - - protected volatile boolean inited = false; - - protected final Object lock = new Object(); - - public ArrayEncoder(final ConvertFactory factory, final Type type) { - this.type = type; - try { - if (type instanceof GenericArrayType) { - Type t = ((GenericArrayType) type).getGenericComponentType(); - this.componentType = t instanceof TypeVariable ? Object.class : t; - } else if ((type instanceof Class) && ((Class) type).isArray()) { - this.componentType = ((Class) type).getComponentType(); - } else { - throw new ConvertException("(" + type + ") is not a array type"); - } - factory.register(type, this); - this.componentEncoder = factory.loadEncoder(this.componentType); - this.anyEncoder = factory.getAnyEncoder(); - this.subtypefinal = (this.componentType instanceof Class) && Modifier.isFinal(((Class) this.componentType).getModifiers()); - } finally { - inited = true; - synchronized (lock) { - lock.notifyAll(); - } - } - } - - @Override - public void convertTo(Writer out, T[] value) { - convertTo(out, null, value); - } - - public void convertTo(Writer out, EnMember member, T[] value) { - if (value == null) { - out.writeNull(); - return; - } - int iMax = value.length - 1; - if (iMax == -1) { - out.writeArrayB(0, this, componentEncoder, value); - out.writeArrayE(); - return; - } - if (this.componentEncoder == null) { - if (!this.inited) { - synchronized (lock) { - try { - lock.wait(); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - } - Encodeable itemEncoder = this.componentEncoder; - if (subtypefinal) { - if (out.writeArrayB(value.length, this, itemEncoder, value) < 0) { - for (int i = 0;; i++) { - writeMemberValue(out, member, itemEncoder, value[i], i); - if (i == iMax) break; - out.writeArrayMark(); - } - } - } else { - if (out.writeArrayB(value.length, this, itemEncoder, value) < 0) { - final Type comp = this.componentType; - for (int i = 0;; i++) { - Object v = value[i]; - writeMemberValue(out, member, ((v != null && (v.getClass() == comp || out.specify() == comp)) ? itemEncoder : anyEncoder), v, i); - if (i == iMax) break; - out.writeArrayMark(); - } - } - } - out.writeArrayE(); - } - - protected void writeMemberValue(Writer out, EnMember member, Encodeable encoder, Object value, int index) { - encoder.convertTo(out, value); - } - - @Override - public String toString() { - return this.getClass().getSimpleName() + "{componentType:" + this.componentType + ", encoder:" + this.componentEncoder + "}"; - } - - @Override - public Type getType() { - return type; - } - - public Type getComponentType() { - return componentType; - } - - public Encodeable getComponentEncoder() { - return componentEncoder; - } - -} +/* + * 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.convert; + +import java.lang.reflect.*; + +/** + * 鏁扮粍鐨勫簭鍒楀寲鎿嶄綔绫
+ * 瀵硅薄鏁扮粍鐨勫簭鍒楀寲锛屼笉鍖呭惈int[]銆乴ong[]杩欐牱鐨刾rimitive class鏁扮粍銆
+ * 鏀寔涓瀹氱▼搴︾殑娉涘瀷銆
+ * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param 搴忓垪鍖栫殑鏁扮粍鍏冪礌绫诲瀷 + */ +@SuppressWarnings("unchecked") +public class ArrayEncoder implements Encodeable { + + protected final Type type; + + protected final Type componentType; + + protected final Encodeable anyEncoder; + + protected final Encodeable componentEncoder; + + protected final boolean subtypefinal; + + protected volatile boolean inited = false; + + protected final Object lock = new Object(); + + public ArrayEncoder(final ConvertFactory factory, final Type type) { + this.type = type; + try { + if (type instanceof GenericArrayType) { + Type t = ((GenericArrayType) type).getGenericComponentType(); + this.componentType = t instanceof TypeVariable ? Object.class : t; + } else if ((type instanceof Class) && ((Class) type).isArray()) { + this.componentType = ((Class) type).getComponentType(); + } else { + throw new ConvertException("(" + type + ") is not a array type"); + } + factory.register(type, this); + this.componentEncoder = factory.loadEncoder(this.componentType); + this.anyEncoder = factory.getAnyEncoder(); + this.subtypefinal = (this.componentType instanceof Class) && Modifier.isFinal(((Class) this.componentType).getModifiers()); + } finally { + inited = true; + synchronized (lock) { + lock.notifyAll(); + } + } + } + + @Override + public void convertTo(Writer out, T[] value) { + convertTo(out, null, value); + } + + public void convertTo(Writer out, EnMember member, T[] value) { + if (value == null) { + out.writeNull(); + return; + } + int iMax = value.length - 1; + if (iMax == -1) { + out.writeArrayB(0, this, componentEncoder, value); + out.writeArrayE(); + return; + } + if (this.componentEncoder == null) { + if (!this.inited) { + synchronized (lock) { + try { + lock.wait(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + Encodeable itemEncoder = this.componentEncoder; + if (subtypefinal) { + if (out.writeArrayB(value.length, this, itemEncoder, value) < 0) { + for (int i = 0;; i++) { + writeMemberValue(out, member, itemEncoder, value[i], i); + if (i == iMax) break; + out.writeArrayMark(); + } + } + } else { + if (out.writeArrayB(value.length, this, itemEncoder, value) < 0) { + final Type comp = this.componentType; + for (int i = 0;; i++) { + Object v = value[i]; + writeMemberValue(out, member, ((v != null && (v.getClass() == comp || out.specify() == comp)) ? itemEncoder : anyEncoder), v, i); + if (i == iMax) break; + out.writeArrayMark(); + } + } + } + out.writeArrayE(); + } + + protected void writeMemberValue(Writer out, EnMember member, Encodeable encoder, Object value, int index) { + encoder.convertTo(out, value); + } + + @Override + public String toString() { + return this.getClass().getSimpleName() + "{componentType:" + this.componentType + ", encoder:" + this.componentEncoder + "}"; + } + + @Override + public Type getType() { + return type; + } + + public Type getComponentType() { + return componentType; + } + + public Encodeable getComponentEncoder() { + return componentEncoder; + } + +} diff --git a/src/main/java/org/redkale/convert/BinaryConvert.java b/src/main/java/org/redkale/convert/BinaryConvert.java index 3c3c4254e..6db363567 100644 --- a/src/main/java/org/redkale/convert/BinaryConvert.java +++ b/src/main/java/org/redkale/convert/BinaryConvert.java @@ -1,35 +1,35 @@ -/* - * 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.convert; - -import java.lang.reflect.Type; - -/** - * 浜岃繘鍒跺簭鍒楀寲/鍙嶅簭鍒楀寲鎿嶄綔绫 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Reader杈撳叆鐨勫瓙绫 - * @param Writer杈撳嚭鐨勫瓙绫 - */ -public abstract class BinaryConvert extends Convert { - - protected BinaryConvert(ConvertFactory factory) { - super(factory); - } - - @Override - public final boolean isBinary() { - return true; - } - - public abstract byte[] convertTo(final Object value); - - public abstract byte[] convertTo(final Type type, final Object value); - -} +/* + * 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.convert; + +import java.lang.reflect.Type; + +/** + * 浜岃繘鍒跺簭鍒楀寲/鍙嶅簭鍒楀寲鎿嶄綔绫 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Reader杈撳叆鐨勫瓙绫 + * @param Writer杈撳嚭鐨勫瓙绫 + */ +public abstract class BinaryConvert extends Convert { + + protected BinaryConvert(ConvertFactory factory) { + super(factory); + } + + @Override + public final boolean isBinary() { + return true; + } + + public abstract byte[] convertTo(final Object value); + + public abstract byte[] convertTo(final Type type, final Object value); + +} diff --git a/src/main/java/org/redkale/convert/CollectionDecoder.java b/src/main/java/org/redkale/convert/CollectionDecoder.java index af5538397..a67feccdd 100644 --- a/src/main/java/org/redkale/convert/CollectionDecoder.java +++ b/src/main/java/org/redkale/convert/CollectionDecoder.java @@ -1,149 +1,149 @@ -/* - * 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.convert; - -import org.redkale.util.Creator; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.util.*; - -/** - * Collection鐨勫弽搴忓垪鍖栨搷浣滅被
- * 鏀寔涓瀹氱▼搴︾殑娉涘瀷銆
- * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param 鍙嶈В鏋愮殑闆嗗悎鍏冪礌绫诲瀷 - */ -@SuppressWarnings("unchecked") -public class CollectionDecoder implements Decodeable> { - - protected final Type type; - - protected final Type componentType; - - protected Creator> creator; - - protected final Decodeable componentDecoder; - - protected volatile boolean inited = false; - - protected final Object lock = new Object(); - - public CollectionDecoder(final ConvertFactory factory, final Type type) { - this.type = type; - try { - if (type instanceof ParameterizedType) { - final ParameterizedType pt = (ParameterizedType) type; - this.componentType = pt.getActualTypeArguments()[0]; - this.creator = factory.loadCreator((Class) pt.getRawType()); - factory.register(type, this); - this.componentDecoder = factory.loadDecoder(this.componentType); - } else if (factory.isReversible()) { - this.componentType = Object.class; - this.creator = factory.loadCreator(type instanceof Class ? (Class) type : Collection.class); - factory.register(type, this); - this.componentDecoder = factory.loadDecoder(this.componentType); - } else { - throw new ConvertException("CollectionDecoder not support the type (" + type + ")"); - } - } finally { - inited = true; - synchronized (lock) { - lock.notifyAll(); - } - } - } - - //浠呬緵绫讳技JsonAnyDecoder杩欑鍔ㄦ佸垱寤轰娇鐢紝 涓嶅緱璋冪敤 factory.register - public CollectionDecoder(final ConvertFactory factory, Type type, Type componentType, - Creator> creator, final Decodeable componentDecoder) { - Objects.requireNonNull(componentDecoder); - this.type = type; - this.componentType = componentType; - this.creator = creator; - this.componentDecoder = componentDecoder; - this.inited = true; - } - - @Override - public Collection convertFrom(Reader in) { - return convertFrom(in, null); - } - - public Collection convertFrom(Reader in, DeMember member) { - byte[] typevals = new byte[1]; - int len = in.readArrayB(member, typevals, componentDecoder); - int contentLength = -1; - if (len == Reader.SIGN_NULL) return null; - if (len == Reader.SIGN_NOLENBUTBYTES) { - contentLength = in.readMemberContentLength(member, componentDecoder); - len = Reader.SIGN_NOLENGTH; - } - if (this.componentDecoder == null) { - if (!this.inited) { - synchronized (lock) { - try { - lock.wait(); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - } - final Decodeable localdecoder = getComponentDecoder(this.componentDecoder, typevals); - final Collection result = this.creator.create(); - boolean first = true; - if (len == Reader.SIGN_NOLENGTH) { - int startPosition = in.position(); - while (hasNext(in, member, startPosition, contentLength, first)) { - Reader itemReader = getItemReader(in, member, first); - if (itemReader == null) break; - result.add(readMemberValue(itemReader, member, localdecoder, first)); - first = false; - } - } else { - for (int i = 0; i < len; i++) { - result.add(localdecoder.convertFrom(in)); - } - } - in.readArrayE(); - return result; - } - - protected boolean hasNext(Reader in, DeMember member, int startPosition, int contentLength, boolean first) { - return in.hasNext(startPosition, contentLength); - } - - protected Decodeable getComponentDecoder(Decodeable decoder, byte[] typevals) { - return decoder; - } - - protected Reader getItemReader(Reader in, DeMember member, boolean first) { - return in; - } - - protected T readMemberValue(Reader in, DeMember member, Decodeable decoder, boolean first) { - if (in == null) return null; - return decoder.convertFrom(in); - } - - @Override - public Type getType() { - return type; - } - - public Type getComponentType() { - return componentType; - } - - public Decodeable getComponentDecoder() { - return componentDecoder; - } - -} +/* + * 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.convert; + +import org.redkale.util.Creator; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.*; + +/** + * Collection鐨勫弽搴忓垪鍖栨搷浣滅被
+ * 鏀寔涓瀹氱▼搴︾殑娉涘瀷銆
+ * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param 鍙嶈В鏋愮殑闆嗗悎鍏冪礌绫诲瀷 + */ +@SuppressWarnings("unchecked") +public class CollectionDecoder implements Decodeable> { + + protected final Type type; + + protected final Type componentType; + + protected Creator> creator; + + protected final Decodeable componentDecoder; + + protected volatile boolean inited = false; + + protected final Object lock = new Object(); + + public CollectionDecoder(final ConvertFactory factory, final Type type) { + this.type = type; + try { + if (type instanceof ParameterizedType) { + final ParameterizedType pt = (ParameterizedType) type; + this.componentType = pt.getActualTypeArguments()[0]; + this.creator = factory.loadCreator((Class) pt.getRawType()); + factory.register(type, this); + this.componentDecoder = factory.loadDecoder(this.componentType); + } else if (factory.isReversible()) { + this.componentType = Object.class; + this.creator = factory.loadCreator(type instanceof Class ? (Class) type : Collection.class); + factory.register(type, this); + this.componentDecoder = factory.loadDecoder(this.componentType); + } else { + throw new ConvertException("CollectionDecoder not support the type (" + type + ")"); + } + } finally { + inited = true; + synchronized (lock) { + lock.notifyAll(); + } + } + } + + //浠呬緵绫讳技JsonAnyDecoder杩欑鍔ㄦ佸垱寤轰娇鐢紝 涓嶅緱璋冪敤 factory.register + public CollectionDecoder(final ConvertFactory factory, Type type, Type componentType, + Creator> creator, final Decodeable componentDecoder) { + Objects.requireNonNull(componentDecoder); + this.type = type; + this.componentType = componentType; + this.creator = creator; + this.componentDecoder = componentDecoder; + this.inited = true; + } + + @Override + public Collection convertFrom(Reader in) { + return convertFrom(in, null); + } + + public Collection convertFrom(Reader in, DeMember member) { + byte[] typevals = new byte[1]; + int len = in.readArrayB(member, typevals, componentDecoder); + int contentLength = -1; + if (len == Reader.SIGN_NULL) return null; + if (len == Reader.SIGN_NOLENBUTBYTES) { + contentLength = in.readMemberContentLength(member, componentDecoder); + len = Reader.SIGN_NOLENGTH; + } + if (this.componentDecoder == null) { + if (!this.inited) { + synchronized (lock) { + try { + lock.wait(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + final Decodeable localdecoder = getComponentDecoder(this.componentDecoder, typevals); + final Collection result = this.creator.create(); + boolean first = true; + if (len == Reader.SIGN_NOLENGTH) { + int startPosition = in.position(); + while (hasNext(in, member, startPosition, contentLength, first)) { + Reader itemReader = getItemReader(in, member, first); + if (itemReader == null) break; + result.add(readMemberValue(itemReader, member, localdecoder, first)); + first = false; + } + } else { + for (int i = 0; i < len; i++) { + result.add(localdecoder.convertFrom(in)); + } + } + in.readArrayE(); + return result; + } + + protected boolean hasNext(Reader in, DeMember member, int startPosition, int contentLength, boolean first) { + return in.hasNext(startPosition, contentLength); + } + + protected Decodeable getComponentDecoder(Decodeable decoder, byte[] typevals) { + return decoder; + } + + protected Reader getItemReader(Reader in, DeMember member, boolean first) { + return in; + } + + protected T readMemberValue(Reader in, DeMember member, Decodeable decoder, boolean first) { + if (in == null) return null; + return decoder.convertFrom(in); + } + + @Override + public Type getType() { + return type; + } + + public Type getComponentType() { + return componentType; + } + + public Decodeable getComponentDecoder() { + return componentDecoder; + } + +} diff --git a/src/main/java/org/redkale/convert/CollectionEncoder.java b/src/main/java/org/redkale/convert/CollectionEncoder.java index 64233ffb9..f294fd412 100644 --- a/src/main/java/org/redkale/convert/CollectionEncoder.java +++ b/src/main/java/org/redkale/convert/CollectionEncoder.java @@ -1,111 +1,111 @@ -/* - * 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.convert; - -import java.lang.reflect.*; -import java.util.Collection; - -/** - * Collection鐨勫簭鍒楀寲鎿嶄綔绫
- * 鏀寔涓瀹氱▼搴︾殑娉涘瀷銆
- * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param 搴忓垪鍖栫殑闆嗗悎鍏冪礌绫诲瀷 - */ -@SuppressWarnings("unchecked") -public class CollectionEncoder implements Encodeable> { - - protected final Type type; - - protected final Encodeable componentEncoder; - - protected volatile boolean inited = false; - - protected final Object lock = new Object(); - - public CollectionEncoder(final ConvertFactory factory, final Type type) { - this.type = type; - try { - if (type instanceof ParameterizedType) { - Type t = ((ParameterizedType) type).getActualTypeArguments()[0]; - if (t instanceof TypeVariable) { - this.componentEncoder = factory.getAnyEncoder(); - } else { - this.componentEncoder = factory.loadEncoder(t); - } - } else { - this.componentEncoder = factory.getAnyEncoder(); - } - } finally { - inited = true; - synchronized (lock) { - lock.notifyAll(); - } - } - } - - @Override - public void convertTo(Writer out, Collection value) { - convertTo(out, null, value); - } - - public void convertTo(Writer out, EnMember member, Collection value) { - if (value == null) { - out.writeNull(); - return; - } - if (value.isEmpty()) { - out.writeArrayB(0, this, componentEncoder, value); - out.writeArrayE(); - return; - } - if (this.componentEncoder == null) { - if (!this.inited) { - synchronized (lock) { - try { - lock.wait(); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - } - if (out.writeArrayB(value.size(), this, componentEncoder, value) < 0) { - boolean first = true; - for (Object v : value) { - if (!first) out.writeArrayMark(); - writeMemberValue(out, member, v, first); - if (first) first = false; - } - } - out.writeArrayE(); - } - - protected void writeMemberValue(Writer out, EnMember member, Object value, boolean first) { - componentEncoder.convertTo(out, value); - } - - @Override - public Type getType() { - return type; - } - - @Override - public String toString() { - return this.getClass().getSimpleName() + "{componentType:" + this.type + ", encoder:" + this.componentEncoder + "}"; - } - - public Encodeable getComponentEncoder() { - return componentEncoder; - } - - public Type getComponentType() { - return componentEncoder == null ? null : componentEncoder.getType(); - } -} +/* + * 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.convert; + +import java.lang.reflect.*; +import java.util.Collection; + +/** + * Collection鐨勫簭鍒楀寲鎿嶄綔绫
+ * 鏀寔涓瀹氱▼搴︾殑娉涘瀷銆
+ * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param 搴忓垪鍖栫殑闆嗗悎鍏冪礌绫诲瀷 + */ +@SuppressWarnings("unchecked") +public class CollectionEncoder implements Encodeable> { + + protected final Type type; + + protected final Encodeable componentEncoder; + + protected volatile boolean inited = false; + + protected final Object lock = new Object(); + + public CollectionEncoder(final ConvertFactory factory, final Type type) { + this.type = type; + try { + if (type instanceof ParameterizedType) { + Type t = ((ParameterizedType) type).getActualTypeArguments()[0]; + if (t instanceof TypeVariable) { + this.componentEncoder = factory.getAnyEncoder(); + } else { + this.componentEncoder = factory.loadEncoder(t); + } + } else { + this.componentEncoder = factory.getAnyEncoder(); + } + } finally { + inited = true; + synchronized (lock) { + lock.notifyAll(); + } + } + } + + @Override + public void convertTo(Writer out, Collection value) { + convertTo(out, null, value); + } + + public void convertTo(Writer out, EnMember member, Collection value) { + if (value == null) { + out.writeNull(); + return; + } + if (value.isEmpty()) { + out.writeArrayB(0, this, componentEncoder, value); + out.writeArrayE(); + return; + } + if (this.componentEncoder == null) { + if (!this.inited) { + synchronized (lock) { + try { + lock.wait(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + if (out.writeArrayB(value.size(), this, componentEncoder, value) < 0) { + boolean first = true; + for (Object v : value) { + if (!first) out.writeArrayMark(); + writeMemberValue(out, member, v, first); + if (first) first = false; + } + } + out.writeArrayE(); + } + + protected void writeMemberValue(Writer out, EnMember member, Object value, boolean first) { + componentEncoder.convertTo(out, value); + } + + @Override + public Type getType() { + return type; + } + + @Override + public String toString() { + return this.getClass().getSimpleName() + "{componentType:" + this.type + ", encoder:" + this.componentEncoder + "}"; + } + + public Encodeable getComponentEncoder() { + return componentEncoder; + } + + public Type getComponentType() { + return componentEncoder == null ? null : componentEncoder.getType(); + } +} diff --git a/src/main/java/org/redkale/convert/Convert.java b/src/main/java/org/redkale/convert/Convert.java index cfbbdfc8e..6d4041728 100644 --- a/src/main/java/org/redkale/convert/Convert.java +++ b/src/main/java/org/redkale/convert/Convert.java @@ -1,80 +1,80 @@ -/* - * 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.convert; - -import java.lang.reflect.Type; -import java.nio.ByteBuffer; -import java.util.function.*; -import org.redkale.util.*; - -/** - * 搴忓垪鍖/鍙嶅簭鍒楀寲鎿嶄綔绫 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Reader杈撳叆鐨勫瓙绫 - * @param Writer杈撳嚭鐨勫瓙绫 - */ -public abstract class Convert { - - protected final ConvertFactory factory; - - protected Convert(ConvertFactory factory) { - this.factory = factory; - } - - public ConvertFactory getFactory() { - return this.factory; - } - - protected S configWrite(S writer) { - return writer; - } - - protected S fieldFunc(S writer, BiFunction objFieldFunc, Function objExtFunc) { - writer.objFieldFunc = objFieldFunc; - writer.objExtFunc = objExtFunc; - return writer; - } - - public abstract Convert newConvert(final BiFunction objFieldFunc); - - public abstract Convert newConvert(final BiFunction objFieldFunc, Function objExtFunc); - - public abstract boolean isBinary(); - - public abstract T convertFrom(final Type type, final byte[] bytes); - - //@since 2.2.0 - public abstract T convertFrom(final Type type, final byte[] bytes, final int offset, final int length); - - public abstract T convertFrom(final Type type, final ByteBuffer... buffers); - - public abstract T convertFrom(final Type type, final ConvertMask mask, final ByteBuffer... buffers); - - public abstract void convertTo(final W writer, final Object value); - - public abstract void convertTo(final W writer, final Type type, final Object value); - - public abstract byte[] convertToBytes(final Object value); - - public abstract byte[] convertToBytes(final Type type, final Object value); - - public abstract void convertToBytes(final Object value, final ConvertBytesHandler handler); - - public abstract void convertToBytes(final Type type, final Object value, final ConvertBytesHandler handler); - - public abstract void convertToBytes(final ByteArray array, final Object value); - - public abstract void convertToBytes(final ByteArray array, final Type type, final Object value); - - public abstract ByteBuffer[] convertTo(final Supplier supplier, final Object value); - - public abstract ByteBuffer[] convertTo(final Supplier supplier, final Type type, final Object value); - -} +/* + * 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.convert; + +import java.lang.reflect.Type; +import java.nio.ByteBuffer; +import java.util.function.*; +import org.redkale.util.*; + +/** + * 搴忓垪鍖/鍙嶅簭鍒楀寲鎿嶄綔绫 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Reader杈撳叆鐨勫瓙绫 + * @param Writer杈撳嚭鐨勫瓙绫 + */ +public abstract class Convert { + + protected final ConvertFactory factory; + + protected Convert(ConvertFactory factory) { + this.factory = factory; + } + + public ConvertFactory getFactory() { + return this.factory; + } + + protected S configWrite(S writer) { + return writer; + } + + protected S fieldFunc(S writer, BiFunction objFieldFunc, Function objExtFunc) { + writer.objFieldFunc = objFieldFunc; + writer.objExtFunc = objExtFunc; + return writer; + } + + public abstract Convert newConvert(final BiFunction objFieldFunc); + + public abstract Convert newConvert(final BiFunction objFieldFunc, Function objExtFunc); + + public abstract boolean isBinary(); + + public abstract T convertFrom(final Type type, final byte[] bytes); + + //@since 2.2.0 + public abstract T convertFrom(final Type type, final byte[] bytes, final int offset, final int length); + + public abstract T convertFrom(final Type type, final ByteBuffer... buffers); + + public abstract T convertFrom(final Type type, final ConvertMask mask, final ByteBuffer... buffers); + + public abstract void convertTo(final W writer, final Object value); + + public abstract void convertTo(final W writer, final Type type, final Object value); + + public abstract byte[] convertToBytes(final Object value); + + public abstract byte[] convertToBytes(final Type type, final Object value); + + public abstract void convertToBytes(final Object value, final ConvertBytesHandler handler); + + public abstract void convertToBytes(final Type type, final Object value, final ConvertBytesHandler handler); + + public abstract void convertToBytes(final ByteArray array, final Object value); + + public abstract void convertToBytes(final ByteArray array, final Type type, final Object value); + + public abstract ByteBuffer[] convertTo(final Supplier supplier, final Object value); + + public abstract ByteBuffer[] convertTo(final Supplier supplier, final Type type, final Object value); + +} diff --git a/src/main/java/org/redkale/convert/ConvertBytesHandler.java b/src/main/java/org/redkale/convert/ConvertBytesHandler.java index c1386ce6b..320ca0dcf 100644 --- a/src/main/java/org/redkale/convert/ConvertBytesHandler.java +++ b/src/main/java/org/redkale/convert/ConvertBytesHandler.java @@ -1,23 +1,23 @@ -/* - * 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.convert; - -import java.util.function.Consumer; - -/** - * - * convertToBytes绯诲垪鐨勬柟娉曠殑鍥炶皟 - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * - * @since 2.3.0 - */ -public interface ConvertBytesHandler { - - void completed(byte[] bs, int offset, int length, Consumer callback, A attachment); -} +/* + * 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.convert; + +import java.util.function.Consumer; + +/** + * + * convertToBytes绯诲垪鐨勬柟娉曠殑鍥炶皟 + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.3.0 + */ +public interface ConvertBytesHandler { + + void completed(byte[] bs, int offset, int length, Consumer callback, A attachment); +} diff --git a/src/main/java/org/redkale/convert/ConvertColumn.java b/src/main/java/org/redkale/convert/ConvertColumn.java index 9d220c346..6769e0cf7 100644 --- a/src/main/java/org/redkale/convert/ConvertColumn.java +++ b/src/main/java/org/redkale/convert/ConvertColumn.java @@ -1,71 +1,71 @@ -/* - * 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.convert; - -import java.lang.annotation.*; -import static java.lang.annotation.ElementType.*; -import static java.lang.annotation.RetentionPolicy.*; - -/** - * 渚濋檮鍦╯etter銆乬etter鏂规硶銆佸瓧娈佃繘琛岀畝鍗曠殑閰嶇疆 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@Inherited -@Documented -@Target({METHOD, FIELD}) -@Retention(RUNTIME) -@Repeatable(ConvertColumn.ConvertColumns.class) -public @interface ConvertColumn { - - /** - * 缁欏瓧娈靛彇涓埆鍚 - * - * @return 瀛楁鍒悕 - */ - String name() default ""; - - /** - * 缁欏瓧娈靛彇涓簭鍙稩D锛屽煎皬闈犲墠 - * - * @return 瀛楁鎺掑簭ID - */ - int index() default 0; - - /** - * 瑙f瀽/搴忓垪鍖栨椂鏄惁灞忚斀璇ュ瓧娈 - * - * @return 鏄惁灞忚斀璇ュ瓧娈 - */ - boolean ignore() default false; - - /** - * 瑙f瀽/搴忓垪鍖栧畾鍒跺寲鐨凾YPE - * - * @return JSON or BSON or ALL - */ - ConvertType type() default ConvertType.ALL; - - /** - * ConvertColumn 鐨勫鐢ㄧ被 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ - @Inherited - @Documented - @Target({METHOD, FIELD}) - @Retention(RUNTIME) - public static @interface ConvertColumns { - - ConvertColumn[] value(); - } -} +/* + * 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.convert; + +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +/** + * 渚濋檮鍦╯etter銆乬etter鏂规硶銆佸瓧娈佃繘琛岀畝鍗曠殑閰嶇疆 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@Inherited +@Documented +@Target({METHOD, FIELD}) +@Retention(RUNTIME) +@Repeatable(ConvertColumn.ConvertColumns.class) +public @interface ConvertColumn { + + /** + * 缁欏瓧娈靛彇涓埆鍚 + * + * @return 瀛楁鍒悕 + */ + String name() default ""; + + /** + * 缁欏瓧娈靛彇涓簭鍙稩D锛屽煎皬闈犲墠 + * + * @return 瀛楁鎺掑簭ID + */ + int index() default 0; + + /** + * 瑙f瀽/搴忓垪鍖栨椂鏄惁灞忚斀璇ュ瓧娈 + * + * @return 鏄惁灞忚斀璇ュ瓧娈 + */ + boolean ignore() default false; + + /** + * 瑙f瀽/搴忓垪鍖栧畾鍒跺寲鐨凾YPE + * + * @return JSON or BSON or ALL + */ + ConvertType type() default ConvertType.ALL; + + /** + * ConvertColumn 鐨勫鐢ㄧ被 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ + @Inherited + @Documented + @Target({METHOD, FIELD}) + @Retention(RUNTIME) + public static @interface ConvertColumns { + + ConvertColumn[] value(); + } +} diff --git a/src/main/java/org/redkale/convert/ConvertColumnEntry.java b/src/main/java/org/redkale/convert/ConvertColumnEntry.java index 5b119f445..1b10dd09a 100644 --- a/src/main/java/org/redkale/convert/ConvertColumnEntry.java +++ b/src/main/java/org/redkale/convert/ConvertColumnEntry.java @@ -1,97 +1,97 @@ -/* - * 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.convert; - -/** - * ConvertColumn 瀵瑰簲鐨勫疄浣撶被 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public final class ConvertColumnEntry { - - private int index; - - private String name = ""; - - private boolean ignore; - - private ConvertType convertType; - - public ConvertColumnEntry() { - } - - public ConvertColumnEntry(ConvertColumn column) { - if (column == null) return; - this.name = column.name(); - this.index = column.index(); - this.ignore = column.ignore(); - this.convertType = column.type(); - } - - public ConvertColumnEntry(String name) { - this(name, false); - } - - public ConvertColumnEntry(String name, boolean ignore) { - this.name = name; - this.ignore = ignore; - this.convertType = ConvertType.ALL; - } - - public ConvertColumnEntry(String name, boolean ignore, ConvertType convertType) { - this.name = name; - this.ignore = ignore; - this.convertType = convertType; - } - - public ConvertColumnEntry(String name, int index, boolean ignore, ConvertType convertType) { - this.name = name; - this.index = index; - this.ignore = ignore; - this.convertType = convertType; - } - - public String name() { - return name == null ? "" : name; - } - - public void setName(String name) { - this.name = name; - } - - public boolean ignore() { - return ignore; - } - - public void setIgnore(boolean ignore) { - this.ignore = ignore; - } - - public ConvertType type() { - return convertType == null ? ConvertType.ALL : convertType; - } - - public void setConvertType(ConvertType convertType) { - this.convertType = convertType; - } - - public int getIndex() { - return index; - } - - public void setIndex(int index) { - this.index = index; - } - - @Override - public String toString() { - return "ConvertColumnEntry{" + "index=" + index + ", name=" + name + ", ignore=" + ignore + ", convertType=" + convertType + '}'; - } - -} +/* + * 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.convert; + +/** + * ConvertColumn 瀵瑰簲鐨勫疄浣撶被 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public final class ConvertColumnEntry { + + private int index; + + private String name = ""; + + private boolean ignore; + + private ConvertType convertType; + + public ConvertColumnEntry() { + } + + public ConvertColumnEntry(ConvertColumn column) { + if (column == null) return; + this.name = column.name(); + this.index = column.index(); + this.ignore = column.ignore(); + this.convertType = column.type(); + } + + public ConvertColumnEntry(String name) { + this(name, false); + } + + public ConvertColumnEntry(String name, boolean ignore) { + this.name = name; + this.ignore = ignore; + this.convertType = ConvertType.ALL; + } + + public ConvertColumnEntry(String name, boolean ignore, ConvertType convertType) { + this.name = name; + this.ignore = ignore; + this.convertType = convertType; + } + + public ConvertColumnEntry(String name, int index, boolean ignore, ConvertType convertType) { + this.name = name; + this.index = index; + this.ignore = ignore; + this.convertType = convertType; + } + + public String name() { + return name == null ? "" : name; + } + + public void setName(String name) { + this.name = name; + } + + public boolean ignore() { + return ignore; + } + + public void setIgnore(boolean ignore) { + this.ignore = ignore; + } + + public ConvertType type() { + return convertType == null ? ConvertType.ALL : convertType; + } + + public void setConvertType(ConvertType convertType) { + this.convertType = convertType; + } + + public int getIndex() { + return index; + } + + public void setIndex(int index) { + this.index = index; + } + + @Override + public String toString() { + return "ConvertColumnEntry{" + "index=" + index + ", name=" + name + ", ignore=" + ignore + ", convertType=" + convertType + '}'; + } + +} diff --git a/src/main/java/org/redkale/convert/ConvertDisabled.java b/src/main/java/org/redkale/convert/ConvertDisabled.java index c3b86ffc2..4c6b7ee26 100644 --- a/src/main/java/org/redkale/convert/ConvertDisabled.java +++ b/src/main/java/org/redkale/convert/ConvertDisabled.java @@ -1,47 +1,47 @@ -/* - * 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.convert; - -import java.lang.annotation.*; -import static java.lang.annotation.ElementType.*; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * 搴忓垪鍖栨椂姘镐箙绂佺敤璇ュ瓧娈, 涓嶤onvertColumn.ignore()鐨勫尯鍒湪浜: ConvertDisabled涓嶈兘閫氳繃ConvertEntity鏉ヨВ绂 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@Target({METHOD, FIELD}) -@Retention(RUNTIME) -public @interface ConvertDisabled { - - /** - * 瑙f瀽/搴忓垪鍖栧畾鍒跺寲鐨凾YPE - * - * @return JSON or BSON or ALL - */ - ConvertType type() default ConvertType.ALL; - - /** - * ConvertDisabled 鐨勫鐢ㄧ被 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ - @Inherited - @Documented - @Target({METHOD, FIELD}) - @Retention(RUNTIME) - public static @interface ConvertDisableds { - - ConvertDisabled[] value(); - } -} +/* + * 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.convert; + +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * 搴忓垪鍖栨椂姘镐箙绂佺敤璇ュ瓧娈, 涓嶤onvertColumn.ignore()鐨勫尯鍒湪浜: ConvertDisabled涓嶈兘閫氳繃ConvertEntity鏉ヨВ绂 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@Target({METHOD, FIELD}) +@Retention(RUNTIME) +public @interface ConvertDisabled { + + /** + * 瑙f瀽/搴忓垪鍖栧畾鍒跺寲鐨凾YPE + * + * @return JSON or BSON or ALL + */ + ConvertType type() default ConvertType.ALL; + + /** + * ConvertDisabled 鐨勫鐢ㄧ被 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ + @Inherited + @Documented + @Target({METHOD, FIELD}) + @Retention(RUNTIME) + public static @interface ConvertDisableds { + + ConvertDisabled[] value(); + } +} diff --git a/src/main/java/org/redkale/convert/ConvertEntity.java b/src/main/java/org/redkale/convert/ConvertEntity.java index 5b831c95e..ee735b87f 100644 --- a/src/main/java/org/redkale/convert/ConvertEntity.java +++ b/src/main/java/org/redkale/convert/ConvertEntity.java @@ -1,33 +1,33 @@ -/* - * 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.convert; - -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; -import java.lang.annotation.*; - -/** - * 鐢ㄤ簬绫诲悕鐨勫埆鍚, 璇ュ煎繀椤绘槸鍏ㄥ眬鍞竴
- * 浣跨敤鍦烘櫙: 褰揃SON搴忓垪鍖栦负浜嗕笉鎸囧畾class鍙互浣跨敤@ConvertEntity鏉ュ彇涓埆鍚嶃傚叧鑱旀柟娉: Reader.readClassName() 鍜 Writer.writeClassName(String value) 銆 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@Inherited -@Documented -@Target({TYPE}) -@Retention(RUNTIME) -public @interface ConvertEntity { - - /** - * 鍒悕鍊 - * - * @return String - */ - String value(); -} +/* + * 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.convert; + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import java.lang.annotation.*; + +/** + * 鐢ㄤ簬绫诲悕鐨勫埆鍚, 璇ュ煎繀椤绘槸鍏ㄥ眬鍞竴
+ * 浣跨敤鍦烘櫙: 褰揃SON搴忓垪鍖栦负浜嗕笉鎸囧畾class鍙互浣跨敤@ConvertEntity鏉ュ彇涓埆鍚嶃傚叧鑱旀柟娉: Reader.readClassName() 鍜 Writer.writeClassName(String value) 銆 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@Inherited +@Documented +@Target({TYPE}) +@Retention(RUNTIME) +public @interface ConvertEntity { + + /** + * 鍒悕鍊 + * + * @return String + */ + String value(); +} diff --git a/src/main/java/org/redkale/convert/ConvertException.java b/src/main/java/org/redkale/convert/ConvertException.java index 4142f581b..31acf0e62 100644 --- a/src/main/java/org/redkale/convert/ConvertException.java +++ b/src/main/java/org/redkale/convert/ConvertException.java @@ -1,32 +1,32 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ -package org.redkale.convert; - -/** - * 搴忓垪鍖栬嚜瀹氫箟寮傚父绫 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public class ConvertException extends RuntimeException { - - public ConvertException() { - super(); - } - - public ConvertException(String s) { - super(s); - } - - public ConvertException(String message, Throwable cause) { - super(message, cause); - } - - public ConvertException(Throwable cause) { - super(cause); - } -} +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.convert; + +/** + * 搴忓垪鍖栬嚜瀹氫箟寮傚父绫 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public class ConvertException extends RuntimeException { + + public ConvertException() { + super(); + } + + public ConvertException(String s) { + super(s); + } + + public ConvertException(String message, Throwable cause) { + super(message, cause); + } + + public ConvertException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/org/redkale/convert/ConvertFactory.java b/src/main/java/org/redkale/convert/ConvertFactory.java index 30bae602b..4152bd357 100644 --- a/src/main/java/org/redkale/convert/ConvertFactory.java +++ b/src/main/java/org/redkale/convert/ConvertFactory.java @@ -1,879 +1,879 @@ -/* - * 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.convert; - -import java.io.File; -import java.lang.reflect.*; -import java.math.*; -import java.net.*; -import java.nio.ByteBuffer; -import java.nio.channels.CompletionHandler; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.*; -import java.util.regex.Pattern; -import java.util.stream.*; -import org.redkale.convert.bson.BsonConvert; -import org.redkale.convert.ext.*; -import org.redkale.convert.json.JsonConvert; -import org.redkale.util.*; - -/** - * 搴忓垪鍖栨ā鍧楃殑宸ュ巶绫伙紝鐢ㄤ簬娉ㄥ唽鑷畾涔夌殑搴忓垪鍖栫被鍨嬶紝鑾峰彇Convert - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Reader杈撳叆鐨勫瓙绫 - * @param Writer杈撳嚭鐨勫瓙绫 - */ -@SuppressWarnings("unchecked") -public abstract class ConvertFactory { - - private static final AtomicBoolean loaderInited = new AtomicBoolean(); - - private static Convert defProtobufConvert; - - private final ConvertFactory parent; - - protected Convert convert; - - protected boolean tiny; //String绫诲瀷鍊间负""锛孊oolean绫诲瀷鍊间负false鏃舵槸鍚﹂渶瑕佽緭鍑猴紝 榛樿涓簍rue - - private final Encodeable anyEncoder = new AnyEncoder(this); - - //----------------------------------------------------------------------------------- - private final ConcurrentHashMap creators = new ConcurrentHashMap(); - - private final ConcurrentHashMap entitys = new ConcurrentHashMap(); - - private final ConcurrentHashMap>> fieldCoders = new ConcurrentHashMap(); - - private final ConcurrentHashMap> decoders = new ConcurrentHashMap(); - - private final ConcurrentHashMap> encoders = new ConcurrentHashMap(); - - private final ConcurrentHashMap columnEntrys = new ConcurrentHashMap(); - - private final Set skipIgnores = new HashSet(); - - //key:闇瑕佸睆钄界殑瀛楁锛泇alue锛氭帓闄ょ殑瀛楁鍚 - private final ConcurrentHashMap> ignoreAlls = new ConcurrentHashMap(); - - private boolean skipAllIgnore = false; - - protected ConvertFactory(ConvertFactory parent, boolean tiny) { - this.tiny = tiny; - this.parent = parent; - if (parent == null) { - //--------------------------------------------------------- - - this.register(boolean.class, BoolSimpledCoder.instance); - this.register(Boolean.class, BoolSimpledCoder.instance); - - this.register(byte.class, ByteSimpledCoder.instance); - this.register(Byte.class, ByteSimpledCoder.instance); - - this.register(short.class, ShortSimpledCoder.instance); - this.register(Short.class, ShortSimpledCoder.instance); - - this.register(char.class, CharSimpledCoder.instance); - this.register(Character.class, CharSimpledCoder.instance); - - this.register(int.class, IntSimpledCoder.instance); - this.register(Integer.class, IntSimpledCoder.instance); - - this.register(long.class, LongSimpledCoder.instance); - this.register(Long.class, LongSimpledCoder.instance); - - this.register(float.class, FloatSimpledCoder.instance); - this.register(Float.class, FloatSimpledCoder.instance); - - this.register(double.class, DoubleSimpledCoder.instance); - this.register(Double.class, DoubleSimpledCoder.instance); - - this.register(Number.class, NumberSimpledCoder.instance); - this.register(String.class, StringSimpledCoder.instance); - this.register(StringWrapper.class, StringWrapperSimpledCoder.instance); - this.register(CharSequence.class, CharSequenceSimpledCoder.instance); - this.register(StringBuilder.class, CharSequenceSimpledCoder.StringBuilderSimpledCoder.instance); - this.register(java.util.Date.class, DateSimpledCoder.instance); - this.register(java.time.Instant.class, InstantSimpledCoder.instance); - this.register(java.time.LocalDate.class, LocalDateSimpledCoder.instance); - this.register(java.time.LocalTime.class, LocalTimeSimpledCoder.instance); - this.register(java.time.LocalDateTime.class, LocalDateTimeSimpledCoder.instance); - this.register(java.time.Duration.class, DurationSimpledCoder.instance); - this.register(AtomicInteger.class, AtomicIntegerSimpledCoder.instance); - this.register(AtomicLong.class, AtomicLongSimpledCoder.instance); - this.register(BigInteger.class, BigIntegerSimpledCoder.instance); - this.register(BigDecimal.class, BigDecimalSimpledCoder.instance); - this.register(InetAddress.class, InetAddressSimpledCoder.instance); - this.register(LongAdder.class, LongAdderSimpledCoder.instance); - this.register(DLong.class, DLongSimpledCoder.instance); - this.register(Class.class, TypeSimpledCoder.instance); - this.register(InetSocketAddress.class, InetAddressSimpledCoder.InetSocketAddressSimpledCoder.instance); - this.register(Pattern.class, PatternSimpledCoder.instance); - this.register(File.class, FileSimpledCoder.instance); - this.register(Throwable.class, ThrowableSimpledCoder.instance); - this.register(CompletionHandler.class, CompletionHandlerSimpledCoder.instance); - this.register(URL.class, URLSimpledCoder.instance); - this.register(URI.class, URISimpledCoder.instance); - //--------------------------------------------------------- - this.register(ByteBuffer.class, ByteBufferSimpledCoder.instance); - this.register(boolean[].class, BoolArraySimpledCoder.instance); - this.register(byte[].class, ByteArraySimpledCoder.instance); - this.register(short[].class, ShortArraySimpledCoder.instance); - this.register(char[].class, CharArraySimpledCoder.instance); - this.register(int[].class, IntArraySimpledCoder.instance); - this.register(IntStream.class, IntArraySimpledCoder.IntStreamSimpledCoder.instance); - this.register(long[].class, LongArraySimpledCoder.instance); - this.register(LongStream.class, LongArraySimpledCoder.LongStreamSimpledCoder.instance); - this.register(float[].class, FloatArraySimpledCoder.instance); - this.register(double[].class, DoubleArraySimpledCoder.instance); - this.register(DoubleStream.class, DoubleArraySimpledCoder.DoubleStreamSimpledCoder.instance); - this.register(String[].class, StringArraySimpledCoder.instance); - //--------------------------------------------------------- - this.register(AnyValue.class, Creator.create(AnyValue.DefaultAnyValue.class)); - this.register(HttpCookie.class, new Creator() { - @Override - @ConstructorParameters({"name", "value"}) - public HttpCookie create(Object... params) { - return new HttpCookie((String) params[0], (String) params[1]); - } - - }); - try { - Class sqldateClass = Thread.currentThread().getContextClassLoader().loadClass("java.sql.Date"); - Invoker sqldateInvoker = Invoker.create(sqldateClass, "valueOf", String.class); - this.register(sqldateClass, new SimpledCoder() { - - @Override - public void convertTo(W out, Object value) { - out.writeSmallString(value == null ? null : value.toString()); - } - - @Override - public Object convertFrom(R in) { - String t = in.readSmallString(); - return t == null ? null : sqldateInvoker.invoke(null, t); - } - - }); - Class sqltimeClass = Thread.currentThread().getContextClassLoader().loadClass("java.sql.Time"); - Invoker sqltimeInvoker = Invoker.create(sqltimeClass, "valueOf", String.class); - this.register(sqltimeClass, new SimpledCoder() { - - @Override - public void convertTo(W out, Object value) { - out.writeSmallString(value == null ? null : value.toString()); - } - - @Override - public Object convertFrom(R in) { - String t = in.readSmallString(); - return t == null ? null : sqltimeInvoker.invoke(null, t); - } - - }); - Class timestampClass = Thread.currentThread().getContextClassLoader().loadClass("java.sql.Timestamp"); - Invoker timestampInvoker = Invoker.create(timestampClass, "valueOf", String.class); - this.register(timestampClass, new SimpledCoder() { - - @Override - public void convertTo(W out, Object value) { - out.writeSmallString(value == null ? null : value.toString()); - } - - @Override - public Object convertFrom(R in) { - String t = in.readSmallString(); - return t == null ? null : timestampInvoker.invoke(null, t); - } - - }); - } catch (Throwable t) { - } - } - } - - public ConvertFactory parent() { - return this.parent; - } - - public static Convert findConvert(ConvertType type) { - if (type == null) return null; - if (type == ConvertType.JSON) return JsonConvert.root(); - if (type == ConvertType.BSON) return BsonConvert.root(); - if (loaderInited.get()) { - if (type == ConvertType.PROTOBUF) return defProtobufConvert; - } - synchronized (loaderInited) { - if (!loaderInited.get()) { - Iterator it = ServiceLoader.load(ConvertProvider.class).iterator(); - RedkaleClassLoader.putServiceLoader(ConvertProvider.class); - while (it.hasNext()) { - ConvertProvider cl = it.next(); - RedkaleClassLoader.putReflectionPublicConstructors(cl.getClass(), cl.getClass().getName()); - if (cl.type() == ConvertType.PROTOBUF) defProtobufConvert = cl.convert(); - } - loaderInited.set(true); - } - } - return type == ConvertType.PROTOBUF ? defProtobufConvert : null; - } - - protected static boolean getSystemPropertyBoolean(String key, String parentkey, boolean defvalue) { - return Boolean.parseBoolean(System.getProperty(key, System.getProperty(parentkey, String.valueOf(defvalue)))); - } - - public abstract ConvertType getConvertType(); - - public abstract boolean isReversible(); //鏄惁鍙嗙殑 - - public abstract boolean isFieldSort(); //褰揅onvertColumn.index鐩稿悓鏃舵槸鍚︽寜瀛楁鍚嶇О鎺掑簭 - - public abstract ConvertFactory createChild(); - - public abstract ConvertFactory createChild(boolean tiny); - - protected SimpledCoder createEnumSimpledCoder(Class enumClass) { - return new EnumSimpledCoder(enumClass); - } - - protected Type formatObjectType(Type type) { - if (type instanceof Class) { - Class clazz = (Class) type; - ConvertImpl ci = clazz.getAnnotation(ConvertImpl.class); - if (ci != null) { - if (!Modifier.isAbstract(clazz.getModifiers()) && !Modifier.isInterface(clazz.getModifiers())) { - throw new ConvertException("@" + ConvertImpl.class.getSimpleName() + " must at interface or abstract class, but " + clazz + " not"); - } - Class impl = ci.value(); - if (Modifier.isAbstract(impl.getModifiers()) || Modifier.isInterface(impl.getModifiers())) { - throw new ConvertException("@" + ConvertImpl.class.getSimpleName() + " at class " + impl + " cannot be interface or abstract class"); - } - return impl; - } - } - return type; - } - - protected Encodeable createDyncEncoder(Type type) { - return null; - } - - protected ObjectDecoder createObjectDecoder(Type type) { - return new ObjectDecoder(type); - } - - protected ObjectEncoder createObjectEncoder(Type type) { - return new ObjectEncoder(type); - } - - protected Decodeable createMapDecoder(Type type) { - return new MapDecoder(this, type); - } - - protected Encodeable createMapEncoder(Type type) { - return new MapEncoder(this, type); - } - - protected Decodeable createArrayDecoder(Type type) { - return new ArrayDecoder(this, type); - } - - protected Encodeable createArrayEncoder(Type type) { - return new ArrayEncoder(this, type); - } - - protected Decodeable createCollectionDecoder(Type type) { - return new CollectionDecoder(this, type); - } - - protected Encodeable createCollectionEncoder(Type type) { - return new CollectionEncoder(this, type); - } - - protected Decodeable createStreamDecoder(Type type) { - return new StreamDecoder(this, type); - } - - protected Encodeable createStreamEncoder(Type type) { - return new StreamEncoder(this, type); - } - - public Convert getConvert() { - return convert; - } - - public ConvertFactory tiny(boolean tiny) { - this.tiny = tiny; - return this; - } - - public boolean isConvertDisabled(AccessibleObject element) { - ConvertDisabled[] ccs = element.getAnnotationsByType(ConvertDisabled.class); - if (ccs.length == 0 && element instanceof Method) { - final Method method = (Method) element; - String fieldName = readGetSetFieldName(method); - if (fieldName != null) { - try { - ccs = method.getDeclaringClass().getDeclaredField(fieldName).getAnnotationsByType(ConvertDisabled.class); - } catch (Exception e) { //璇存槑娌℃湁璇ュ瓧娈碉紝蹇界暐寮傚父 - } - } - } - final ConvertType ct = this.getConvertType(); - for (ConvertDisabled ref : ccs) { - if (ref.type().contains(ct)) return true; - } - return false; - } - - public ConvertColumnEntry findRef(Class clazz, AccessibleObject element) { - if (element == null) return null; - ConvertColumnEntry en = this.columnEntrys.get(element); - Set onlyColumns = ignoreAlls.get(clazz); - if (en != null && onlyColumns == null) return en; - final ConvertType ct = this.getConvertType(); - ConvertColumn[] ccs = element.getAnnotationsByType(ConvertColumn.class); - String fieldName = null; - if (ccs.length == 0 && element instanceof Method) { - final Method method = (Method) element; - fieldName = readGetSetFieldName(method); - if (fieldName != null) { - Class mclz = method.getDeclaringClass(); - do { - try { - ccs = mclz.getDeclaredField(fieldName).getAnnotationsByType(ConvertColumn.class); - break; - } catch (Exception e) { //璇存槑娌℃湁璇ュ瓧娈碉紝蹇界暐寮傚父 - } - } while (mclz != Object.class && (mclz = mclz.getSuperclass()) != Object.class); - } - } - if (onlyColumns != null && fieldName == null) { - if (element instanceof Method) { - fieldName = readGetSetFieldName((Method) element); - } else if (element instanceof Field) { - fieldName = ((Field) element).getName(); - } - } - if (ccs.length == 0 && onlyColumns != null && fieldName != null) { - if (!onlyColumns.contains(fieldName)) return new ConvertColumnEntry(fieldName, true); - } - for (ConvertColumn ref : ccs) { - if (ref.type().contains(ct)) { - String realName = ref.name().isEmpty() ? fieldName : ref.name(); - if (onlyColumns != null && fieldName != null) { - if (!onlyColumns.contains(realName)) return new ConvertColumnEntry(realName, true); - } - ConvertColumnEntry entry = new ConvertColumnEntry(ref); - if (skipAllIgnore) { - entry.setIgnore(false); - return entry; - } - if (skipIgnores.isEmpty()) { - if (onlyColumns != null && realName != null && onlyColumns.contains(realName)) entry.setIgnore(false); - return entry; - } - if (skipIgnores.contains(((Member) element).getDeclaringClass())) entry.setIgnore(false); - return entry; - } - } - return null; - } - - static Field readGetSetField(Method method) { - String name = readGetSetFieldName(method); - if (name == null) return null; - try { - return method.getDeclaringClass().getDeclaredField(name); - } catch (Exception e) { - return null; - } - } - - static String readGetSetFieldName(Method method) { - if (method == null) return null; - String fname = method.getName(); - if (!fname.startsWith("is") && !fname.startsWith("get") && !fname.startsWith("set")) return fname; //record绫讳細鐩存帴鐢╢ield鍚嶄綔涓簃ethod鍚 - fname = fname.substring(fname.startsWith("is") ? 2 : 3); - if (fname.length() > 1 && !(fname.charAt(1) >= 'A' && fname.charAt(1) <= 'Z')) { - fname = Character.toLowerCase(fname.charAt(0)) + fname.substring(1); - } else if (fname.length() == 1) { - fname = "" + Character.toLowerCase(fname.charAt(0)); - } - return fname; - } - - final String getEntityAlias(Class clazz) { - if (clazz == String.class) return "A"; - if (clazz == int.class) return "I"; - if (clazz == Integer.class) return "i"; - if (clazz == long.class) return "J"; - if (clazz == Long.class) return "j"; - if (clazz == byte.class) return "B"; - if (clazz == Byte.class) return "b"; - if (clazz == boolean.class) return "Z"; - if (clazz == Boolean.class) return "z"; - if (clazz == short.class) return "S"; - if (clazz == Short.class) return "s"; - if (clazz == char.class) return "C"; - if (clazz == Character.class) return "c"; - if (clazz == float.class) return "F"; - if (clazz == Float.class) return "f"; - if (clazz == double.class) return "D"; - if (clazz == Double.class) return "d"; - - if (clazz == String[].class) return "[A"; - if (clazz == int[].class) return "[I"; - if (clazz == long[].class) return "[J"; - if (clazz == byte[].class) return "[B"; - if (clazz == boolean[].class) return "[Z"; - if (clazz == short[].class) return "[S"; - if (clazz == char[].class) return "[C"; - if (clazz == float[].class) return "[F"; - if (clazz == double[].class) return "[D"; - - ConvertEntity ce = (ConvertEntity) clazz.getAnnotation(ConvertEntity.class); - if (ce != null && findEntityAlias(ce.value()) == null) entitys.put(ce.value(), clazz); - return ce == null ? clazz.getName() : ce.value(); - } - - final Class getEntityAlias(String name) { - if ("A".equals(name)) return String.class; - if ("I".equals(name)) return int.class; - if ("i".equals(name)) return Integer.class; - if ("J".equals(name)) return long.class; - if ("j".equals(name)) return Long.class; - if ("B".equals(name)) return byte.class; - if ("b".equals(name)) return Byte.class; - if ("Z".equals(name)) return boolean.class; - if ("z".equals(name)) return Boolean.class; - if ("S".equals(name)) return short.class; - if ("s".equals(name)) return Short.class; - if ("C".equals(name)) return char.class; - if ("c".equals(name)) return Character.class; - if ("F".equals(name)) return float.class; - if ("f".equals(name)) return Float.class; - if ("D".equals(name)) return double.class; - if ("d".equals(name)) return Double.class; - - if ("[A".equals(name)) return String[].class; - if ("[I".equals(name)) return int[].class; - if ("[J".equals(name)) return long[].class; - if ("[B".equals(name)) return byte[].class; - if ("[Z".equals(name)) return boolean[].class; - if ("[S".equals(name)) return short[].class; - if ("[C".equals(name)) return char[].class; - if ("[F".equals(name)) return float[].class; - if ("[D".equals(name)) return double[].class; - - Class clazz = findEntityAlias(name); - try { - return clazz == null ? Thread.currentThread().getContextClassLoader().loadClass(name) : clazz; - } catch (Exception ex) { - throw new ConvertException("convert entity is " + name, ex); - } - } - - private Class findEntityAlias(String name) { - Class clazz = entitys.get(name); - return parent == null ? clazz : parent.findEntityAlias(name); - } - - /** - * 浣挎墍鏈夌被鐨勬墍鏈夎澹版槑涓篊onvertColumn.ignore = true 鐨勫瓧娈垫垨鏂规硶鍙樹负ConvertColumn.ignore = false - * - * @param skipIgnore 鏄惁蹇界暐Ignore娉ㄨВ - */ - public final void registerSkipAllIgnore(final boolean skipIgnore) { - this.skipAllIgnore = skipIgnore; - } - - /** - * 浣挎墍鏈夌被鐨勬墍鏈夎澹版槑涓篊onvertColumn.ignore = true 鐨勫瓧娈垫垨鏂规硶鍙樹负ConvertColumn.ignore = false - * - * @param skipIgnore 蹇界暐ignore - * - * @return 鑷韩 - */ - public ConvertFactory skipAllIgnore(final boolean skipIgnore) { - this.skipAllIgnore = skipIgnore; - return this; - } - - /** - * 浣胯绫绘墍鏈夎澹版槑涓篊onvertColumn.ignore = true 鐨勫瓧娈垫垨鏂规硶鍙樹负ConvertColumn.ignore = false - * - * @param type 鎸囧畾鐨勭被 - */ - public final void registerSkipIgnore(final Class type) { - skipIgnores.add(type); - } - - /** - * 灞忚斀鎸囧畾绫绘墍鏈夊瓧娈碉紝浠呬粎淇濈暀鎸囧畾瀛楁
- * 娉ㄦ剰: 璇ラ厤缃紭鍏堢骇楂樹簬skipAllIgnore鍜孋onvertColumnEntry閰嶇疆 - * - * @param type 鎸囧畾鐨勭被 - * @param excludeColumns 闇瑕佹帓闄ょ殑瀛楁鍚 - */ - public final void registerIgnoreAll(final Class type, String... excludeColumns) { - Set set = ignoreAlls.get(type); - if (set == null) { - ignoreAlls.put(type, new HashSet<>(Arrays.asList(excludeColumns))); - } else { - set.addAll(Arrays.asList(excludeColumns)); - } - } - - public final void registerIgnoreAll(final Class type, Collection excludeColumns) { - Set set = ignoreAlls.get(type); - if (set == null) { - ignoreAlls.put(type, new HashSet<>(excludeColumns)); - } else { - set.addAll(new ArrayList(excludeColumns)); - } - } - - public final void register(final Class type, boolean ignore, String... columns) { - for (String column : columns) { - register(type, column, new ConvertColumnEntry(column, ignore)); - } - } - - public final void register(final Class type, boolean ignore, Collection columns) { - for (String column : columns) { - register(type, column, new ConvertColumnEntry(column, ignore)); - } - } - - public final boolean register(final Class type, String column, String alias) { - return register(type, column, new ConvertColumnEntry(alias)); - } - - public final boolean register(final Class type, String column, ConvertColumnEntry entry) { - if (type == null || column == null || entry == null) return false; - Field field = null; - try { - field = type.getDeclaredField(column); - } catch (Exception e) { - } - String get = "get"; - if (field != null && (field.getType() == boolean.class || field.getType() == Boolean.class)) get = "is"; - char[] cols = column.toCharArray(); - cols[0] = Character.toUpperCase(cols[0]); - final String bigColumn = new String(cols); - try { - register(type.getMethod(get + bigColumn), entry); - } catch (NoSuchMethodException mex) { - if (get.length() >= 3) { //get - try { - register(type.getMethod("is" + bigColumn), entry); - } catch (Exception ex) { - } - } - } catch (Exception ex) { - } - try { - register(type.getMethod("set" + bigColumn, field.getType()), entry); - } catch (Exception ex) { - } - return field == null ? true : register(field, entry); - } - - public final boolean register(final AccessibleObject field, final ConvertColumnEntry entry) { - if (field == null || entry == null) return false; - this.columnEntrys.put(field, entry); - return true; - } - - public final void reloadCoder(final Type type) { - this.register(type, this.createDecoder(type)); - this.register(type, this.createEncoder(type)); - } - - public final void reloadCoder(final Type type, final Class clazz) { - this.register(type, this.createDecoder(type, clazz)); - this.register(type, this.createEncoder(type, clazz)); - } - - public final void register(final Class clazz, final Creator creator) { - creators.put(clazz, creator); - } - - public final Creator findCreator(Class type) { - Creator creator = creators.get(type); - if (creator != null) return creator; - return this.parent == null ? null : this.parent.findCreator(type); - } - - public final Creator loadCreator(Class type) { - Creator result = findCreator(type); - if (result == null) { - result = Creator.create(type); - if (result != null) creators.put(type, result); - } - return result; - } - - //---------------------------------------------------------------------- - public final Encodeable getAnyEncoder() { - return (Encodeable) anyEncoder; - } - - public final void register(final Type clazz, final SimpledCoder coder) { - decoders.put(clazz, coder); - encoders.put(clazz, coder); - } - - public final void register(final Type clazz, final Decodeable decoder, final Encodeable encoder) { - decoders.put(clazz, decoder); - encoders.put(clazz, encoder); - } - - public final void register(final Type clazz, final Decodeable decoder) { - decoders.put(clazz, decoder); - } - - public final void register(final Type clazz, final Encodeable encoder) { - encoders.put(clazz, encoder); - } - - //coder = null琛ㄧず鍒犻櫎璇ュ瓧娈电殑鎸囧畾SimpledCoder - public final void register(final Class clazz, final String field, final SimpledCoder coder) { - if (field == null || clazz == null) return; - try { - clazz.getDeclaredField(field); - } catch (Exception e) { - throw new RuntimeException(clazz + " not found field(" + field + ")"); - } - if (coder == null) { - Map map = this.fieldCoders.get(clazz); - if (map != null) map.remove(field); - } else { - this.fieldCoders.computeIfAbsent(clazz, c -> new ConcurrentHashMap<>()).put(field, coder); - } - } - - public final SimpledCoder findFieldCoder(final Type clazz, final String field) { - if (field == null) return null; - Map> map = this.fieldCoders.get(clazz); - if (map == null) return parent == null ? null : parent.findFieldCoder(clazz, field); - return (SimpledCoder) map.get(field); - } - - public final Decodeable findDecoder(final Type type) { - Decodeable rs = (Decodeable) decoders.get(type); - if (rs != null) return rs; - return this.parent == null ? null : this.parent.findDecoder(type); - } - - public final Encodeable findEncoder(final Type type) { - Encodeable rs = (Encodeable) encoders.get(type); - if (rs != null) return rs; - return this.parent == null ? null : this.parent.findEncoder(type); - } - - public final Decodeable loadDecoder(final Type type) { - Decodeable decoder = findDecoder(type); - if (decoder != null) return decoder; - if (type instanceof GenericArrayType) return createArrayDecoder(type); - Class clazz; - if (type instanceof ParameterizedType) { - final ParameterizedType pts = (ParameterizedType) type; - clazz = (Class) (pts).getRawType(); - } else if (type instanceof TypeVariable) { // e.g. - final TypeVariable tv = (TypeVariable) type; - Class cz = tv.getBounds().length == 0 ? Object.class : null; - for (Type f : tv.getBounds()) { - if (f instanceof Class) { - cz = (Class) f; - break; - } - } - clazz = cz; - if (cz == null) throw new ConvertException("not support the type (" + type + ")"); - } else if (type instanceof WildcardType) { // e.g. - final WildcardType wt = (WildcardType) type; - Class cz = null; - for (Type f : wt.getUpperBounds()) { - if (f instanceof Class) { - cz = (Class) f; - break; - } - } - clazz = cz; - if (cz == null) throw new ConvertException("not support the type (" + type + ")"); - } else if (type instanceof Class) { - clazz = (Class) type; - } else { - throw new ConvertException("not support the type (" + type + ")"); - } - //姝ゅ涓嶈兘鍐峟indDecoder锛屽惁鍒檛ype涓巆lass涓嶄竴鑷, 濡: RetResult 鍜 RetResult - return createDecoder(type, clazz); - } - - public final Decodeable createDecoder(final Type type) { - Class clazz; - if (type instanceof ParameterizedType) { - final ParameterizedType pts = (ParameterizedType) type; - clazz = (Class) (pts).getRawType(); - } else if (type instanceof Class) { - clazz = (Class) type; - } else { - throw new ConvertException("not support the type (" + type + ")"); - } - return createDecoder(type, clazz); - } - - private Decodeable createDecoder(final Type type, final Class clazz) { - Decodeable decoder = null; - ObjectDecoder od = null; - if (clazz.isEnum()) { - decoder = createEnumSimpledCoder(clazz); - } else if (clazz.isArray()) { - decoder = createArrayDecoder(type); - } else if (Collection.class.isAssignableFrom(clazz)) { - decoder = createCollectionDecoder(type); - } else if (Stream.class.isAssignableFrom(clazz)) { - decoder = createStreamDecoder(type); - } else if (Map.class.isAssignableFrom(clazz)) { - decoder = createMapDecoder(type); - } else if (Optional.class == clazz) { - decoder = new OptionalCoder(this, type); - } else if (clazz == Object.class) { - od = createObjectDecoder(type); - decoder = od; - } else if (!clazz.getName().startsWith("java.") - || java.net.HttpCookie.class == clazz - || java.util.AbstractMap.SimpleEntry.class == clazz - || clazz.getName().startsWith("java.awt.geom.Point2D")) { - Decodeable simpleCoder = null; - for (final Method method : clazz.getDeclaredMethods()) { - if (!Modifier.isStatic(method.getModifiers())) continue; - Class[] paramTypes = method.getParameterTypes(); - if (paramTypes.length != 1) continue; - if (paramTypes[0] != ConvertFactory.class && paramTypes[0] != this.getClass()) continue; - if (!Decodeable.class.isAssignableFrom(method.getReturnType())) continue; - try { - method.setAccessible(true); - simpleCoder = (Decodeable) method.invoke(null, this); - RedkaleClassLoader.putReflectionDeclaredMethods(clazz.getName()); - RedkaleClassLoader.putReflectionMethod(clazz.getName(), method); - break; - } catch (Exception e) { - } - } - if (simpleCoder == null) { - Type impl = formatObjectType(type); - od = createObjectDecoder(impl); - decoder = od; - } else { - decoder = simpleCoder; - } - } - if (decoder == null) throw new ConvertException("not support the type (" + type + ")"); - register(type, decoder); - if (od != null) od.init(this); - return decoder; - } - - public final Encodeable loadEncoder(final Type type) { - Encodeable encoder = findEncoder(type); - if (encoder != null) return encoder; - if (type instanceof GenericArrayType) return createArrayEncoder(type); - Class clazz; - if (type instanceof ParameterizedType) { - final ParameterizedType pts = (ParameterizedType) type; - clazz = (Class) (pts).getRawType(); - } else if (type instanceof TypeVariable) { - TypeVariable tv = (TypeVariable) type; - Type t = Object.class; - if (tv.getBounds().length == 1) { - t = tv.getBounds()[0]; - } - if (!(t instanceof Class)) t = Object.class; - clazz = (Class) t; - } else if (type instanceof Class) { - clazz = (Class) type; - } else { - throw new ConvertException("not support the type (" + type + ")"); - } - //姝ゅ涓嶈兘鍐峟indEncoder锛屽惁鍒檛ype涓巆lass涓嶄竴鑷, 濡: RetResult 鍜 RetResult - return createEncoder(type, clazz); - } - - public final Encodeable createEncoder(final Type type) { - Class clazz; - if (type instanceof ParameterizedType) { - final ParameterizedType pts = (ParameterizedType) type; - clazz = (Class) (pts).getRawType(); - } else if (type instanceof Class) { - clazz = (Class) type; - } else { - throw new ConvertException("not support the type (" + type + ")"); - } - return createEncoder(type, clazz); - } - - private Encodeable createEncoder(final Type type, final Class clazz) { - Encodeable encoder = null; - ObjectEncoder oe = null; - if (clazz.isEnum()) { - encoder = createEnumSimpledCoder(clazz); - } else if (clazz.isArray()) { - encoder = createArrayEncoder(type); - } else if (Collection.class.isAssignableFrom(clazz)) { - encoder = createCollectionEncoder(type); - } else if (Stream.class.isAssignableFrom(clazz)) { - encoder = createStreamEncoder(type); - } else if (Map.class.isAssignableFrom(clazz)) { - encoder = createMapEncoder(type); - } else if (Optional.class == clazz) { - encoder = new OptionalCoder(this, type); - } else if (clazz == Object.class) { - return (Encodeable) this.anyEncoder; - } else if (!clazz.getName().startsWith("java.") || java.net.HttpCookie.class == clazz - || java.util.Map.Entry.class == clazz || java.util.AbstractMap.SimpleEntry.class == clazz) { - Encodeable simpleCoder = null; - for (final Method method : clazz.getDeclaredMethods()) { - if (!Modifier.isStatic(method.getModifiers())) continue; - Class[] paramTypes = method.getParameterTypes(); - if (paramTypes.length != 1) continue; - if (paramTypes[0] != ConvertFactory.class && paramTypes[0] != this.getClass()) continue; - if (!Encodeable.class.isAssignableFrom(method.getReturnType())) continue; - try { - method.setAccessible(true); - simpleCoder = (Encodeable) method.invoke(null, this); - RedkaleClassLoader.putReflectionDeclaredMethods(clazz.getName()); - RedkaleClassLoader.putReflectionMethod(clazz.getName(), method); - break; - } catch (Exception e) { - } - } - if (simpleCoder == null) { - Type impl = formatObjectType(type); - encoder = createDyncEncoder(impl); - if (encoder == null) { - oe = createObjectEncoder(impl); - encoder = oe; - } - } else { - encoder = simpleCoder; - } - } - if (encoder == null) throw new ConvertException("not support the type (" + type + ")"); - register(type, encoder); - if (oe != null) oe.init(this); - return encoder; - - } - -} +/* + * 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.convert; + +import java.io.File; +import java.lang.reflect.*; +import java.math.*; +import java.net.*; +import java.nio.ByteBuffer; +import java.nio.channels.CompletionHandler; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.*; +import java.util.regex.Pattern; +import java.util.stream.*; +import org.redkale.convert.bson.BsonConvert; +import org.redkale.convert.ext.*; +import org.redkale.convert.json.JsonConvert; +import org.redkale.util.*; + +/** + * 搴忓垪鍖栨ā鍧楃殑宸ュ巶绫伙紝鐢ㄤ簬娉ㄥ唽鑷畾涔夌殑搴忓垪鍖栫被鍨嬶紝鑾峰彇Convert + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Reader杈撳叆鐨勫瓙绫 + * @param Writer杈撳嚭鐨勫瓙绫 + */ +@SuppressWarnings("unchecked") +public abstract class ConvertFactory { + + private static final AtomicBoolean loaderInited = new AtomicBoolean(); + + private static Convert defProtobufConvert; + + private final ConvertFactory parent; + + protected Convert convert; + + protected boolean tiny; //String绫诲瀷鍊间负""锛孊oolean绫诲瀷鍊间负false鏃舵槸鍚﹂渶瑕佽緭鍑猴紝 榛樿涓簍rue + + private final Encodeable anyEncoder = new AnyEncoder(this); + + //----------------------------------------------------------------------------------- + private final ConcurrentHashMap creators = new ConcurrentHashMap(); + + private final ConcurrentHashMap entitys = new ConcurrentHashMap(); + + private final ConcurrentHashMap>> fieldCoders = new ConcurrentHashMap(); + + private final ConcurrentHashMap> decoders = new ConcurrentHashMap(); + + private final ConcurrentHashMap> encoders = new ConcurrentHashMap(); + + private final ConcurrentHashMap columnEntrys = new ConcurrentHashMap(); + + private final Set skipIgnores = new HashSet(); + + //key:闇瑕佸睆钄界殑瀛楁锛泇alue锛氭帓闄ょ殑瀛楁鍚 + private final ConcurrentHashMap> ignoreAlls = new ConcurrentHashMap(); + + private boolean skipAllIgnore = false; + + protected ConvertFactory(ConvertFactory parent, boolean tiny) { + this.tiny = tiny; + this.parent = parent; + if (parent == null) { + //--------------------------------------------------------- + + this.register(boolean.class, BoolSimpledCoder.instance); + this.register(Boolean.class, BoolSimpledCoder.instance); + + this.register(byte.class, ByteSimpledCoder.instance); + this.register(Byte.class, ByteSimpledCoder.instance); + + this.register(short.class, ShortSimpledCoder.instance); + this.register(Short.class, ShortSimpledCoder.instance); + + this.register(char.class, CharSimpledCoder.instance); + this.register(Character.class, CharSimpledCoder.instance); + + this.register(int.class, IntSimpledCoder.instance); + this.register(Integer.class, IntSimpledCoder.instance); + + this.register(long.class, LongSimpledCoder.instance); + this.register(Long.class, LongSimpledCoder.instance); + + this.register(float.class, FloatSimpledCoder.instance); + this.register(Float.class, FloatSimpledCoder.instance); + + this.register(double.class, DoubleSimpledCoder.instance); + this.register(Double.class, DoubleSimpledCoder.instance); + + this.register(Number.class, NumberSimpledCoder.instance); + this.register(String.class, StringSimpledCoder.instance); + this.register(StringWrapper.class, StringWrapperSimpledCoder.instance); + this.register(CharSequence.class, CharSequenceSimpledCoder.instance); + this.register(StringBuilder.class, CharSequenceSimpledCoder.StringBuilderSimpledCoder.instance); + this.register(java.util.Date.class, DateSimpledCoder.instance); + this.register(java.time.Instant.class, InstantSimpledCoder.instance); + this.register(java.time.LocalDate.class, LocalDateSimpledCoder.instance); + this.register(java.time.LocalTime.class, LocalTimeSimpledCoder.instance); + this.register(java.time.LocalDateTime.class, LocalDateTimeSimpledCoder.instance); + this.register(java.time.Duration.class, DurationSimpledCoder.instance); + this.register(AtomicInteger.class, AtomicIntegerSimpledCoder.instance); + this.register(AtomicLong.class, AtomicLongSimpledCoder.instance); + this.register(BigInteger.class, BigIntegerSimpledCoder.instance); + this.register(BigDecimal.class, BigDecimalSimpledCoder.instance); + this.register(InetAddress.class, InetAddressSimpledCoder.instance); + this.register(LongAdder.class, LongAdderSimpledCoder.instance); + this.register(DLong.class, DLongSimpledCoder.instance); + this.register(Class.class, TypeSimpledCoder.instance); + this.register(InetSocketAddress.class, InetAddressSimpledCoder.InetSocketAddressSimpledCoder.instance); + this.register(Pattern.class, PatternSimpledCoder.instance); + this.register(File.class, FileSimpledCoder.instance); + this.register(Throwable.class, ThrowableSimpledCoder.instance); + this.register(CompletionHandler.class, CompletionHandlerSimpledCoder.instance); + this.register(URL.class, URLSimpledCoder.instance); + this.register(URI.class, URISimpledCoder.instance); + //--------------------------------------------------------- + this.register(ByteBuffer.class, ByteBufferSimpledCoder.instance); + this.register(boolean[].class, BoolArraySimpledCoder.instance); + this.register(byte[].class, ByteArraySimpledCoder.instance); + this.register(short[].class, ShortArraySimpledCoder.instance); + this.register(char[].class, CharArraySimpledCoder.instance); + this.register(int[].class, IntArraySimpledCoder.instance); + this.register(IntStream.class, IntArraySimpledCoder.IntStreamSimpledCoder.instance); + this.register(long[].class, LongArraySimpledCoder.instance); + this.register(LongStream.class, LongArraySimpledCoder.LongStreamSimpledCoder.instance); + this.register(float[].class, FloatArraySimpledCoder.instance); + this.register(double[].class, DoubleArraySimpledCoder.instance); + this.register(DoubleStream.class, DoubleArraySimpledCoder.DoubleStreamSimpledCoder.instance); + this.register(String[].class, StringArraySimpledCoder.instance); + //--------------------------------------------------------- + this.register(AnyValue.class, Creator.create(AnyValue.DefaultAnyValue.class)); + this.register(HttpCookie.class, new Creator() { + @Override + @ConstructorParameters({"name", "value"}) + public HttpCookie create(Object... params) { + return new HttpCookie((String) params[0], (String) params[1]); + } + + }); + try { + Class sqldateClass = Thread.currentThread().getContextClassLoader().loadClass("java.sql.Date"); + Invoker sqldateInvoker = Invoker.create(sqldateClass, "valueOf", String.class); + this.register(sqldateClass, new SimpledCoder() { + + @Override + public void convertTo(W out, Object value) { + out.writeSmallString(value == null ? null : value.toString()); + } + + @Override + public Object convertFrom(R in) { + String t = in.readSmallString(); + return t == null ? null : sqldateInvoker.invoke(null, t); + } + + }); + Class sqltimeClass = Thread.currentThread().getContextClassLoader().loadClass("java.sql.Time"); + Invoker sqltimeInvoker = Invoker.create(sqltimeClass, "valueOf", String.class); + this.register(sqltimeClass, new SimpledCoder() { + + @Override + public void convertTo(W out, Object value) { + out.writeSmallString(value == null ? null : value.toString()); + } + + @Override + public Object convertFrom(R in) { + String t = in.readSmallString(); + return t == null ? null : sqltimeInvoker.invoke(null, t); + } + + }); + Class timestampClass = Thread.currentThread().getContextClassLoader().loadClass("java.sql.Timestamp"); + Invoker timestampInvoker = Invoker.create(timestampClass, "valueOf", String.class); + this.register(timestampClass, new SimpledCoder() { + + @Override + public void convertTo(W out, Object value) { + out.writeSmallString(value == null ? null : value.toString()); + } + + @Override + public Object convertFrom(R in) { + String t = in.readSmallString(); + return t == null ? null : timestampInvoker.invoke(null, t); + } + + }); + } catch (Throwable t) { + } + } + } + + public ConvertFactory parent() { + return this.parent; + } + + public static Convert findConvert(ConvertType type) { + if (type == null) return null; + if (type == ConvertType.JSON) return JsonConvert.root(); + if (type == ConvertType.BSON) return BsonConvert.root(); + if (loaderInited.get()) { + if (type == ConvertType.PROTOBUF) return defProtobufConvert; + } + synchronized (loaderInited) { + if (!loaderInited.get()) { + Iterator it = ServiceLoader.load(ConvertProvider.class).iterator(); + RedkaleClassLoader.putServiceLoader(ConvertProvider.class); + while (it.hasNext()) { + ConvertProvider cl = it.next(); + RedkaleClassLoader.putReflectionPublicConstructors(cl.getClass(), cl.getClass().getName()); + if (cl.type() == ConvertType.PROTOBUF) defProtobufConvert = cl.convert(); + } + loaderInited.set(true); + } + } + return type == ConvertType.PROTOBUF ? defProtobufConvert : null; + } + + protected static boolean getSystemPropertyBoolean(String key, String parentkey, boolean defvalue) { + return Boolean.parseBoolean(System.getProperty(key, System.getProperty(parentkey, String.valueOf(defvalue)))); + } + + public abstract ConvertType getConvertType(); + + public abstract boolean isReversible(); //鏄惁鍙嗙殑 + + public abstract boolean isFieldSort(); //褰揅onvertColumn.index鐩稿悓鏃舵槸鍚︽寜瀛楁鍚嶇О鎺掑簭 + + public abstract ConvertFactory createChild(); + + public abstract ConvertFactory createChild(boolean tiny); + + protected SimpledCoder createEnumSimpledCoder(Class enumClass) { + return new EnumSimpledCoder(enumClass); + } + + protected Type formatObjectType(Type type) { + if (type instanceof Class) { + Class clazz = (Class) type; + ConvertImpl ci = clazz.getAnnotation(ConvertImpl.class); + if (ci != null) { + if (!Modifier.isAbstract(clazz.getModifiers()) && !Modifier.isInterface(clazz.getModifiers())) { + throw new ConvertException("@" + ConvertImpl.class.getSimpleName() + " must at interface or abstract class, but " + clazz + " not"); + } + Class impl = ci.value(); + if (Modifier.isAbstract(impl.getModifiers()) || Modifier.isInterface(impl.getModifiers())) { + throw new ConvertException("@" + ConvertImpl.class.getSimpleName() + " at class " + impl + " cannot be interface or abstract class"); + } + return impl; + } + } + return type; + } + + protected Encodeable createDyncEncoder(Type type) { + return null; + } + + protected ObjectDecoder createObjectDecoder(Type type) { + return new ObjectDecoder(type); + } + + protected ObjectEncoder createObjectEncoder(Type type) { + return new ObjectEncoder(type); + } + + protected Decodeable createMapDecoder(Type type) { + return new MapDecoder(this, type); + } + + protected Encodeable createMapEncoder(Type type) { + return new MapEncoder(this, type); + } + + protected Decodeable createArrayDecoder(Type type) { + return new ArrayDecoder(this, type); + } + + protected Encodeable createArrayEncoder(Type type) { + return new ArrayEncoder(this, type); + } + + protected Decodeable createCollectionDecoder(Type type) { + return new CollectionDecoder(this, type); + } + + protected Encodeable createCollectionEncoder(Type type) { + return new CollectionEncoder(this, type); + } + + protected Decodeable createStreamDecoder(Type type) { + return new StreamDecoder(this, type); + } + + protected Encodeable createStreamEncoder(Type type) { + return new StreamEncoder(this, type); + } + + public Convert getConvert() { + return convert; + } + + public ConvertFactory tiny(boolean tiny) { + this.tiny = tiny; + return this; + } + + public boolean isConvertDisabled(AccessibleObject element) { + ConvertDisabled[] ccs = element.getAnnotationsByType(ConvertDisabled.class); + if (ccs.length == 0 && element instanceof Method) { + final Method method = (Method) element; + String fieldName = readGetSetFieldName(method); + if (fieldName != null) { + try { + ccs = method.getDeclaringClass().getDeclaredField(fieldName).getAnnotationsByType(ConvertDisabled.class); + } catch (Exception e) { //璇存槑娌℃湁璇ュ瓧娈碉紝蹇界暐寮傚父 + } + } + } + final ConvertType ct = this.getConvertType(); + for (ConvertDisabled ref : ccs) { + if (ref.type().contains(ct)) return true; + } + return false; + } + + public ConvertColumnEntry findRef(Class clazz, AccessibleObject element) { + if (element == null) return null; + ConvertColumnEntry en = this.columnEntrys.get(element); + Set onlyColumns = ignoreAlls.get(clazz); + if (en != null && onlyColumns == null) return en; + final ConvertType ct = this.getConvertType(); + ConvertColumn[] ccs = element.getAnnotationsByType(ConvertColumn.class); + String fieldName = null; + if (ccs.length == 0 && element instanceof Method) { + final Method method = (Method) element; + fieldName = readGetSetFieldName(method); + if (fieldName != null) { + Class mclz = method.getDeclaringClass(); + do { + try { + ccs = mclz.getDeclaredField(fieldName).getAnnotationsByType(ConvertColumn.class); + break; + } catch (Exception e) { //璇存槑娌℃湁璇ュ瓧娈碉紝蹇界暐寮傚父 + } + } while (mclz != Object.class && (mclz = mclz.getSuperclass()) != Object.class); + } + } + if (onlyColumns != null && fieldName == null) { + if (element instanceof Method) { + fieldName = readGetSetFieldName((Method) element); + } else if (element instanceof Field) { + fieldName = ((Field) element).getName(); + } + } + if (ccs.length == 0 && onlyColumns != null && fieldName != null) { + if (!onlyColumns.contains(fieldName)) return new ConvertColumnEntry(fieldName, true); + } + for (ConvertColumn ref : ccs) { + if (ref.type().contains(ct)) { + String realName = ref.name().isEmpty() ? fieldName : ref.name(); + if (onlyColumns != null && fieldName != null) { + if (!onlyColumns.contains(realName)) return new ConvertColumnEntry(realName, true); + } + ConvertColumnEntry entry = new ConvertColumnEntry(ref); + if (skipAllIgnore) { + entry.setIgnore(false); + return entry; + } + if (skipIgnores.isEmpty()) { + if (onlyColumns != null && realName != null && onlyColumns.contains(realName)) entry.setIgnore(false); + return entry; + } + if (skipIgnores.contains(((Member) element).getDeclaringClass())) entry.setIgnore(false); + return entry; + } + } + return null; + } + + static Field readGetSetField(Method method) { + String name = readGetSetFieldName(method); + if (name == null) return null; + try { + return method.getDeclaringClass().getDeclaredField(name); + } catch (Exception e) { + return null; + } + } + + static String readGetSetFieldName(Method method) { + if (method == null) return null; + String fname = method.getName(); + if (!fname.startsWith("is") && !fname.startsWith("get") && !fname.startsWith("set")) return fname; //record绫讳細鐩存帴鐢╢ield鍚嶄綔涓簃ethod鍚 + fname = fname.substring(fname.startsWith("is") ? 2 : 3); + if (fname.length() > 1 && !(fname.charAt(1) >= 'A' && fname.charAt(1) <= 'Z')) { + fname = Character.toLowerCase(fname.charAt(0)) + fname.substring(1); + } else if (fname.length() == 1) { + fname = "" + Character.toLowerCase(fname.charAt(0)); + } + return fname; + } + + final String getEntityAlias(Class clazz) { + if (clazz == String.class) return "A"; + if (clazz == int.class) return "I"; + if (clazz == Integer.class) return "i"; + if (clazz == long.class) return "J"; + if (clazz == Long.class) return "j"; + if (clazz == byte.class) return "B"; + if (clazz == Byte.class) return "b"; + if (clazz == boolean.class) return "Z"; + if (clazz == Boolean.class) return "z"; + if (clazz == short.class) return "S"; + if (clazz == Short.class) return "s"; + if (clazz == char.class) return "C"; + if (clazz == Character.class) return "c"; + if (clazz == float.class) return "F"; + if (clazz == Float.class) return "f"; + if (clazz == double.class) return "D"; + if (clazz == Double.class) return "d"; + + if (clazz == String[].class) return "[A"; + if (clazz == int[].class) return "[I"; + if (clazz == long[].class) return "[J"; + if (clazz == byte[].class) return "[B"; + if (clazz == boolean[].class) return "[Z"; + if (clazz == short[].class) return "[S"; + if (clazz == char[].class) return "[C"; + if (clazz == float[].class) return "[F"; + if (clazz == double[].class) return "[D"; + + ConvertEntity ce = (ConvertEntity) clazz.getAnnotation(ConvertEntity.class); + if (ce != null && findEntityAlias(ce.value()) == null) entitys.put(ce.value(), clazz); + return ce == null ? clazz.getName() : ce.value(); + } + + final Class getEntityAlias(String name) { + if ("A".equals(name)) return String.class; + if ("I".equals(name)) return int.class; + if ("i".equals(name)) return Integer.class; + if ("J".equals(name)) return long.class; + if ("j".equals(name)) return Long.class; + if ("B".equals(name)) return byte.class; + if ("b".equals(name)) return Byte.class; + if ("Z".equals(name)) return boolean.class; + if ("z".equals(name)) return Boolean.class; + if ("S".equals(name)) return short.class; + if ("s".equals(name)) return Short.class; + if ("C".equals(name)) return char.class; + if ("c".equals(name)) return Character.class; + if ("F".equals(name)) return float.class; + if ("f".equals(name)) return Float.class; + if ("D".equals(name)) return double.class; + if ("d".equals(name)) return Double.class; + + if ("[A".equals(name)) return String[].class; + if ("[I".equals(name)) return int[].class; + if ("[J".equals(name)) return long[].class; + if ("[B".equals(name)) return byte[].class; + if ("[Z".equals(name)) return boolean[].class; + if ("[S".equals(name)) return short[].class; + if ("[C".equals(name)) return char[].class; + if ("[F".equals(name)) return float[].class; + if ("[D".equals(name)) return double[].class; + + Class clazz = findEntityAlias(name); + try { + return clazz == null ? Thread.currentThread().getContextClassLoader().loadClass(name) : clazz; + } catch (Exception ex) { + throw new ConvertException("convert entity is " + name, ex); + } + } + + private Class findEntityAlias(String name) { + Class clazz = entitys.get(name); + return parent == null ? clazz : parent.findEntityAlias(name); + } + + /** + * 浣挎墍鏈夌被鐨勬墍鏈夎澹版槑涓篊onvertColumn.ignore = true 鐨勫瓧娈垫垨鏂规硶鍙樹负ConvertColumn.ignore = false + * + * @param skipIgnore 鏄惁蹇界暐Ignore娉ㄨВ + */ + public final void registerSkipAllIgnore(final boolean skipIgnore) { + this.skipAllIgnore = skipIgnore; + } + + /** + * 浣挎墍鏈夌被鐨勬墍鏈夎澹版槑涓篊onvertColumn.ignore = true 鐨勫瓧娈垫垨鏂规硶鍙樹负ConvertColumn.ignore = false + * + * @param skipIgnore 蹇界暐ignore + * + * @return 鑷韩 + */ + public ConvertFactory skipAllIgnore(final boolean skipIgnore) { + this.skipAllIgnore = skipIgnore; + return this; + } + + /** + * 浣胯绫绘墍鏈夎澹版槑涓篊onvertColumn.ignore = true 鐨勫瓧娈垫垨鏂规硶鍙樹负ConvertColumn.ignore = false + * + * @param type 鎸囧畾鐨勭被 + */ + public final void registerSkipIgnore(final Class type) { + skipIgnores.add(type); + } + + /** + * 灞忚斀鎸囧畾绫绘墍鏈夊瓧娈碉紝浠呬粎淇濈暀鎸囧畾瀛楁
+ * 娉ㄦ剰: 璇ラ厤缃紭鍏堢骇楂樹簬skipAllIgnore鍜孋onvertColumnEntry閰嶇疆 + * + * @param type 鎸囧畾鐨勭被 + * @param excludeColumns 闇瑕佹帓闄ょ殑瀛楁鍚 + */ + public final void registerIgnoreAll(final Class type, String... excludeColumns) { + Set set = ignoreAlls.get(type); + if (set == null) { + ignoreAlls.put(type, new HashSet<>(Arrays.asList(excludeColumns))); + } else { + set.addAll(Arrays.asList(excludeColumns)); + } + } + + public final void registerIgnoreAll(final Class type, Collection excludeColumns) { + Set set = ignoreAlls.get(type); + if (set == null) { + ignoreAlls.put(type, new HashSet<>(excludeColumns)); + } else { + set.addAll(new ArrayList(excludeColumns)); + } + } + + public final void register(final Class type, boolean ignore, String... columns) { + for (String column : columns) { + register(type, column, new ConvertColumnEntry(column, ignore)); + } + } + + public final void register(final Class type, boolean ignore, Collection columns) { + for (String column : columns) { + register(type, column, new ConvertColumnEntry(column, ignore)); + } + } + + public final boolean register(final Class type, String column, String alias) { + return register(type, column, new ConvertColumnEntry(alias)); + } + + public final boolean register(final Class type, String column, ConvertColumnEntry entry) { + if (type == null || column == null || entry == null) return false; + Field field = null; + try { + field = type.getDeclaredField(column); + } catch (Exception e) { + } + String get = "get"; + if (field != null && (field.getType() == boolean.class || field.getType() == Boolean.class)) get = "is"; + char[] cols = column.toCharArray(); + cols[0] = Character.toUpperCase(cols[0]); + final String bigColumn = new String(cols); + try { + register(type.getMethod(get + bigColumn), entry); + } catch (NoSuchMethodException mex) { + if (get.length() >= 3) { //get + try { + register(type.getMethod("is" + bigColumn), entry); + } catch (Exception ex) { + } + } + } catch (Exception ex) { + } + try { + register(type.getMethod("set" + bigColumn, field.getType()), entry); + } catch (Exception ex) { + } + return field == null ? true : register(field, entry); + } + + public final boolean register(final AccessibleObject field, final ConvertColumnEntry entry) { + if (field == null || entry == null) return false; + this.columnEntrys.put(field, entry); + return true; + } + + public final void reloadCoder(final Type type) { + this.register(type, this.createDecoder(type)); + this.register(type, this.createEncoder(type)); + } + + public final void reloadCoder(final Type type, final Class clazz) { + this.register(type, this.createDecoder(type, clazz)); + this.register(type, this.createEncoder(type, clazz)); + } + + public final void register(final Class clazz, final Creator creator) { + creators.put(clazz, creator); + } + + public final Creator findCreator(Class type) { + Creator creator = creators.get(type); + if (creator != null) return creator; + return this.parent == null ? null : this.parent.findCreator(type); + } + + public final Creator loadCreator(Class type) { + Creator result = findCreator(type); + if (result == null) { + result = Creator.create(type); + if (result != null) creators.put(type, result); + } + return result; + } + + //---------------------------------------------------------------------- + public final Encodeable getAnyEncoder() { + return (Encodeable) anyEncoder; + } + + public final void register(final Type clazz, final SimpledCoder coder) { + decoders.put(clazz, coder); + encoders.put(clazz, coder); + } + + public final void register(final Type clazz, final Decodeable decoder, final Encodeable encoder) { + decoders.put(clazz, decoder); + encoders.put(clazz, encoder); + } + + public final void register(final Type clazz, final Decodeable decoder) { + decoders.put(clazz, decoder); + } + + public final void register(final Type clazz, final Encodeable encoder) { + encoders.put(clazz, encoder); + } + + //coder = null琛ㄧず鍒犻櫎璇ュ瓧娈电殑鎸囧畾SimpledCoder + public final void register(final Class clazz, final String field, final SimpledCoder coder) { + if (field == null || clazz == null) return; + try { + clazz.getDeclaredField(field); + } catch (Exception e) { + throw new RuntimeException(clazz + " not found field(" + field + ")"); + } + if (coder == null) { + Map map = this.fieldCoders.get(clazz); + if (map != null) map.remove(field); + } else { + this.fieldCoders.computeIfAbsent(clazz, c -> new ConcurrentHashMap<>()).put(field, coder); + } + } + + public final SimpledCoder findFieldCoder(final Type clazz, final String field) { + if (field == null) return null; + Map> map = this.fieldCoders.get(clazz); + if (map == null) return parent == null ? null : parent.findFieldCoder(clazz, field); + return (SimpledCoder) map.get(field); + } + + public final Decodeable findDecoder(final Type type) { + Decodeable rs = (Decodeable) decoders.get(type); + if (rs != null) return rs; + return this.parent == null ? null : this.parent.findDecoder(type); + } + + public final Encodeable findEncoder(final Type type) { + Encodeable rs = (Encodeable) encoders.get(type); + if (rs != null) return rs; + return this.parent == null ? null : this.parent.findEncoder(type); + } + + public final Decodeable loadDecoder(final Type type) { + Decodeable decoder = findDecoder(type); + if (decoder != null) return decoder; + if (type instanceof GenericArrayType) return createArrayDecoder(type); + Class clazz; + if (type instanceof ParameterizedType) { + final ParameterizedType pts = (ParameterizedType) type; + clazz = (Class) (pts).getRawType(); + } else if (type instanceof TypeVariable) { // e.g. + final TypeVariable tv = (TypeVariable) type; + Class cz = tv.getBounds().length == 0 ? Object.class : null; + for (Type f : tv.getBounds()) { + if (f instanceof Class) { + cz = (Class) f; + break; + } + } + clazz = cz; + if (cz == null) throw new ConvertException("not support the type (" + type + ")"); + } else if (type instanceof WildcardType) { // e.g. + final WildcardType wt = (WildcardType) type; + Class cz = null; + for (Type f : wt.getUpperBounds()) { + if (f instanceof Class) { + cz = (Class) f; + break; + } + } + clazz = cz; + if (cz == null) throw new ConvertException("not support the type (" + type + ")"); + } else if (type instanceof Class) { + clazz = (Class) type; + } else { + throw new ConvertException("not support the type (" + type + ")"); + } + //姝ゅ涓嶈兘鍐峟indDecoder锛屽惁鍒檛ype涓巆lass涓嶄竴鑷, 濡: RetResult 鍜 RetResult + return createDecoder(type, clazz); + } + + public final Decodeable createDecoder(final Type type) { + Class clazz; + if (type instanceof ParameterizedType) { + final ParameterizedType pts = (ParameterizedType) type; + clazz = (Class) (pts).getRawType(); + } else if (type instanceof Class) { + clazz = (Class) type; + } else { + throw new ConvertException("not support the type (" + type + ")"); + } + return createDecoder(type, clazz); + } + + private Decodeable createDecoder(final Type type, final Class clazz) { + Decodeable decoder = null; + ObjectDecoder od = null; + if (clazz.isEnum()) { + decoder = createEnumSimpledCoder(clazz); + } else if (clazz.isArray()) { + decoder = createArrayDecoder(type); + } else if (Collection.class.isAssignableFrom(clazz)) { + decoder = createCollectionDecoder(type); + } else if (Stream.class.isAssignableFrom(clazz)) { + decoder = createStreamDecoder(type); + } else if (Map.class.isAssignableFrom(clazz)) { + decoder = createMapDecoder(type); + } else if (Optional.class == clazz) { + decoder = new OptionalCoder(this, type); + } else if (clazz == Object.class) { + od = createObjectDecoder(type); + decoder = od; + } else if (!clazz.getName().startsWith("java.") + || java.net.HttpCookie.class == clazz + || java.util.AbstractMap.SimpleEntry.class == clazz + || clazz.getName().startsWith("java.awt.geom.Point2D")) { + Decodeable simpleCoder = null; + for (final Method method : clazz.getDeclaredMethods()) { + if (!Modifier.isStatic(method.getModifiers())) continue; + Class[] paramTypes = method.getParameterTypes(); + if (paramTypes.length != 1) continue; + if (paramTypes[0] != ConvertFactory.class && paramTypes[0] != this.getClass()) continue; + if (!Decodeable.class.isAssignableFrom(method.getReturnType())) continue; + try { + method.setAccessible(true); + simpleCoder = (Decodeable) method.invoke(null, this); + RedkaleClassLoader.putReflectionDeclaredMethods(clazz.getName()); + RedkaleClassLoader.putReflectionMethod(clazz.getName(), method); + break; + } catch (Exception e) { + } + } + if (simpleCoder == null) { + Type impl = formatObjectType(type); + od = createObjectDecoder(impl); + decoder = od; + } else { + decoder = simpleCoder; + } + } + if (decoder == null) throw new ConvertException("not support the type (" + type + ")"); + register(type, decoder); + if (od != null) od.init(this); + return decoder; + } + + public final Encodeable loadEncoder(final Type type) { + Encodeable encoder = findEncoder(type); + if (encoder != null) return encoder; + if (type instanceof GenericArrayType) return createArrayEncoder(type); + Class clazz; + if (type instanceof ParameterizedType) { + final ParameterizedType pts = (ParameterizedType) type; + clazz = (Class) (pts).getRawType(); + } else if (type instanceof TypeVariable) { + TypeVariable tv = (TypeVariable) type; + Type t = Object.class; + if (tv.getBounds().length == 1) { + t = tv.getBounds()[0]; + } + if (!(t instanceof Class)) t = Object.class; + clazz = (Class) t; + } else if (type instanceof Class) { + clazz = (Class) type; + } else { + throw new ConvertException("not support the type (" + type + ")"); + } + //姝ゅ涓嶈兘鍐峟indEncoder锛屽惁鍒檛ype涓巆lass涓嶄竴鑷, 濡: RetResult 鍜 RetResult + return createEncoder(type, clazz); + } + + public final Encodeable createEncoder(final Type type) { + Class clazz; + if (type instanceof ParameterizedType) { + final ParameterizedType pts = (ParameterizedType) type; + clazz = (Class) (pts).getRawType(); + } else if (type instanceof Class) { + clazz = (Class) type; + } else { + throw new ConvertException("not support the type (" + type + ")"); + } + return createEncoder(type, clazz); + } + + private Encodeable createEncoder(final Type type, final Class clazz) { + Encodeable encoder = null; + ObjectEncoder oe = null; + if (clazz.isEnum()) { + encoder = createEnumSimpledCoder(clazz); + } else if (clazz.isArray()) { + encoder = createArrayEncoder(type); + } else if (Collection.class.isAssignableFrom(clazz)) { + encoder = createCollectionEncoder(type); + } else if (Stream.class.isAssignableFrom(clazz)) { + encoder = createStreamEncoder(type); + } else if (Map.class.isAssignableFrom(clazz)) { + encoder = createMapEncoder(type); + } else if (Optional.class == clazz) { + encoder = new OptionalCoder(this, type); + } else if (clazz == Object.class) { + return (Encodeable) this.anyEncoder; + } else if (!clazz.getName().startsWith("java.") || java.net.HttpCookie.class == clazz + || java.util.Map.Entry.class == clazz || java.util.AbstractMap.SimpleEntry.class == clazz) { + Encodeable simpleCoder = null; + for (final Method method : clazz.getDeclaredMethods()) { + if (!Modifier.isStatic(method.getModifiers())) continue; + Class[] paramTypes = method.getParameterTypes(); + if (paramTypes.length != 1) continue; + if (paramTypes[0] != ConvertFactory.class && paramTypes[0] != this.getClass()) continue; + if (!Encodeable.class.isAssignableFrom(method.getReturnType())) continue; + try { + method.setAccessible(true); + simpleCoder = (Encodeable) method.invoke(null, this); + RedkaleClassLoader.putReflectionDeclaredMethods(clazz.getName()); + RedkaleClassLoader.putReflectionMethod(clazz.getName(), method); + break; + } catch (Exception e) { + } + } + if (simpleCoder == null) { + Type impl = formatObjectType(type); + encoder = createDyncEncoder(impl); + if (encoder == null) { + oe = createObjectEncoder(impl); + encoder = oe; + } + } else { + encoder = simpleCoder; + } + } + if (encoder == null) throw new ConvertException("not support the type (" + type + ")"); + register(type, encoder); + if (oe != null) oe.init(this); + return encoder; + + } + +} diff --git a/src/main/java/org/redkale/convert/ConvertField.java b/src/main/java/org/redkale/convert/ConvertField.java index 176eb3cad..16dc869e6 100644 --- a/src/main/java/org/redkale/convert/ConvertField.java +++ b/src/main/java/org/redkale/convert/ConvertField.java @@ -1,102 +1,102 @@ -/* - * 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.convert; - -import java.io.Serializable; -import java.lang.reflect.Type; -import org.redkale.convert.json.JsonConvert; - -/** - * newConvert鍙傛暟涓殑Function杩斿洖缁撴灉鐨勬暟鎹被 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public class ConvertField implements Serializable { - - protected String name; - - protected Type type; - - protected int position; - - protected Object value; - - public ConvertField() { - } - - public ConvertField(String name, Object value) { - this.name = name; - this.value = value; - } - - public ConvertField(String name, int position, Object value) { - this.name = name; - this.position = position; - this.value = value; - } - - public ConvertField(String name, Type type, Object value) { - this.name = name; - this.type = type; - this.value = value; - } - - public ConvertField(String name, Type type, int position, Object value) { - this.name = name; - this.type = type; - this.position = position; - this.value = value; - } - - public static ConvertField[] ofArray(Object... items) { - int len = items.length / 2; - ConvertField[] rs = new ConvertField[len]; - for (int i = 0; i < len; i++) { - rs[i] = new ConvertField(items[i * 2].toString(), items[i * 2 + 1]); - } - return rs; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public Type getType() { - return type; - } - - public void setType(Type type) { - this.type = type; - } - - public int getPosition() { - return position; - } - - public void setPosition(int position) { - this.position = position; - } - - public Object getValue() { - return value; - } - - public void setValue(Object value) { - this.value = value; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } -} +/* + * 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.convert; + +import java.io.Serializable; +import java.lang.reflect.Type; +import org.redkale.convert.json.JsonConvert; + +/** + * newConvert鍙傛暟涓殑Function杩斿洖缁撴灉鐨勬暟鎹被 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public class ConvertField implements Serializable { + + protected String name; + + protected Type type; + + protected int position; + + protected Object value; + + public ConvertField() { + } + + public ConvertField(String name, Object value) { + this.name = name; + this.value = value; + } + + public ConvertField(String name, int position, Object value) { + this.name = name; + this.position = position; + this.value = value; + } + + public ConvertField(String name, Type type, Object value) { + this.name = name; + this.type = type; + this.value = value; + } + + public ConvertField(String name, Type type, int position, Object value) { + this.name = name; + this.type = type; + this.position = position; + this.value = value; + } + + public static ConvertField[] ofArray(Object... items) { + int len = items.length / 2; + ConvertField[] rs = new ConvertField[len]; + for (int i = 0; i < len; i++) { + rs[i] = new ConvertField(items[i * 2].toString(), items[i * 2 + 1]); + } + return rs; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Type getType() { + return type; + } + + public void setType(Type type) { + this.type = type; + } + + public int getPosition() { + return position; + } + + public void setPosition(int position) { + this.position = position; + } + + public Object getValue() { + return value; + } + + public void setValue(Object value) { + this.value = value; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } +} diff --git a/src/main/java/org/redkale/convert/ConvertMask.java b/src/main/java/org/redkale/convert/ConvertMask.java index 49633c86d..11829f57f 100644 --- a/src/main/java/org/redkale/convert/ConvertMask.java +++ b/src/main/java/org/redkale/convert/ConvertMask.java @@ -1,25 +1,25 @@ -/* - * 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.convert; - -/** - * Mask鎺ュ彛 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public interface ConvertMask { - - default byte mask(byte value) { - return value; - } - - default byte unmask(byte value) { - return value; - } -} +/* + * 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.convert; + +/** + * Mask鎺ュ彛 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public interface ConvertMask { + + default byte mask(byte value) { + return value; + } + + default byte unmask(byte value) { + return value; + } +} diff --git a/src/main/java/org/redkale/convert/ConvertProvider.java b/src/main/java/org/redkale/convert/ConvertProvider.java index 160de4a1c..a4521052b 100644 --- a/src/main/java/org/redkale/convert/ConvertProvider.java +++ b/src/main/java/org/redkale/convert/ConvertProvider.java @@ -1,23 +1,23 @@ -/* - * 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.convert; - -/** - * Convert鐨勬墿灞曞疄鐜扮被鍔犺浇鍣 - * - * - * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * - * @since 2.5.0 - */ -public interface ConvertProvider { - - public ConvertType type(); - - public Convert convert(); -} +/* + * 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.convert; + +/** + * Convert鐨勬墿灞曞疄鐜扮被鍔犺浇鍣 + * + * + * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.5.0 + */ +public interface ConvertProvider { + + public ConvertType type(); + + public Convert convert(); +} diff --git a/src/main/java/org/redkale/convert/ConvertSmallString.java b/src/main/java/org/redkale/convert/ConvertSmallString.java index 210f8c384..4fcdd637f 100644 --- a/src/main/java/org/redkale/convert/ConvertSmallString.java +++ b/src/main/java/org/redkale/convert/ConvertSmallString.java @@ -1,27 +1,27 @@ -/* - * 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.convert; - -import java.lang.annotation.*; -import static java.lang.annotation.ElementType.*; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * 搴忓垪鍖栨椂鏍囪String瀛楁鐨勫兼槸鍚︿负鏃犺浆涔夊瓧绗︿笖闀垮害涓嶈秴杩255鐨勫瓧绗︿覆 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * - * @since 2.3.0 - * - */ -@Target({METHOD, FIELD}) -@Retention(RUNTIME) -public @interface ConvertSmallString { - -} +/* + * 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.convert; + +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * 搴忓垪鍖栨椂鏍囪String瀛楁鐨勫兼槸鍚︿负鏃犺浆涔夊瓧绗︿笖闀垮害涓嶈秴杩255鐨勫瓧绗︿覆 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.3.0 + * + */ +@Target({METHOD, FIELD}) +@Retention(RUNTIME) +public @interface ConvertSmallString { + +} diff --git a/src/main/java/org/redkale/convert/ConvertType.java b/src/main/java/org/redkale/convert/ConvertType.java index 61bdedec2..19f816e3e 100644 --- a/src/main/java/org/redkale/convert/ConvertType.java +++ b/src/main/java/org/redkale/convert/ConvertType.java @@ -1,46 +1,46 @@ -/* - * 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.convert; - -/** - * 搴忓垪鍖栫被鍨嬫灇涓撅紝缁撳悎@ConvertColumn浣跨敤 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public enum ConvertType { - - JSON(1), - BSON(2), - PROTOBUF(64), - PROTOBUF_JSON(64 + 1), - DIY(256), - ALL(1023); - - private final int value; - - private ConvertType(int v) { - this.value = v; - } - - public int getValue() { - return value; - } - - public boolean contains(ConvertType type) { - if (type == null) return false; - return this.value >= type.value && (this.value & type.value) > 0; - } - - public static ConvertType find(int value) { - for (ConvertType t : ConvertType.values()) { - if (value == t.value) return t; - } - return null; - } -} +/* + * 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.convert; + +/** + * 搴忓垪鍖栫被鍨嬫灇涓撅紝缁撳悎@ConvertColumn浣跨敤 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public enum ConvertType { + + JSON(1), + BSON(2), + PROTOBUF(64), + PROTOBUF_JSON(64 + 1), + DIY(256), + ALL(1023); + + private final int value; + + private ConvertType(int v) { + this.value = v; + } + + public int getValue() { + return value; + } + + public boolean contains(ConvertType type) { + if (type == null) return false; + return this.value >= type.value && (this.value & type.value) > 0; + } + + public static ConvertType find(int value) { + for (ConvertType t : ConvertType.values()) { + if (value == t.value) return t; + } + return null; + } +} diff --git a/src/main/java/org/redkale/convert/DeMember.java b/src/main/java/org/redkale/convert/DeMember.java index 44fc8f30a..57beaf003 100644 --- a/src/main/java/org/redkale/convert/DeMember.java +++ b/src/main/java/org/redkale/convert/DeMember.java @@ -1,137 +1,137 @@ -/* - * 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.convert; - -import java.lang.reflect.*; -import org.redkale.util.Attribute; - -/** - * 瀛楁鐨勫弽搴忓垪鍖栨搷浣滅被 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Reader杈撳叆鐨勫瓙绫 - * @param 瀛楁渚濋檮鐨勭被 - * @param 瀛楁鐨勬暟鎹被鍨 - */ -@SuppressWarnings("unchecked") -public final class DeMember { - - final Field field; //瀵瑰簲绫绘垚鍛樼殑Field锛 涔熷彲鑳戒负null - - final Method method; //瀵瑰簲绫绘垚鍛樼殑Method涔熷彲鑳戒负null - - protected int index; - - protected int position; //浠1寮濮 - - protected int tag; //涓昏缁檖rotobuf浣跨敤 - - protected final Attribute attribute; - - protected Decodeable decoder; - - public DeMember(final Attribute attribute, Field field, Method method) { - this.attribute = attribute; - this.field = field; - this.method = method; - } - - public DeMember(Attribute attribute, Decodeable decoder, Field field, Method method) { - this(attribute, field, method); - this.decoder = decoder; - } - - public static DeMember create(final ConvertFactory factory, final Class clazz, final String fieldname) { - try { - Field field = clazz.getDeclaredField(fieldname); - return new DeMember<>(Attribute.create(field), factory.loadDecoder(field.getGenericType()), field, null); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - public static DeMember create(final ConvertFactory factory, final Class clazz, final String fieldname, final Class fieldtype) { - try { - Field field = clazz.getDeclaredField(fieldname); - return new DeMember<>(Attribute.create(clazz, fieldname, fieldtype), factory.loadDecoder(fieldtype), field, null); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - public static DeMember create(final Attribute attribute, final ConvertFactory factory, final Class fieldtype) { - return new DeMember<>(attribute, factory.loadDecoder(fieldtype), null, null); - } - - public final boolean accepts(String name) { - return attribute.field().equals(name); - } - - public final void read(R in, T obj) { - this.attribute.set(obj, decoder.convertFrom(in)); - } - - public final F read(R in) { - return decoder.convertFrom(in); - } - - public Attribute getAttribute() { - return this.attribute; - } - - public Decodeable getDecoder() { - return decoder; - } - - public Field getField() { - return field; - } - - public Method getMethod() { - return method; - } - - public int getIndex() { - return this.index; - } - - public int getPosition() { - return this.position; - } - - public int getTag() { - return this.tag; - } - - public int compareTo(boolean fieldSort, DeMember o) { - if (o == null) return -1; - if (this.position != o.position) return (this.position == 0 ? Integer.MAX_VALUE : this.position) - (o.position == 0 ? Integer.MAX_VALUE : o.position); - if (this.index != o.index) return (this.index == 0 ? Integer.MAX_VALUE : this.index) - (o.index == 0 ? Integer.MAX_VALUE : o.index); - if (this.index != 0) throw new RuntimeException("fields (" + attribute.field() + ", " + o.attribute.field() + ") have same ConvertColumn.index(" + this.index + ") in " + attribute.declaringClass()); - return fieldSort ? this.attribute.field().compareTo(o.attribute.field()) : 0; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (!(obj instanceof DeMember)) return false; - DeMember other = (DeMember) obj; - return compareTo(true, other) == 0; - } - - @Override - public int hashCode() { - return this.attribute.field().hashCode(); - } - - @Override - public String toString() { - return "DeMember{" + "attribute=" + attribute.field() + ", position=" + position + ", tag=" + tag + ", decoder=" + (decoder == null ? null : decoder.getClass().getName()) + '}'; - } -} +/* + * 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.convert; + +import java.lang.reflect.*; +import org.redkale.util.Attribute; + +/** + * 瀛楁鐨勫弽搴忓垪鍖栨搷浣滅被 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Reader杈撳叆鐨勫瓙绫 + * @param 瀛楁渚濋檮鐨勭被 + * @param 瀛楁鐨勬暟鎹被鍨 + */ +@SuppressWarnings("unchecked") +public final class DeMember { + + final Field field; //瀵瑰簲绫绘垚鍛樼殑Field锛 涔熷彲鑳戒负null + + final Method method; //瀵瑰簲绫绘垚鍛樼殑Method涔熷彲鑳戒负null + + protected int index; + + protected int position; //浠1寮濮 + + protected int tag; //涓昏缁檖rotobuf浣跨敤 + + protected final Attribute attribute; + + protected Decodeable decoder; + + public DeMember(final Attribute attribute, Field field, Method method) { + this.attribute = attribute; + this.field = field; + this.method = method; + } + + public DeMember(Attribute attribute, Decodeable decoder, Field field, Method method) { + this(attribute, field, method); + this.decoder = decoder; + } + + public static DeMember create(final ConvertFactory factory, final Class clazz, final String fieldname) { + try { + Field field = clazz.getDeclaredField(fieldname); + return new DeMember<>(Attribute.create(field), factory.loadDecoder(field.getGenericType()), field, null); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static DeMember create(final ConvertFactory factory, final Class clazz, final String fieldname, final Class fieldtype) { + try { + Field field = clazz.getDeclaredField(fieldname); + return new DeMember<>(Attribute.create(clazz, fieldname, fieldtype), factory.loadDecoder(fieldtype), field, null); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static DeMember create(final Attribute attribute, final ConvertFactory factory, final Class fieldtype) { + return new DeMember<>(attribute, factory.loadDecoder(fieldtype), null, null); + } + + public final boolean accepts(String name) { + return attribute.field().equals(name); + } + + public final void read(R in, T obj) { + this.attribute.set(obj, decoder.convertFrom(in)); + } + + public final F read(R in) { + return decoder.convertFrom(in); + } + + public Attribute getAttribute() { + return this.attribute; + } + + public Decodeable getDecoder() { + return decoder; + } + + public Field getField() { + return field; + } + + public Method getMethod() { + return method; + } + + public int getIndex() { + return this.index; + } + + public int getPosition() { + return this.position; + } + + public int getTag() { + return this.tag; + } + + public int compareTo(boolean fieldSort, DeMember o) { + if (o == null) return -1; + if (this.position != o.position) return (this.position == 0 ? Integer.MAX_VALUE : this.position) - (o.position == 0 ? Integer.MAX_VALUE : o.position); + if (this.index != o.index) return (this.index == 0 ? Integer.MAX_VALUE : this.index) - (o.index == 0 ? Integer.MAX_VALUE : o.index); + if (this.index != 0) throw new RuntimeException("fields (" + attribute.field() + ", " + o.attribute.field() + ") have same ConvertColumn.index(" + this.index + ") in " + attribute.declaringClass()); + return fieldSort ? this.attribute.field().compareTo(o.attribute.field()) : 0; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (!(obj instanceof DeMember)) return false; + DeMember other = (DeMember) obj; + return compareTo(true, other) == 0; + } + + @Override + public int hashCode() { + return this.attribute.field().hashCode(); + } + + @Override + public String toString() { + return "DeMember{" + "attribute=" + attribute.field() + ", position=" + position + ", tag=" + tag + ", decoder=" + (decoder == null ? null : decoder.getClass().getName()) + '}'; + } +} diff --git a/src/main/java/org/redkale/convert/Decodeable.java b/src/main/java/org/redkale/convert/Decodeable.java index f1db855f4..98e9b933f 100644 --- a/src/main/java/org/redkale/convert/Decodeable.java +++ b/src/main/java/org/redkale/convert/Decodeable.java @@ -1,31 +1,31 @@ -/* - * 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.convert; - -import java.lang.reflect.Type; - -/** - * 鍙嶅簭鍒楀寲鎿嶄綔绫 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Reader杈撳叆鐨勫瓙绫 - * @param 鍙嶈В鏋愮殑鏁版嵁绫诲瀷 - */ -public interface Decodeable { - - public T convertFrom(final R in); - - /** - * 娉涘瀷鏄犲皠鎺ュ彛 - * - * @return 鍙嶈В鏋愮殑鏁版嵁绫诲瀷 - */ - public Type getType(); - -} +/* + * 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.convert; + +import java.lang.reflect.Type; + +/** + * 鍙嶅簭鍒楀寲鎿嶄綔绫 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Reader杈撳叆鐨勫瓙绫 + * @param 鍙嶈В鏋愮殑鏁版嵁绫诲瀷 + */ +public interface Decodeable { + + public T convertFrom(final R in); + + /** + * 娉涘瀷鏄犲皠鎺ュ彛 + * + * @return 鍙嶈В鏋愮殑鏁版嵁绫诲瀷 + */ + public Type getType(); + +} diff --git a/src/main/java/org/redkale/convert/EnMember.java b/src/main/java/org/redkale/convert/EnMember.java index f6da37cfc..ee038ad6f 100644 --- a/src/main/java/org/redkale/convert/EnMember.java +++ b/src/main/java/org/redkale/convert/EnMember.java @@ -1,156 +1,156 @@ -/* - * 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.convert; - -import java.lang.reflect.*; -import org.redkale.util.Attribute; - -/** - * 瀛楁鐨勫簭鍒楀寲鎿嶄綔绫 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Writer杈撳嚭鐨勫瓙绫 - * @param 瀛楁渚濋檮鐨勭被 - * @param 瀛楁鐨勬暟鎹被鍨 - */ -@SuppressWarnings("unchecked") -public final class EnMember { - - final Attribute attribute; - - final Encodeable encoder; - - final boolean string; - - //final boolean isnumber; - final boolean bool; - - final char[] jsonFieldNameChars; - - final byte[] jsonFieldNameBytes; - - final Field field; //瀵瑰簲绫绘垚鍛樼殑Field涔熷彲鑳戒负null - - final Method method; //瀵瑰簲绫绘垚鍛樼殑Method涔熷彲鑳戒负null - - protected int index; - - protected int position; //浠1寮濮 - - protected int tag; //涓昏缁檖rotobuf浣跨敤 - - public EnMember(Attribute attribute, Encodeable encoder, Field field, Method method) { - this.attribute = attribute; - this.encoder = encoder; - this.field = field; - this.method = method; - Class t = attribute.type(); - this.string = CharSequence.class.isAssignableFrom(t); - this.bool = t == Boolean.class || t == boolean.class; - this.jsonFieldNameChars = ('"' + attribute.field() + "\":").toCharArray(); - this.jsonFieldNameBytes = ('"' + attribute.field() + "\":").getBytes(); - //this.isnumber = Number.class.isAssignableFrom(t) || (!this.isbool && t.isPrimitive()); - } - - public static EnMember create(final ConvertFactory factory, final Class clazz, final String fieldname) { - try { - Field field = clazz.getDeclaredField(fieldname); - return new EnMember<>(Attribute.create(field), factory.loadEncoder(field.getGenericType()), field, null); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - public static EnMember create(final ConvertFactory factory, final Class clazz, final String fieldname, final Class fieldtype) { - try { - Field field = clazz.getDeclaredField(fieldname); - return new EnMember<>(Attribute.create(clazz, fieldname, fieldtype), factory.loadEncoder(fieldtype), field, null); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - public static EnMember create(final Attribute attribute, final ConvertFactory factory, final Class fieldtype) { - return new EnMember<>(attribute, factory.loadEncoder(fieldtype), null, null); - } - - public final boolean accepts(String name) { - return attribute.field().equals(name); - } - - public Attribute getAttribute() { - return attribute; - } - - public char[] getJsonFieldNameChars() { - return jsonFieldNameChars; - } - - public byte[] getJsonFieldNameBytes() { - return jsonFieldNameBytes; - } - - public Encodeable getEncoder() { - return encoder; - } - - public boolean isStringType() { - return string; - } - - public Field getField() { - return field; - } - - public Method getMethod() { - return method; - } - - public boolean isBoolType() { - return bool; - } - - public int getIndex() { - return this.index; - } - - public int getPosition() { - return this.position; - } - - public int getTag() { - return this.tag; - } - - public int compareTo(boolean fieldSort, EnMember o) { - if (o == null) return -1; - if (this.position != o.position) return (this.position == 0 ? Integer.MAX_VALUE : this.position) - (o.position == 0 ? Integer.MAX_VALUE : o.position); - if (this.index != o.index) return (this.index == 0 ? Integer.MAX_VALUE : this.index) - (o.index == 0 ? Integer.MAX_VALUE : o.index); - if (this.index != 0) throw new RuntimeException("fields (" + attribute.field() + ", " + o.attribute.field() + ") have same ConvertColumn.index(" + this.index + ") in " + attribute.declaringClass()); - return fieldSort ? this.attribute.field().compareTo(o.attribute.field()) : 0; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (!(obj instanceof EnMember)) return false; - EnMember other = (EnMember) obj; - return compareTo(true, other) == 0; - } - - @Override - public int hashCode() { - return this.attribute.field().hashCode(); - } - - @Override - public String toString() { - return "EnMember{" + "attribute=" + attribute.field() + ", position=" + position + ", encoder=" + (encoder == null ? null : encoder.getClass().getName()) + '}'; - } -} +/* + * 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.convert; + +import java.lang.reflect.*; +import org.redkale.util.Attribute; + +/** + * 瀛楁鐨勫簭鍒楀寲鎿嶄綔绫 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Writer杈撳嚭鐨勫瓙绫 + * @param 瀛楁渚濋檮鐨勭被 + * @param 瀛楁鐨勬暟鎹被鍨 + */ +@SuppressWarnings("unchecked") +public final class EnMember { + + final Attribute attribute; + + final Encodeable encoder; + + final boolean string; + + //final boolean isnumber; + final boolean bool; + + final char[] jsonFieldNameChars; + + final byte[] jsonFieldNameBytes; + + final Field field; //瀵瑰簲绫绘垚鍛樼殑Field涔熷彲鑳戒负null + + final Method method; //瀵瑰簲绫绘垚鍛樼殑Method涔熷彲鑳戒负null + + protected int index; + + protected int position; //浠1寮濮 + + protected int tag; //涓昏缁檖rotobuf浣跨敤 + + public EnMember(Attribute attribute, Encodeable encoder, Field field, Method method) { + this.attribute = attribute; + this.encoder = encoder; + this.field = field; + this.method = method; + Class t = attribute.type(); + this.string = CharSequence.class.isAssignableFrom(t); + this.bool = t == Boolean.class || t == boolean.class; + this.jsonFieldNameChars = ('"' + attribute.field() + "\":").toCharArray(); + this.jsonFieldNameBytes = ('"' + attribute.field() + "\":").getBytes(); + //this.isnumber = Number.class.isAssignableFrom(t) || (!this.isbool && t.isPrimitive()); + } + + public static EnMember create(final ConvertFactory factory, final Class clazz, final String fieldname) { + try { + Field field = clazz.getDeclaredField(fieldname); + return new EnMember<>(Attribute.create(field), factory.loadEncoder(field.getGenericType()), field, null); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static EnMember create(final ConvertFactory factory, final Class clazz, final String fieldname, final Class fieldtype) { + try { + Field field = clazz.getDeclaredField(fieldname); + return new EnMember<>(Attribute.create(clazz, fieldname, fieldtype), factory.loadEncoder(fieldtype), field, null); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static EnMember create(final Attribute attribute, final ConvertFactory factory, final Class fieldtype) { + return new EnMember<>(attribute, factory.loadEncoder(fieldtype), null, null); + } + + public final boolean accepts(String name) { + return attribute.field().equals(name); + } + + public Attribute getAttribute() { + return attribute; + } + + public char[] getJsonFieldNameChars() { + return jsonFieldNameChars; + } + + public byte[] getJsonFieldNameBytes() { + return jsonFieldNameBytes; + } + + public Encodeable getEncoder() { + return encoder; + } + + public boolean isStringType() { + return string; + } + + public Field getField() { + return field; + } + + public Method getMethod() { + return method; + } + + public boolean isBoolType() { + return bool; + } + + public int getIndex() { + return this.index; + } + + public int getPosition() { + return this.position; + } + + public int getTag() { + return this.tag; + } + + public int compareTo(boolean fieldSort, EnMember o) { + if (o == null) return -1; + if (this.position != o.position) return (this.position == 0 ? Integer.MAX_VALUE : this.position) - (o.position == 0 ? Integer.MAX_VALUE : o.position); + if (this.index != o.index) return (this.index == 0 ? Integer.MAX_VALUE : this.index) - (o.index == 0 ? Integer.MAX_VALUE : o.index); + if (this.index != 0) throw new RuntimeException("fields (" + attribute.field() + ", " + o.attribute.field() + ") have same ConvertColumn.index(" + this.index + ") in " + attribute.declaringClass()); + return fieldSort ? this.attribute.field().compareTo(o.attribute.field()) : 0; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (!(obj instanceof EnMember)) return false; + EnMember other = (EnMember) obj; + return compareTo(true, other) == 0; + } + + @Override + public int hashCode() { + return this.attribute.field().hashCode(); + } + + @Override + public String toString() { + return "EnMember{" + "attribute=" + attribute.field() + ", position=" + position + ", encoder=" + (encoder == null ? null : encoder.getClass().getName()) + '}'; + } +} diff --git a/src/main/java/org/redkale/convert/Encodeable.java b/src/main/java/org/redkale/convert/Encodeable.java index 14a5de81f..136e1458c 100644 --- a/src/main/java/org/redkale/convert/Encodeable.java +++ b/src/main/java/org/redkale/convert/Encodeable.java @@ -1,36 +1,36 @@ -/* - * 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.convert; - -import java.lang.reflect.Type; - -/** - * 搴忓垪鍖栨搷浣滅被 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Writer杈撳嚭鐨勫瓙绫 - * @param 搴忓垪鍖栫殑鏁版嵁绫诲瀷 - */ -public interface Encodeable { - - public void convertTo(final W out, T value); - - /** - * 娉涘瀷鏄犲皠鎺ュ彛 - * - * @return 杩斿洖搴忓垪鍖栧璞$被鐨勬暟鎹被鍨 - */ - public Type getType(); - - //鏄惁闇瑕佹鏌riter.specify - default boolean specifyable() { - return true; - } - -} +/* + * 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.convert; + +import java.lang.reflect.Type; + +/** + * 搴忓垪鍖栨搷浣滅被 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Writer杈撳嚭鐨勫瓙绫 + * @param 搴忓垪鍖栫殑鏁版嵁绫诲瀷 + */ +public interface Encodeable { + + public void convertTo(final W out, T value); + + /** + * 娉涘瀷鏄犲皠鎺ュ彛 + * + * @return 杩斿洖搴忓垪鍖栧璞$被鐨勬暟鎹被鍨 + */ + public Type getType(); + + //鏄惁闇瑕佹鏌riter.specify + default boolean specifyable() { + return true; + } + +} diff --git a/src/main/java/org/redkale/convert/MapDecoder.java b/src/main/java/org/redkale/convert/MapDecoder.java index 3baa14a3b..bef9269f8 100644 --- a/src/main/java/org/redkale/convert/MapDecoder.java +++ b/src/main/java/org/redkale/convert/MapDecoder.java @@ -1,189 +1,189 @@ -/* - * 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.convert; - -import org.redkale.util.Creator; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.util.*; - -/** - * Map鐨勫弽搴忓垪鍖栨搷浣滅被
- * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Map key鐨勬暟鎹被鍨 - * @param Map value鐨勬暟鎹被鍨 - */ -@SuppressWarnings("unchecked") -public class MapDecoder implements Decodeable> { - - protected final Type type; - - protected final Type keyType; - - protected final Type valueType; - - protected Creator> creator; - - protected final Decodeable keyDecoder; - - protected final Decodeable valueDecoder; - - protected volatile boolean inited = false; - - protected final Object lock = new Object(); - - public MapDecoder(final ConvertFactory factory, final Type type) { - this.type = type; - try { - if (type == java.util.Properties.class) { - this.keyType = String.class; - this.valueType = String.class; - this.creator = factory.loadCreator(java.util.Properties.class); - factory.register(type, this); - this.keyDecoder = factory.loadDecoder(String.class); - this.valueDecoder = factory.loadDecoder(String.class); - } else if (type instanceof ParameterizedType) { - final ParameterizedType pt = (ParameterizedType) type; - this.keyType = pt.getActualTypeArguments()[0]; - this.valueType = pt.getActualTypeArguments()[1]; - this.creator = factory.loadCreator((Class) pt.getRawType()); - factory.register(type, this); - this.keyDecoder = factory.loadDecoder(this.keyType); - this.valueDecoder = factory.loadDecoder(this.valueType); - } else if (factory.isReversible()) { - this.keyType = Object.class; - this.valueType = Object.class; - this.creator = factory.loadCreator((Class) type); - this.keyDecoder = factory.loadDecoder(this.keyType); - this.valueDecoder = factory.loadDecoder(this.valueType); - } else { - throw new ConvertException("mapdecoder not support the type (" + type + ")"); - } - } finally { - inited = true; - synchronized (lock) { - lock.notifyAll(); - } - } - } - - //浠呬緵绫讳技JsonAnyDecoder杩欑鍔ㄦ佸垱寤轰娇鐢紝 涓嶅緱璋冪敤 factory.register - public MapDecoder(final ConvertFactory factory, Type type, Type keyType, Type valueType, - Creator> creator, final Decodeable keyDecoder, Decodeable valueDecoder) { - Objects.requireNonNull(keyDecoder); - Objects.requireNonNull(valueDecoder); - this.type = type; - this.keyType = keyType; - this.valueType = valueType; - this.creator = creator; - this.keyDecoder = keyDecoder; - this.valueDecoder = valueDecoder; - this.inited = true; - } - - @Override - public Map convertFrom(Reader in) { - return convertFrom(in, null); - } - - public Map convertFrom(Reader in, DeMember member) { - if (this.keyDecoder == null || this.valueDecoder == null) { - if (!this.inited) { - synchronized (lock) { - try { - lock.wait(); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - } - byte[] typevals = new byte[2]; - int len = in.readMapB(member, typevals, this.keyDecoder, this.valueDecoder); - int contentLength = -1; - if (len == Reader.SIGN_NULL) return null; - if (len == Reader.SIGN_NOLENBUTBYTES) { - contentLength = in.readMemberContentLength(member, null); - len = Reader.SIGN_NOLENGTH; - } - final Map result = this.creator.create(); - boolean first = true; - Decodeable kdecoder = getKeyDecoder(this.keyDecoder, typevals); - Decodeable vdecoder = getValueDecoder(this.valueDecoder, typevals); - if (len == Reader.SIGN_NOLENGTH) { - int startPosition = in.position(); - while (hasNext(in, member, startPosition, contentLength, first)) { - Reader entryReader = getEntryReader(in, member, first); - if (entryReader == null) break; - K key = readKeyMember(entryReader, member, kdecoder, first); - entryReader.readBlank(); - V value = readValueMember(entryReader, member, vdecoder, first); - result.put(key, value); - first = false; - } - } else { - for (int i = 0; i < len; i++) { - K key = readKeyMember(in, member, kdecoder, first); - in.readBlank(); - V value = readValueMember(in, member, vdecoder, first); - result.put(key, value); - first = false; - } - } - in.readMapE(); - return result; - } - - protected boolean hasNext(Reader in, DeMember member, int startPosition, int contentLength, boolean first) { - return in.hasNext(startPosition, contentLength); - } - - protected Decodeable getKeyDecoder(Decodeable decoder, byte[] typevals) { - return decoder; - } - - protected Decodeable getValueDecoder(Decodeable decoder, byte[] typevals) { - return decoder; - } - - protected Reader getEntryReader(Reader in, DeMember member, boolean first) { - return in; - } - - protected K readKeyMember(Reader in, DeMember member, Decodeable decoder, boolean first) { - return decoder.convertFrom(in); - } - - protected V readValueMember(Reader in, DeMember member, Decodeable decoder, boolean first) { - return decoder.convertFrom(in); - } - - @Override - public Type getType() { - return this.type; - } - - public Type getKeyType() { - return keyType; - } - - public Type getValueType() { - return valueType; - } - - public Decodeable getKeyDecoder() { - return keyDecoder; - } - - public Decodeable getValueDecoder() { - return valueDecoder; - } - -} +/* + * 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.convert; + +import org.redkale.util.Creator; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.*; + +/** + * Map鐨勫弽搴忓垪鍖栨搷浣滅被
+ * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Map key鐨勬暟鎹被鍨 + * @param Map value鐨勬暟鎹被鍨 + */ +@SuppressWarnings("unchecked") +public class MapDecoder implements Decodeable> { + + protected final Type type; + + protected final Type keyType; + + protected final Type valueType; + + protected Creator> creator; + + protected final Decodeable keyDecoder; + + protected final Decodeable valueDecoder; + + protected volatile boolean inited = false; + + protected final Object lock = new Object(); + + public MapDecoder(final ConvertFactory factory, final Type type) { + this.type = type; + try { + if (type == java.util.Properties.class) { + this.keyType = String.class; + this.valueType = String.class; + this.creator = factory.loadCreator(java.util.Properties.class); + factory.register(type, this); + this.keyDecoder = factory.loadDecoder(String.class); + this.valueDecoder = factory.loadDecoder(String.class); + } else if (type instanceof ParameterizedType) { + final ParameterizedType pt = (ParameterizedType) type; + this.keyType = pt.getActualTypeArguments()[0]; + this.valueType = pt.getActualTypeArguments()[1]; + this.creator = factory.loadCreator((Class) pt.getRawType()); + factory.register(type, this); + this.keyDecoder = factory.loadDecoder(this.keyType); + this.valueDecoder = factory.loadDecoder(this.valueType); + } else if (factory.isReversible()) { + this.keyType = Object.class; + this.valueType = Object.class; + this.creator = factory.loadCreator((Class) type); + this.keyDecoder = factory.loadDecoder(this.keyType); + this.valueDecoder = factory.loadDecoder(this.valueType); + } else { + throw new ConvertException("mapdecoder not support the type (" + type + ")"); + } + } finally { + inited = true; + synchronized (lock) { + lock.notifyAll(); + } + } + } + + //浠呬緵绫讳技JsonAnyDecoder杩欑鍔ㄦ佸垱寤轰娇鐢紝 涓嶅緱璋冪敤 factory.register + public MapDecoder(final ConvertFactory factory, Type type, Type keyType, Type valueType, + Creator> creator, final Decodeable keyDecoder, Decodeable valueDecoder) { + Objects.requireNonNull(keyDecoder); + Objects.requireNonNull(valueDecoder); + this.type = type; + this.keyType = keyType; + this.valueType = valueType; + this.creator = creator; + this.keyDecoder = keyDecoder; + this.valueDecoder = valueDecoder; + this.inited = true; + } + + @Override + public Map convertFrom(Reader in) { + return convertFrom(in, null); + } + + public Map convertFrom(Reader in, DeMember member) { + if (this.keyDecoder == null || this.valueDecoder == null) { + if (!this.inited) { + synchronized (lock) { + try { + lock.wait(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + byte[] typevals = new byte[2]; + int len = in.readMapB(member, typevals, this.keyDecoder, this.valueDecoder); + int contentLength = -1; + if (len == Reader.SIGN_NULL) return null; + if (len == Reader.SIGN_NOLENBUTBYTES) { + contentLength = in.readMemberContentLength(member, null); + len = Reader.SIGN_NOLENGTH; + } + final Map result = this.creator.create(); + boolean first = true; + Decodeable kdecoder = getKeyDecoder(this.keyDecoder, typevals); + Decodeable vdecoder = getValueDecoder(this.valueDecoder, typevals); + if (len == Reader.SIGN_NOLENGTH) { + int startPosition = in.position(); + while (hasNext(in, member, startPosition, contentLength, first)) { + Reader entryReader = getEntryReader(in, member, first); + if (entryReader == null) break; + K key = readKeyMember(entryReader, member, kdecoder, first); + entryReader.readBlank(); + V value = readValueMember(entryReader, member, vdecoder, first); + result.put(key, value); + first = false; + } + } else { + for (int i = 0; i < len; i++) { + K key = readKeyMember(in, member, kdecoder, first); + in.readBlank(); + V value = readValueMember(in, member, vdecoder, first); + result.put(key, value); + first = false; + } + } + in.readMapE(); + return result; + } + + protected boolean hasNext(Reader in, DeMember member, int startPosition, int contentLength, boolean first) { + return in.hasNext(startPosition, contentLength); + } + + protected Decodeable getKeyDecoder(Decodeable decoder, byte[] typevals) { + return decoder; + } + + protected Decodeable getValueDecoder(Decodeable decoder, byte[] typevals) { + return decoder; + } + + protected Reader getEntryReader(Reader in, DeMember member, boolean first) { + return in; + } + + protected K readKeyMember(Reader in, DeMember member, Decodeable decoder, boolean first) { + return decoder.convertFrom(in); + } + + protected V readValueMember(Reader in, DeMember member, Decodeable decoder, boolean first) { + return decoder.convertFrom(in); + } + + @Override + public Type getType() { + return this.type; + } + + public Type getKeyType() { + return keyType; + } + + public Type getValueType() { + return valueType; + } + + public Decodeable getKeyDecoder() { + return keyDecoder; + } + + public Decodeable getValueDecoder() { + return valueDecoder; + } + +} diff --git a/src/main/java/org/redkale/convert/MapEncoder.java b/src/main/java/org/redkale/convert/MapEncoder.java index 299aff86d..53f5b0f40 100644 --- a/src/main/java/org/redkale/convert/MapEncoder.java +++ b/src/main/java/org/redkale/convert/MapEncoder.java @@ -1,115 +1,115 @@ -/* - * 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.convert; - -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.util.Map; - -/** - * Map鐨勫簭鍒楀寲鎿嶄綔绫 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Map key鐨勬暟鎹被鍨 - * @param Map value鐨勬暟鎹被鍨 - */ -@SuppressWarnings("unchecked") -public class MapEncoder implements Encodeable> { - - protected final Type type; - - protected final Encodeable keyEncoder; - - protected final Encodeable valueEncoder; - - protected volatile boolean inited = false; - - protected final Object lock = new Object(); - - public MapEncoder(final ConvertFactory factory, final Type type) { - this.type = type; - try { - if (type instanceof ParameterizedType) { - final Type[] pt = ((ParameterizedType) type).getActualTypeArguments(); - this.keyEncoder = factory.loadEncoder(pt[0]); - this.valueEncoder = factory.loadEncoder(pt[1]); - } else { - this.keyEncoder = factory.getAnyEncoder(); - this.valueEncoder = factory.getAnyEncoder(); - } - } finally { - inited = true; - synchronized (lock) { - lock.notifyAll(); - } - } - } - - @Override - public void convertTo(Writer out, Map value) { - convertTo(out, null, value); - } - - public void convertTo(Writer out, EnMember member, Map value) { - final Map values = value; - if (values == null) { - out.writeNull(); - return; - } - - if (this.keyEncoder == null || this.valueEncoder == null) { - if (!this.inited) { - synchronized (lock) { - try { - lock.wait(); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - } - if (out.writeMapB(values.size(), (Encodeable) keyEncoder, (Encodeable) valueEncoder, value) < 0) { - boolean first = true; - for (Map.Entry en : values.entrySet()) { - if (!first) out.writeArrayMark(); - writeMemberValue(out, member, en.getKey(), en.getValue(), first); - if (first) first = false; - } - } - out.writeMapE(); - } - - protected void writeMemberValue(Writer out, EnMember member, K key, V value, boolean first) { - keyEncoder.convertTo(out, key); - out.writeMapMark(); - valueEncoder.convertTo(out, value); - } - - @Override - public Type getType() { - return type; - } - - public Type getKeyType() { - return keyEncoder == null ? null : keyEncoder.getType(); - } - - public Type getValueType() { - return valueEncoder == null ? null : valueEncoder.getType(); - } - - public Encodeable getKeyEncoder() { - return keyEncoder; - } - - public Encodeable getValueEncoder() { - return valueEncoder; - } - -} +/* + * 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.convert; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.Map; + +/** + * Map鐨勫簭鍒楀寲鎿嶄綔绫 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Map key鐨勬暟鎹被鍨 + * @param Map value鐨勬暟鎹被鍨 + */ +@SuppressWarnings("unchecked") +public class MapEncoder implements Encodeable> { + + protected final Type type; + + protected final Encodeable keyEncoder; + + protected final Encodeable valueEncoder; + + protected volatile boolean inited = false; + + protected final Object lock = new Object(); + + public MapEncoder(final ConvertFactory factory, final Type type) { + this.type = type; + try { + if (type instanceof ParameterizedType) { + final Type[] pt = ((ParameterizedType) type).getActualTypeArguments(); + this.keyEncoder = factory.loadEncoder(pt[0]); + this.valueEncoder = factory.loadEncoder(pt[1]); + } else { + this.keyEncoder = factory.getAnyEncoder(); + this.valueEncoder = factory.getAnyEncoder(); + } + } finally { + inited = true; + synchronized (lock) { + lock.notifyAll(); + } + } + } + + @Override + public void convertTo(Writer out, Map value) { + convertTo(out, null, value); + } + + public void convertTo(Writer out, EnMember member, Map value) { + final Map values = value; + if (values == null) { + out.writeNull(); + return; + } + + if (this.keyEncoder == null || this.valueEncoder == null) { + if (!this.inited) { + synchronized (lock) { + try { + lock.wait(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + if (out.writeMapB(values.size(), (Encodeable) keyEncoder, (Encodeable) valueEncoder, value) < 0) { + boolean first = true; + for (Map.Entry en : values.entrySet()) { + if (!first) out.writeArrayMark(); + writeMemberValue(out, member, en.getKey(), en.getValue(), first); + if (first) first = false; + } + } + out.writeMapE(); + } + + protected void writeMemberValue(Writer out, EnMember member, K key, V value, boolean first) { + keyEncoder.convertTo(out, key); + out.writeMapMark(); + valueEncoder.convertTo(out, value); + } + + @Override + public Type getType() { + return type; + } + + public Type getKeyType() { + return keyEncoder == null ? null : keyEncoder.getType(); + } + + public Type getValueType() { + return valueEncoder == null ? null : valueEncoder.getType(); + } + + public Encodeable getKeyEncoder() { + return keyEncoder; + } + + public Encodeable getValueEncoder() { + return valueEncoder; + } + +} diff --git a/src/main/java/org/redkale/convert/ObjectDecoder.java b/src/main/java/org/redkale/convert/ObjectDecoder.java index f0076a69c..41b4f75d5 100644 --- a/src/main/java/org/redkale/convert/ObjectDecoder.java +++ b/src/main/java/org/redkale/convert/ObjectDecoder.java @@ -1,359 +1,359 @@ -/* - * 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.convert; - -import org.redkale.util.Creator; -import java.lang.reflect.*; -import java.util.*; -import org.redkale.convert.ext.StringSimpledCoder; -import org.redkale.util.*; - -/** - * 鑷畾涔夊璞$殑鍙嶅簭鍒楀寲鎿嶄綔绫 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Reader杈撳叆鐨勫瓙绫 - * @param 鍙嶈В鏋愮殑鏁版嵁绫诲瀷 - */ -@SuppressWarnings("unchecked") -public class ObjectDecoder implements Decodeable { - - protected final Type type; - - protected final Class typeClass; - - protected Creator creator; - - protected DeMember[] creatorConstructorMembers = null; - - protected DeMember[] members; - - protected ConvertFactory factory; - - protected volatile boolean inited = false; - - protected final Object lock = new Object(); - - protected ObjectDecoder(Type type) { - this.type = ((type instanceof Class) && ((Class) type).isInterface()) ? Object.class : type; - if (type instanceof ParameterizedType) { - final ParameterizedType pt = (ParameterizedType) type; - this.typeClass = (Class) pt.getRawType(); - } else if (type instanceof TypeVariable) { - TypeVariable tv = (TypeVariable) type; - Type[] ts = tv.getBounds(); - if (ts.length == 1 && ts[0] instanceof Class) { - this.typeClass = (Class) ts[0]; - } else { - throw new ConvertException("[" + type + "] is no a class or ParameterizedType"); - } - } else { - this.typeClass = (Class) type; - } - this.members = new DeMember[0]; - } - - public void init(final ConvertFactory factory) { - this.factory = factory; - try { - if (type == Object.class) { - this.creatorConstructorMembers = null; - return; - } - - Class clazz = null; - if (type instanceof ParameterizedType) { - final ParameterizedType pts = (ParameterizedType) type; - clazz = (Class) (pts).getRawType(); - } else if (type instanceof TypeVariable) { - TypeVariable tv = (TypeVariable) type; - Type[] ts = tv.getBounds(); - if (ts.length == 1 && ts[0] instanceof Class) { - clazz = (Class) ts[0]; - } else { - throw new ConvertException("[" + type + "] is no a class or TypeVariable"); - } - } else if (!(type instanceof Class)) { - throw new ConvertException("[" + type + "] is no a class"); - } else { - clazz = (Class) type; - } - if (!clazz.isInterface() && !Modifier.isAbstract(clazz.getModifiers())) { - this.creator = factory.loadCreator(clazz); - if (this.creator == null) throw new ConvertException("Cannot create a creator for " + clazz); - } - final Set list = new LinkedHashSet(); - final String[] cps = ObjectEncoder.findConstructorProperties(this.creator); - try { - ConvertColumnEntry ref; - RedkaleClassLoader.putReflectionPublicFields(clazz.getName()); - for (final Field field : clazz.getFields()) { - if (Modifier.isStatic(field.getModifiers())) continue; - if (factory.isConvertDisabled(field)) continue; - ref = factory.findRef(clazz, field); - if (ref != null && ref.ignore()) continue; - ConvertSmallString small = field.getAnnotation(ConvertSmallString.class); - Decodeable fieldCoder; - if (small != null && field.getType() == String.class) { - fieldCoder = StringSimpledCoder.SmallStringSimpledCoder.instance; - } else { - fieldCoder = factory.findFieldCoder(clazz, field.getName()); - } - if (fieldCoder == null) { - Type t = TypeToken.createClassType(TypeToken.getGenericType(field.getGenericType(), this.type), this.type); - fieldCoder = factory.loadDecoder(t); - } - DeMember member = new DeMember(ObjectEncoder.createAttribute(factory, type, clazz, field, null, null), fieldCoder, field, null); - if (ref != null) member.index = ref.getIndex(); - list.add(member); - } - final boolean reversible = factory.isReversible(); - RedkaleClassLoader.putReflectionPublicMethods(clazz.getName()); - for (final Method method : clazz.getMethods()) { - if (Modifier.isStatic(method.getModifiers())) continue; - if (Modifier.isAbstract(method.getModifiers())) continue; - if (method.isSynthetic()) continue; - if (method.getReturnType() != void.class) continue; - if (method.getParameterCount() != 1) continue; - if (method.getName().length() < 4) continue; - if (!method.getName().startsWith("set")) continue; - if (factory.isConvertDisabled(method)) continue; - if (reversible && (cps == null || !ObjectEncoder.contains(cps, ConvertFactory.readGetSetFieldName(method)))) { - boolean is = method.getParameterTypes()[0] == boolean.class || method.getParameterTypes()[0] == Boolean.class; - try { - Method getter = clazz.getMethod(method.getName().replaceFirst("set", is ? "is" : "get")); - if (getter.getReturnType() != method.getParameterTypes()[0]) continue; - } catch (Exception e) { - continue; - } - } else { - String fieldname = ConvertFactory.readGetSetFieldName(method); - Field f = null; - try { - f = clazz.getDeclaredField(fieldname); - if (f.getType() != method.getParameterTypes()[0]) continue; - } catch (Exception e) { - } - if (f == null) { - boolean is = method.getParameterTypes()[0] == boolean.class || method.getParameterTypes()[0] == Boolean.class; - try { - Method getter = clazz.getMethod(method.getName().replaceFirst("set", is ? "is" : "get")); - if (getter.getReturnType() != method.getParameterTypes()[0]) continue; - } catch (Exception e) { - } - } - } - ref = factory.findRef(clazz, method); - if (ref != null && ref.ignore()) continue; - - ConvertSmallString small = method.getAnnotation(ConvertSmallString.class); - Decodeable fieldCoder; - if (small != null && method.getReturnType() == String.class) { - fieldCoder = StringSimpledCoder.SmallStringSimpledCoder.instance; - } else { - fieldCoder = factory.findFieldCoder(clazz, ConvertFactory.readGetSetFieldName(method)); - } - if (fieldCoder == null) { - Type t = TypeToken.createClassType(TypeToken.getGenericType(method.getGenericParameterTypes()[0], this.type), this.type); - fieldCoder = factory.loadDecoder(t); - } - DeMember member = new DeMember(ObjectEncoder.createAttribute(factory, type, clazz, null, null, method), fieldCoder, ConvertFactory.readGetSetField(method), method); - if (ref != null) member.index = ref.getIndex(); - list.add(member); - } - if (cps != null) { //鍙兘瀛樺湪鏌愪簺鏋勯犲嚱鏁颁腑鐨勫瓧娈靛悕涓嶅瓨鍦╯etter鏂规硶 - for (final String constructorField : cps) { - boolean flag = false; - for (DeMember m : list) { - if (m.attribute.field().equals(constructorField)) { - flag = true; - break; - } - } - if (flag) continue; - //涓嶅瓨鍦╯etter鏂规硶 - try { - Field f = clazz.getDeclaredField(constructorField); - Type t = TypeToken.createClassType(f.getGenericType(), this.type); - list.add(new DeMember(ObjectEncoder.createAttribute(factory, type, clazz, f, null, null), factory.loadDecoder(t), f, null)); - } catch (NoSuchFieldException nsfe) { //涓嶅瓨鍦╢ield锛 鍙兘瀛樺湪getter鏂规硶 - char[] fs = constructorField.toCharArray(); - fs[0] = Character.toUpperCase(fs[0]); - String mn = new String(fs); - Method getter; - try { - getter = clazz.getMethod("get" + mn); - } catch (NoSuchMethodException ex) { - getter = clazz.getMethod("is" + mn); - } - Type t = TypeToken.createClassType(TypeToken.getGenericType(getter.getGenericParameterTypes()[0], this.type), this.type); - list.add(new DeMember(ObjectEncoder.createAttribute(factory, type, clazz, null, getter, null), factory.loadDecoder(t), ConvertFactory.readGetSetField(getter), getter)); - } - } - } - - List sorts = new ArrayList<>(list); - Collections.sort(sorts, (a, b) -> a.compareTo(factory.isFieldSort(), b)); - Set pos = new HashSet<>(); - for (DeMember member : sorts) { - if (member.index > 0) pos.add(member.index); - } - int pidx = 0; - for (DeMember member : sorts) { - if (member.index > 0) { - member.position = member.index; - } else { - while (pos.contains(++pidx)); - member.position = pidx; - } - initForEachDeMember(factory, member); - } - - this.members = list.toArray(new DeMember[list.size()]); - Arrays.sort(this.members, (a, b) -> a.compareTo(factory.isFieldSort(), b)); - - if (cps != null) { - final String[] fields = cps; - final DeMember[] ms = new DeMember[fields.length]; - for (int i = 0; i < fields.length; i++) { - for (DeMember m : this.members) { - if (m.attribute.field().equals(fields[i])) { - ms[i] = m; - break; - } - } - } - this.creatorConstructorMembers = ms; - } - } catch (Exception ex) { - throw new ConvertException(ex); - } - } finally { - inited = true; - synchronized (lock) { - lock.notifyAll(); - } - } - } - - protected void initForEachDeMember(ConvertFactory factory, DeMember member) { - } - - protected void setTag(DeMember member, int tag) { - member.tag = tag; - } - - /** - * 瀵硅薄鏍煎紡: [0x1][short瀛楁涓暟][瀛楁鍚峕[瀛楁鍊糫...[0x2] - * - * @param in 杈撳叆娴 - * - * @return 鍙嶈В鏋愬悗鐨勫璞$粨鏋 - */ - @Override - public T convertFrom(final R in) { - R objin = objectReader(in); - final String clazz = objin.readObjectB(typeClass); - if (clazz == null) return null; - if (!clazz.isEmpty()) return (T) factory.loadDecoder(factory.getEntityAlias(clazz)).convertFrom(objin); - if (!this.inited) { - synchronized (lock) { - try { - lock.wait(); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - if (this.creator == null) { - if (typeClass.isInterface() || Modifier.isAbstract(typeClass.getModifiers())) { - throw new ConvertException("[" + typeClass + "] is a interface or abstract class, cannot create it's Creator."); - } - } - if (this.creatorConstructorMembers == null) { //绌烘瀯閫犲嚱鏁 - final T result = this.creator == null ? null : this.creator.create(); - boolean first = true; - while (hasNext(objin, first)) { - DeMember member = objin.readFieldName(members); - objin.readBlank(); - if (member == null) { - objin.skipValue(); //璺宠繃涓嶅瓨鍦ㄧ殑灞炴х殑鍊 - } else { - readMemberValue(objin, member, result, first); - } - first = false; - } - objin.readObjectE(typeClass); - return result; - } else { //甯﹀弬鏁扮殑鏋勯犲嚱鏁 - final DeMember[] fields = this.creatorConstructorMembers; - final Object[] constructorParams = new Object[fields.length]; - final Object[][] otherParams = new Object[this.members.length][2]; - int oc = 0; - boolean first = true; - while (hasNext(objin, first)) { - DeMember member = objin.readFieldName(members); - objin.readBlank(); - if (member == null) { - objin.skipValue(); //璺宠繃涓嶅瓨鍦ㄧ殑灞炴х殑鍊 - } else { - Object val = readMemberValue(objin, member, first); - boolean flag = true; - for (int i = 0; i < fields.length; i++) { - if (member == fields[i]) { - constructorParams[i] = val; - flag = false; - break; - } - } - if (flag) otherParams[oc++] = new Object[]{member.attribute, val}; - - } - first = false; - } - objin.readObjectE(typeClass); - if (this.creator == null) return null; - final T result = this.creator.create(constructorParams); - for (int i = 0; i < oc; i++) { - ((Attribute) otherParams[i][0]).set(result, otherParams[i][1]); - } - return result; - } - } - - protected R objectReader(R in) { - return in; - } - - protected boolean hasNext(R in, boolean first) { - return in.hasNext(); - } - - protected Object readMemberValue(R in, DeMember member, boolean first) { - return member.read(in); - } - - protected void readMemberValue(R in, DeMember member, T result, boolean first) { - member.read(in, result); - } - - @Override - public Type getType() { - return this.type; - } - - public DeMember[] getMembers() { - return Arrays.copyOf(members, members.length); - } - - @Override - public String toString() { - return "ObjectDecoder{" + "type=" + type + ", members=" + Arrays.toString(members) + '}'; - } -} +/* + * 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.convert; + +import org.redkale.util.Creator; +import java.lang.reflect.*; +import java.util.*; +import org.redkale.convert.ext.StringSimpledCoder; +import org.redkale.util.*; + +/** + * 鑷畾涔夊璞$殑鍙嶅簭鍒楀寲鎿嶄綔绫 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Reader杈撳叆鐨勫瓙绫 + * @param 鍙嶈В鏋愮殑鏁版嵁绫诲瀷 + */ +@SuppressWarnings("unchecked") +public class ObjectDecoder implements Decodeable { + + protected final Type type; + + protected final Class typeClass; + + protected Creator creator; + + protected DeMember[] creatorConstructorMembers = null; + + protected DeMember[] members; + + protected ConvertFactory factory; + + protected volatile boolean inited = false; + + protected final Object lock = new Object(); + + protected ObjectDecoder(Type type) { + this.type = ((type instanceof Class) && ((Class) type).isInterface()) ? Object.class : type; + if (type instanceof ParameterizedType) { + final ParameterizedType pt = (ParameterizedType) type; + this.typeClass = (Class) pt.getRawType(); + } else if (type instanceof TypeVariable) { + TypeVariable tv = (TypeVariable) type; + Type[] ts = tv.getBounds(); + if (ts.length == 1 && ts[0] instanceof Class) { + this.typeClass = (Class) ts[0]; + } else { + throw new ConvertException("[" + type + "] is no a class or ParameterizedType"); + } + } else { + this.typeClass = (Class) type; + } + this.members = new DeMember[0]; + } + + public void init(final ConvertFactory factory) { + this.factory = factory; + try { + if (type == Object.class) { + this.creatorConstructorMembers = null; + return; + } + + Class clazz = null; + if (type instanceof ParameterizedType) { + final ParameterizedType pts = (ParameterizedType) type; + clazz = (Class) (pts).getRawType(); + } else if (type instanceof TypeVariable) { + TypeVariable tv = (TypeVariable) type; + Type[] ts = tv.getBounds(); + if (ts.length == 1 && ts[0] instanceof Class) { + clazz = (Class) ts[0]; + } else { + throw new ConvertException("[" + type + "] is no a class or TypeVariable"); + } + } else if (!(type instanceof Class)) { + throw new ConvertException("[" + type + "] is no a class"); + } else { + clazz = (Class) type; + } + if (!clazz.isInterface() && !Modifier.isAbstract(clazz.getModifiers())) { + this.creator = factory.loadCreator(clazz); + if (this.creator == null) throw new ConvertException("Cannot create a creator for " + clazz); + } + final Set list = new LinkedHashSet(); + final String[] cps = ObjectEncoder.findConstructorProperties(this.creator); + try { + ConvertColumnEntry ref; + RedkaleClassLoader.putReflectionPublicFields(clazz.getName()); + for (final Field field : clazz.getFields()) { + if (Modifier.isStatic(field.getModifiers())) continue; + if (factory.isConvertDisabled(field)) continue; + ref = factory.findRef(clazz, field); + if (ref != null && ref.ignore()) continue; + ConvertSmallString small = field.getAnnotation(ConvertSmallString.class); + Decodeable fieldCoder; + if (small != null && field.getType() == String.class) { + fieldCoder = StringSimpledCoder.SmallStringSimpledCoder.instance; + } else { + fieldCoder = factory.findFieldCoder(clazz, field.getName()); + } + if (fieldCoder == null) { + Type t = TypeToken.createClassType(TypeToken.getGenericType(field.getGenericType(), this.type), this.type); + fieldCoder = factory.loadDecoder(t); + } + DeMember member = new DeMember(ObjectEncoder.createAttribute(factory, type, clazz, field, null, null), fieldCoder, field, null); + if (ref != null) member.index = ref.getIndex(); + list.add(member); + } + final boolean reversible = factory.isReversible(); + RedkaleClassLoader.putReflectionPublicMethods(clazz.getName()); + for (final Method method : clazz.getMethods()) { + if (Modifier.isStatic(method.getModifiers())) continue; + if (Modifier.isAbstract(method.getModifiers())) continue; + if (method.isSynthetic()) continue; + if (method.getReturnType() != void.class) continue; + if (method.getParameterCount() != 1) continue; + if (method.getName().length() < 4) continue; + if (!method.getName().startsWith("set")) continue; + if (factory.isConvertDisabled(method)) continue; + if (reversible && (cps == null || !ObjectEncoder.contains(cps, ConvertFactory.readGetSetFieldName(method)))) { + boolean is = method.getParameterTypes()[0] == boolean.class || method.getParameterTypes()[0] == Boolean.class; + try { + Method getter = clazz.getMethod(method.getName().replaceFirst("set", is ? "is" : "get")); + if (getter.getReturnType() != method.getParameterTypes()[0]) continue; + } catch (Exception e) { + continue; + } + } else { + String fieldname = ConvertFactory.readGetSetFieldName(method); + Field f = null; + try { + f = clazz.getDeclaredField(fieldname); + if (f.getType() != method.getParameterTypes()[0]) continue; + } catch (Exception e) { + } + if (f == null) { + boolean is = method.getParameterTypes()[0] == boolean.class || method.getParameterTypes()[0] == Boolean.class; + try { + Method getter = clazz.getMethod(method.getName().replaceFirst("set", is ? "is" : "get")); + if (getter.getReturnType() != method.getParameterTypes()[0]) continue; + } catch (Exception e) { + } + } + } + ref = factory.findRef(clazz, method); + if (ref != null && ref.ignore()) continue; + + ConvertSmallString small = method.getAnnotation(ConvertSmallString.class); + Decodeable fieldCoder; + if (small != null && method.getReturnType() == String.class) { + fieldCoder = StringSimpledCoder.SmallStringSimpledCoder.instance; + } else { + fieldCoder = factory.findFieldCoder(clazz, ConvertFactory.readGetSetFieldName(method)); + } + if (fieldCoder == null) { + Type t = TypeToken.createClassType(TypeToken.getGenericType(method.getGenericParameterTypes()[0], this.type), this.type); + fieldCoder = factory.loadDecoder(t); + } + DeMember member = new DeMember(ObjectEncoder.createAttribute(factory, type, clazz, null, null, method), fieldCoder, ConvertFactory.readGetSetField(method), method); + if (ref != null) member.index = ref.getIndex(); + list.add(member); + } + if (cps != null) { //鍙兘瀛樺湪鏌愪簺鏋勯犲嚱鏁颁腑鐨勫瓧娈靛悕涓嶅瓨鍦╯etter鏂规硶 + for (final String constructorField : cps) { + boolean flag = false; + for (DeMember m : list) { + if (m.attribute.field().equals(constructorField)) { + flag = true; + break; + } + } + if (flag) continue; + //涓嶅瓨鍦╯etter鏂规硶 + try { + Field f = clazz.getDeclaredField(constructorField); + Type t = TypeToken.createClassType(f.getGenericType(), this.type); + list.add(new DeMember(ObjectEncoder.createAttribute(factory, type, clazz, f, null, null), factory.loadDecoder(t), f, null)); + } catch (NoSuchFieldException nsfe) { //涓嶅瓨鍦╢ield锛 鍙兘瀛樺湪getter鏂规硶 + char[] fs = constructorField.toCharArray(); + fs[0] = Character.toUpperCase(fs[0]); + String mn = new String(fs); + Method getter; + try { + getter = clazz.getMethod("get" + mn); + } catch (NoSuchMethodException ex) { + getter = clazz.getMethod("is" + mn); + } + Type t = TypeToken.createClassType(TypeToken.getGenericType(getter.getGenericParameterTypes()[0], this.type), this.type); + list.add(new DeMember(ObjectEncoder.createAttribute(factory, type, clazz, null, getter, null), factory.loadDecoder(t), ConvertFactory.readGetSetField(getter), getter)); + } + } + } + + List sorts = new ArrayList<>(list); + Collections.sort(sorts, (a, b) -> a.compareTo(factory.isFieldSort(), b)); + Set pos = new HashSet<>(); + for (DeMember member : sorts) { + if (member.index > 0) pos.add(member.index); + } + int pidx = 0; + for (DeMember member : sorts) { + if (member.index > 0) { + member.position = member.index; + } else { + while (pos.contains(++pidx)); + member.position = pidx; + } + initForEachDeMember(factory, member); + } + + this.members = list.toArray(new DeMember[list.size()]); + Arrays.sort(this.members, (a, b) -> a.compareTo(factory.isFieldSort(), b)); + + if (cps != null) { + final String[] fields = cps; + final DeMember[] ms = new DeMember[fields.length]; + for (int i = 0; i < fields.length; i++) { + for (DeMember m : this.members) { + if (m.attribute.field().equals(fields[i])) { + ms[i] = m; + break; + } + } + } + this.creatorConstructorMembers = ms; + } + } catch (Exception ex) { + throw new ConvertException(ex); + } + } finally { + inited = true; + synchronized (lock) { + lock.notifyAll(); + } + } + } + + protected void initForEachDeMember(ConvertFactory factory, DeMember member) { + } + + protected void setTag(DeMember member, int tag) { + member.tag = tag; + } + + /** + * 瀵硅薄鏍煎紡: [0x1][short瀛楁涓暟][瀛楁鍚峕[瀛楁鍊糫...[0x2] + * + * @param in 杈撳叆娴 + * + * @return 鍙嶈В鏋愬悗鐨勫璞$粨鏋 + */ + @Override + public T convertFrom(final R in) { + R objin = objectReader(in); + final String clazz = objin.readObjectB(typeClass); + if (clazz == null) return null; + if (!clazz.isEmpty()) return (T) factory.loadDecoder(factory.getEntityAlias(clazz)).convertFrom(objin); + if (!this.inited) { + synchronized (lock) { + try { + lock.wait(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + if (this.creator == null) { + if (typeClass.isInterface() || Modifier.isAbstract(typeClass.getModifiers())) { + throw new ConvertException("[" + typeClass + "] is a interface or abstract class, cannot create it's Creator."); + } + } + if (this.creatorConstructorMembers == null) { //绌烘瀯閫犲嚱鏁 + final T result = this.creator == null ? null : this.creator.create(); + boolean first = true; + while (hasNext(objin, first)) { + DeMember member = objin.readFieldName(members); + objin.readBlank(); + if (member == null) { + objin.skipValue(); //璺宠繃涓嶅瓨鍦ㄧ殑灞炴х殑鍊 + } else { + readMemberValue(objin, member, result, first); + } + first = false; + } + objin.readObjectE(typeClass); + return result; + } else { //甯﹀弬鏁扮殑鏋勯犲嚱鏁 + final DeMember[] fields = this.creatorConstructorMembers; + final Object[] constructorParams = new Object[fields.length]; + final Object[][] otherParams = new Object[this.members.length][2]; + int oc = 0; + boolean first = true; + while (hasNext(objin, first)) { + DeMember member = objin.readFieldName(members); + objin.readBlank(); + if (member == null) { + objin.skipValue(); //璺宠繃涓嶅瓨鍦ㄧ殑灞炴х殑鍊 + } else { + Object val = readMemberValue(objin, member, first); + boolean flag = true; + for (int i = 0; i < fields.length; i++) { + if (member == fields[i]) { + constructorParams[i] = val; + flag = false; + break; + } + } + if (flag) otherParams[oc++] = new Object[]{member.attribute, val}; + + } + first = false; + } + objin.readObjectE(typeClass); + if (this.creator == null) return null; + final T result = this.creator.create(constructorParams); + for (int i = 0; i < oc; i++) { + ((Attribute) otherParams[i][0]).set(result, otherParams[i][1]); + } + return result; + } + } + + protected R objectReader(R in) { + return in; + } + + protected boolean hasNext(R in, boolean first) { + return in.hasNext(); + } + + protected Object readMemberValue(R in, DeMember member, boolean first) { + return member.read(in); + } + + protected void readMemberValue(R in, DeMember member, T result, boolean first) { + member.read(in, result); + } + + @Override + public Type getType() { + return this.type; + } + + public DeMember[] getMembers() { + return Arrays.copyOf(members, members.length); + } + + @Override + public String toString() { + return "ObjectDecoder{" + "type=" + type + ", members=" + Arrays.toString(members) + '}'; + } +} diff --git a/src/main/java/org/redkale/convert/ObjectEncoder.java b/src/main/java/org/redkale/convert/ObjectEncoder.java index 1aa21cd4c..95fb0b317 100644 --- a/src/main/java/org/redkale/convert/ObjectEncoder.java +++ b/src/main/java/org/redkale/convert/ObjectEncoder.java @@ -1,378 +1,378 @@ -/* - * 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.convert; - -import java.lang.reflect.*; -import java.util.*; -import org.redkale.convert.ext.StringSimpledCoder; -import org.redkale.util.*; - -/** - * 鑷畾涔夊璞$殑搴忓垪鍖栨搷浣滅被 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Writer杈撳嚭鐨勫瓙绫 - * @param 搴忓垪鍖栫殑鏁版嵁绫诲瀷 - */ -@SuppressWarnings("unchecked") -public class ObjectEncoder implements Encodeable { - - static final Type[] TYPEZERO = new Type[0]; - - protected final Type type; - - protected final Class typeClass; - - protected EnMember[] members; - - protected ConvertFactory factory; - - protected volatile boolean inited = false; - - protected final Object lock = new Object(); - - protected ObjectEncoder(Type type) { - this.type = type; - if (type instanceof ParameterizedType) { - final ParameterizedType pt = (ParameterizedType) type; - this.typeClass = (Class) pt.getRawType(); - } else if (type instanceof TypeVariable) { - TypeVariable tv = (TypeVariable) type; - Type[] ts = tv.getBounds(); - if (ts.length == 1 && ts[0] instanceof Class) { - this.typeClass = (Class) ts[0]; - } else { - throw new ConvertException("[" + type + "] is no a class or ParameterizedType"); - } - } else { - this.typeClass = (Class) type; - } - this.members = new EnMember[0]; - } - - public void init(final ConvertFactory factory) { - this.factory = factory; - try { - if (type == Object.class) return; - //if (!(type instanceof Class)) throw new ConvertException("[" + type + "] is no a class"); - final Class clazz = this.typeClass; - final Set list = new LinkedHashSet(); - final boolean reversible = factory.isReversible(); - Creator creator = null; - try { - creator = factory.loadCreator(this.typeClass); - } catch (RuntimeException e) { - if (reversible && !Modifier.isAbstract(this.typeClass.getModifiers())) throw e; - } - final String[] cps = creator == null ? null : ObjectEncoder.findConstructorProperties(creator); - try { - ConvertColumnEntry ref; - - RedkaleClassLoader.putReflectionPublicFields(clazz.getName()); - for (final Field field : clazz.getFields()) { - if (Modifier.isStatic(field.getModifiers())) continue; - if (factory.isConvertDisabled(field)) continue; - ref = factory.findRef(clazz, field); - if (ref != null && ref.ignore()) continue; - ConvertSmallString small = field.getAnnotation(ConvertSmallString.class); - Encodeable fieldCoder; - if (small != null && field.getType() == String.class) { - fieldCoder = StringSimpledCoder.SmallStringSimpledCoder.instance; - } else { - fieldCoder = factory.findFieldCoder(clazz, field.getName()); - } - if (fieldCoder == null) { - Type t = TypeToken.createClassType(TypeToken.getGenericType(field.getGenericType(), this.type), this.type); - fieldCoder = factory.loadEncoder(t); - } - EnMember member = new EnMember(createAttribute(factory, type, clazz, field, null, null), fieldCoder, field, null); - if (ref != null) member.index = ref.getIndex(); - list.add(member); - } - - RedkaleClassLoader.putReflectionPublicMethods(clazz.getName()); - for (final Method method : clazz.getMethods()) { - if (Modifier.isStatic(method.getModifiers())) continue; - if (Modifier.isAbstract(method.getModifiers())) continue; - if (method.isSynthetic()) continue; - if (method.getName().equals("getClass")) continue; - if (method.getReturnType() == void.class) continue; - if (method.getParameterCount() != 0) continue; - if (!method.getName().startsWith("is") && !method.getName().startsWith("get") && !Utility.isRecordGetter(clazz, method)) continue; - if (factory.isConvertDisabled(method)) continue; - String convertname = ConvertFactory.readGetSetFieldName(method); - if (reversible && (cps == null || !contains(cps, convertname))) { - boolean is = method.getName().startsWith("is"); - try { - clazz.getMethod(method.getName().replaceFirst(is ? "is" : "get", "set"), method.getReturnType()); - } catch (Exception e) { - continue; - } - } - ref = factory.findRef(clazz, method); - if (ref != null && ref.ignore()) continue; - ConvertSmallString small = method.getAnnotation(ConvertSmallString.class); - if (small == null) { - try { - Field f = clazz.getDeclaredField(convertname); - if (f != null) small = f.getAnnotation(ConvertSmallString.class); - } catch (Exception e) { - } - } - Encodeable fieldCoder; - if (small != null && method.getReturnType() == String.class) { - fieldCoder = StringSimpledCoder.SmallStringSimpledCoder.instance; - } else { - fieldCoder = factory.findFieldCoder(clazz, ConvertFactory.readGetSetFieldName(method)); - } - if (fieldCoder == null) { - Type t = TypeToken.createClassType(TypeToken.getGenericType(method.getGenericReturnType(), this.type), this.type); - fieldCoder = factory.loadEncoder(t); - } - EnMember member = new EnMember(createAttribute(factory, type, clazz, null, method, null), fieldCoder, ConvertFactory.readGetSetField(method), method); - if (ref != null) member.index = ref.getIndex(); - list.add(member); - } - List sorts = new ArrayList<>(list); - if (cps != null) { - Set dissorts = new LinkedHashSet<>(list); - for (final String constructorField : cps) { //reversible妯″紡涓嬮渶瑕佺‘淇滵eMember涓嶦nMember鐨勪釜鏁板拰椤哄簭淇濇寔涓鑷达紝涓嶇劧postition浼氫笉涓鑷村鑷村弽搴忓垪鍖栧搴旂殑瀛楁椤哄簭涓嶅悓 - boolean flag = false; - for (EnMember m : dissorts) { - if (m.attribute.field().equals(constructorField)) { - flag = true; - break; - } - } - if (flag) continue; - //涓嶅瓨鍦╯etter鏂规硶 - try { - Field f = clazz.getDeclaredField(constructorField); - Type t = TypeToken.createClassType(f.getGenericType(), this.type); - try { - dissorts.add(new EnMember(createAttribute(factory, type, clazz, f, null, null), null, f, null)); //铏氭瀯 - } catch (RuntimeException e) { - } - } catch (NoSuchFieldException nsfe) { //涓嶅瓨鍦╢ield锛 鍙兘瀛樺湪getter鏂规硶 - char[] fs = constructorField.toCharArray(); - fs[0] = Character.toUpperCase(fs[0]); - String mn = new String(fs); - Method getter; - try { - getter = clazz.getMethod("get" + mn); - } catch (NoSuchMethodException ex) { - getter = clazz.getMethod("is" + mn); - } - Type t = TypeToken.createClassType(TypeToken.getGenericType(getter.getGenericParameterTypes()[0], this.type), this.type); - try { - dissorts.add(new EnMember(createAttribute(factory, type, clazz, null, getter, null), null, null, null)); //铏氭瀯 - } catch (RuntimeException e) { - } - } - } - if (dissorts.size() != list.size()) sorts = new ArrayList<>(dissorts); - } - Collections.sort(sorts, (a, b) -> a.compareTo(factory.isFieldSort(), b)); - Set pos = new HashSet<>(); - for (EnMember member : sorts) { - if (member.index > 0) pos.add(member.index); - } - int pidx = 0; - for (EnMember member : sorts) { - if (member.index > 0) { - member.position = member.index; - } else { - while (pos.contains(++pidx)); - member.position = pidx; - } - initForEachEnMember(factory, member); - } - - this.members = list.toArray(new EnMember[list.size()]); - Arrays.sort(this.members, (a, b) -> a.compareTo(factory.isFieldSort(), b)); - - } catch (Exception ex) { - throw new ConvertException("ObjectEncoder init type=" + this.type + " error", ex); - } - } finally { - inited = true; - synchronized (lock) { - lock.notifyAll(); - } - } - } - - protected void initForEachEnMember(ConvertFactory factory, EnMember member) { - } - - protected void setTag(EnMember member, int tag) { - member.tag = tag; - } - - @Override - public void convertTo(W out, T value) { - if (value == null) { - out.writeObjectNull(null); - return; - } - if (!this.inited) { - synchronized (lock) { - try { - lock.wait(); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - if (value.getClass() != this.typeClass && !this.type.equals(out.specify())) { - final Class clz = value.getClass(); - if (out.needWriteClassName()) out.writeClassName(factory.getEntityAlias(clz)); - factory.loadEncoder(clz).convertTo(out, value); - return; - } - W objout = objectWriter(out, value); - if (objout.writeObjectB(value) < 0) { - int maxPosition = 0; - for (EnMember member : members) { - maxPosition = member.getPosition(); - objout.writeObjectField(member, value); - } - if (objout.objExtFunc != null) { - ConvertField[] extFields = objout.objExtFunc.apply(value); - if (extFields != null) { - Encodeable anyEncoder = factory.getAnyEncoder(); - for (ConvertField en : extFields) { - if (en == null) continue; - maxPosition++; - objout.writeObjectField(en.getName(), en.getType(), Math.max(en.getPosition(), maxPosition), anyEncoder, en.getValue()); - } - } - } - } - objout.writeObjectE(value); - } - - protected W objectWriter(W out, T value) { - return out; - } - - @Override - public Type getType() { - return this.type; - } - - public Class getTypeClass() { - return this.typeClass; - } - - public EnMember[] getMembers() { - return Arrays.copyOf(members, members.length); - } - - @Override - public String toString() { - return "ObjectEncoder{" + "type=" + type + ", members=" + Arrays.toString(members) + '}'; - } - -// -// static Type makeGenericType(final Type type, final Type[] virGenericTypes, final Type[] realGenericTypes) { -// if (type instanceof Class) { //e.g. String -// return type; -// } else if (type instanceof ParameterizedType) { //e.g. Map -// final ParameterizedType pt = (ParameterizedType) type; -// Type[] paramTypes = pt.getActualTypeArguments(); -// final Type[] newTypes = new Type[paramTypes.length]; -// int count = 0; -// for (int i = 0; i < newTypes.length; i++) { -// newTypes[i] = makeGenericType(paramTypes[i], virGenericTypes, realGenericTypes); -// if (paramTypes[i] == newTypes[i]) count++; -// } -// if (count == paramTypes.length) return pt; -// return new ParameterizedType() { -// -// @Override -// public Type[] getActualTypeArguments() { -// return newTypes; -// } -// -// @Override -// public Type getRawType() { -// return pt.getRawType(); -// } -// -// @Override -// public Type getOwnerType() { -// return pt.getOwnerType(); -// } -// -// }; -// } -// if (realGenericTypes == null) return type; -// if (type instanceof WildcardType) { // e.g. -// final WildcardType wt = (WildcardType) type; -// for (Type f : wt.getUpperBounds()) { -// for (int i = 0; i < virGenericTypes.length; i++) { -// if (virGenericTypes[i] == f) return realGenericTypes.length == 0 ? Object.class : realGenericTypes[i]; -// } -// } -// } else if (type instanceof TypeVariable) { // e.g. -// for (int i = 0; i < virGenericTypes.length; i++) { -// if (virGenericTypes[i] == type) return i >= realGenericTypes.length ? Object.class : realGenericTypes[i]; -// } -// } -// return type; -// } - static boolean contains(String[] values, String value) { - for (String str : values) { - if (str.equals(value)) return true; - } - return false; - } - - static String[] findConstructorProperties(Creator creator) { - if (creator == null) return null; - try { - ConstructorParameters cps = creator.getClass().getMethod("create", Object[].class).getAnnotation(ConstructorParameters.class); - return cps == null ? null : cps.value(); - } catch (Exception e) { - return null; - } - } - - static Attribute createAttribute(final ConvertFactory factory, final Type realType, Class clazz, final Field field, final Method getter, final Method setter) { - String fieldalias; - if (field != null) { // public field - ConvertColumnEntry ref = factory.findRef(clazz, field); - fieldalias = ref == null || ref.name().isEmpty() ? field.getName() : ref.name(); - } else if (getter != null) { - ConvertColumnEntry ref = factory.findRef(clazz, getter); - String mfieldname = ConvertFactory.readGetSetFieldName(getter); - if (ref == null) { - try { - ref = factory.findRef(clazz, clazz.getDeclaredField(mfieldname)); - } catch (Exception e) { - } - } - fieldalias = ref == null || ref.name().isEmpty() ? mfieldname : ref.name(); - } else { // setter != null - ConvertColumnEntry ref = factory.findRef(clazz, setter); - String mfieldname = ConvertFactory.readGetSetFieldName(setter); - if (ref == null) { - try { - ref = factory.findRef(clazz, clazz.getDeclaredField(mfieldname)); - } catch (Exception e) { - } - } - fieldalias = ref == null || ref.name().isEmpty() ? mfieldname : ref.name(); - } - - return Attribute.create(realType, clazz, fieldalias, null, field, getter, setter, null); - } - -} +/* + * 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.convert; + +import java.lang.reflect.*; +import java.util.*; +import org.redkale.convert.ext.StringSimpledCoder; +import org.redkale.util.*; + +/** + * 鑷畾涔夊璞$殑搴忓垪鍖栨搷浣滅被 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Writer杈撳嚭鐨勫瓙绫 + * @param 搴忓垪鍖栫殑鏁版嵁绫诲瀷 + */ +@SuppressWarnings("unchecked") +public class ObjectEncoder implements Encodeable { + + static final Type[] TYPEZERO = new Type[0]; + + protected final Type type; + + protected final Class typeClass; + + protected EnMember[] members; + + protected ConvertFactory factory; + + protected volatile boolean inited = false; + + protected final Object lock = new Object(); + + protected ObjectEncoder(Type type) { + this.type = type; + if (type instanceof ParameterizedType) { + final ParameterizedType pt = (ParameterizedType) type; + this.typeClass = (Class) pt.getRawType(); + } else if (type instanceof TypeVariable) { + TypeVariable tv = (TypeVariable) type; + Type[] ts = tv.getBounds(); + if (ts.length == 1 && ts[0] instanceof Class) { + this.typeClass = (Class) ts[0]; + } else { + throw new ConvertException("[" + type + "] is no a class or ParameterizedType"); + } + } else { + this.typeClass = (Class) type; + } + this.members = new EnMember[0]; + } + + public void init(final ConvertFactory factory) { + this.factory = factory; + try { + if (type == Object.class) return; + //if (!(type instanceof Class)) throw new ConvertException("[" + type + "] is no a class"); + final Class clazz = this.typeClass; + final Set list = new LinkedHashSet(); + final boolean reversible = factory.isReversible(); + Creator creator = null; + try { + creator = factory.loadCreator(this.typeClass); + } catch (RuntimeException e) { + if (reversible && !Modifier.isAbstract(this.typeClass.getModifiers())) throw e; + } + final String[] cps = creator == null ? null : ObjectEncoder.findConstructorProperties(creator); + try { + ConvertColumnEntry ref; + + RedkaleClassLoader.putReflectionPublicFields(clazz.getName()); + for (final Field field : clazz.getFields()) { + if (Modifier.isStatic(field.getModifiers())) continue; + if (factory.isConvertDisabled(field)) continue; + ref = factory.findRef(clazz, field); + if (ref != null && ref.ignore()) continue; + ConvertSmallString small = field.getAnnotation(ConvertSmallString.class); + Encodeable fieldCoder; + if (small != null && field.getType() == String.class) { + fieldCoder = StringSimpledCoder.SmallStringSimpledCoder.instance; + } else { + fieldCoder = factory.findFieldCoder(clazz, field.getName()); + } + if (fieldCoder == null) { + Type t = TypeToken.createClassType(TypeToken.getGenericType(field.getGenericType(), this.type), this.type); + fieldCoder = factory.loadEncoder(t); + } + EnMember member = new EnMember(createAttribute(factory, type, clazz, field, null, null), fieldCoder, field, null); + if (ref != null) member.index = ref.getIndex(); + list.add(member); + } + + RedkaleClassLoader.putReflectionPublicMethods(clazz.getName()); + for (final Method method : clazz.getMethods()) { + if (Modifier.isStatic(method.getModifiers())) continue; + if (Modifier.isAbstract(method.getModifiers())) continue; + if (method.isSynthetic()) continue; + if (method.getName().equals("getClass")) continue; + if (method.getReturnType() == void.class) continue; + if (method.getParameterCount() != 0) continue; + if (!method.getName().startsWith("is") && !method.getName().startsWith("get") && !Utility.isRecordGetter(clazz, method)) continue; + if (factory.isConvertDisabled(method)) continue; + String convertname = ConvertFactory.readGetSetFieldName(method); + if (reversible && (cps == null || !contains(cps, convertname))) { + boolean is = method.getName().startsWith("is"); + try { + clazz.getMethod(method.getName().replaceFirst(is ? "is" : "get", "set"), method.getReturnType()); + } catch (Exception e) { + continue; + } + } + ref = factory.findRef(clazz, method); + if (ref != null && ref.ignore()) continue; + ConvertSmallString small = method.getAnnotation(ConvertSmallString.class); + if (small == null) { + try { + Field f = clazz.getDeclaredField(convertname); + if (f != null) small = f.getAnnotation(ConvertSmallString.class); + } catch (Exception e) { + } + } + Encodeable fieldCoder; + if (small != null && method.getReturnType() == String.class) { + fieldCoder = StringSimpledCoder.SmallStringSimpledCoder.instance; + } else { + fieldCoder = factory.findFieldCoder(clazz, ConvertFactory.readGetSetFieldName(method)); + } + if (fieldCoder == null) { + Type t = TypeToken.createClassType(TypeToken.getGenericType(method.getGenericReturnType(), this.type), this.type); + fieldCoder = factory.loadEncoder(t); + } + EnMember member = new EnMember(createAttribute(factory, type, clazz, null, method, null), fieldCoder, ConvertFactory.readGetSetField(method), method); + if (ref != null) member.index = ref.getIndex(); + list.add(member); + } + List sorts = new ArrayList<>(list); + if (cps != null) { + Set dissorts = new LinkedHashSet<>(list); + for (final String constructorField : cps) { //reversible妯″紡涓嬮渶瑕佺‘淇滵eMember涓嶦nMember鐨勪釜鏁板拰椤哄簭淇濇寔涓鑷达紝涓嶇劧postition浼氫笉涓鑷村鑷村弽搴忓垪鍖栧搴旂殑瀛楁椤哄簭涓嶅悓 + boolean flag = false; + for (EnMember m : dissorts) { + if (m.attribute.field().equals(constructorField)) { + flag = true; + break; + } + } + if (flag) continue; + //涓嶅瓨鍦╯etter鏂规硶 + try { + Field f = clazz.getDeclaredField(constructorField); + Type t = TypeToken.createClassType(f.getGenericType(), this.type); + try { + dissorts.add(new EnMember(createAttribute(factory, type, clazz, f, null, null), null, f, null)); //铏氭瀯 + } catch (RuntimeException e) { + } + } catch (NoSuchFieldException nsfe) { //涓嶅瓨鍦╢ield锛 鍙兘瀛樺湪getter鏂规硶 + char[] fs = constructorField.toCharArray(); + fs[0] = Character.toUpperCase(fs[0]); + String mn = new String(fs); + Method getter; + try { + getter = clazz.getMethod("get" + mn); + } catch (NoSuchMethodException ex) { + getter = clazz.getMethod("is" + mn); + } + Type t = TypeToken.createClassType(TypeToken.getGenericType(getter.getGenericParameterTypes()[0], this.type), this.type); + try { + dissorts.add(new EnMember(createAttribute(factory, type, clazz, null, getter, null), null, null, null)); //铏氭瀯 + } catch (RuntimeException e) { + } + } + } + if (dissorts.size() != list.size()) sorts = new ArrayList<>(dissorts); + } + Collections.sort(sorts, (a, b) -> a.compareTo(factory.isFieldSort(), b)); + Set pos = new HashSet<>(); + for (EnMember member : sorts) { + if (member.index > 0) pos.add(member.index); + } + int pidx = 0; + for (EnMember member : sorts) { + if (member.index > 0) { + member.position = member.index; + } else { + while (pos.contains(++pidx)); + member.position = pidx; + } + initForEachEnMember(factory, member); + } + + this.members = list.toArray(new EnMember[list.size()]); + Arrays.sort(this.members, (a, b) -> a.compareTo(factory.isFieldSort(), b)); + + } catch (Exception ex) { + throw new ConvertException("ObjectEncoder init type=" + this.type + " error", ex); + } + } finally { + inited = true; + synchronized (lock) { + lock.notifyAll(); + } + } + } + + protected void initForEachEnMember(ConvertFactory factory, EnMember member) { + } + + protected void setTag(EnMember member, int tag) { + member.tag = tag; + } + + @Override + public void convertTo(W out, T value) { + if (value == null) { + out.writeObjectNull(null); + return; + } + if (!this.inited) { + synchronized (lock) { + try { + lock.wait(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + if (value.getClass() != this.typeClass && !this.type.equals(out.specify())) { + final Class clz = value.getClass(); + if (out.needWriteClassName()) out.writeClassName(factory.getEntityAlias(clz)); + factory.loadEncoder(clz).convertTo(out, value); + return; + } + W objout = objectWriter(out, value); + if (objout.writeObjectB(value) < 0) { + int maxPosition = 0; + for (EnMember member : members) { + maxPosition = member.getPosition(); + objout.writeObjectField(member, value); + } + if (objout.objExtFunc != null) { + ConvertField[] extFields = objout.objExtFunc.apply(value); + if (extFields != null) { + Encodeable anyEncoder = factory.getAnyEncoder(); + for (ConvertField en : extFields) { + if (en == null) continue; + maxPosition++; + objout.writeObjectField(en.getName(), en.getType(), Math.max(en.getPosition(), maxPosition), anyEncoder, en.getValue()); + } + } + } + } + objout.writeObjectE(value); + } + + protected W objectWriter(W out, T value) { + return out; + } + + @Override + public Type getType() { + return this.type; + } + + public Class getTypeClass() { + return this.typeClass; + } + + public EnMember[] getMembers() { + return Arrays.copyOf(members, members.length); + } + + @Override + public String toString() { + return "ObjectEncoder{" + "type=" + type + ", members=" + Arrays.toString(members) + '}'; + } + +// +// static Type makeGenericType(final Type type, final Type[] virGenericTypes, final Type[] realGenericTypes) { +// if (type instanceof Class) { //e.g. String +// return type; +// } else if (type instanceof ParameterizedType) { //e.g. Map +// final ParameterizedType pt = (ParameterizedType) type; +// Type[] paramTypes = pt.getActualTypeArguments(); +// final Type[] newTypes = new Type[paramTypes.length]; +// int count = 0; +// for (int i = 0; i < newTypes.length; i++) { +// newTypes[i] = makeGenericType(paramTypes[i], virGenericTypes, realGenericTypes); +// if (paramTypes[i] == newTypes[i]) count++; +// } +// if (count == paramTypes.length) return pt; +// return new ParameterizedType() { +// +// @Override +// public Type[] getActualTypeArguments() { +// return newTypes; +// } +// +// @Override +// public Type getRawType() { +// return pt.getRawType(); +// } +// +// @Override +// public Type getOwnerType() { +// return pt.getOwnerType(); +// } +// +// }; +// } +// if (realGenericTypes == null) return type; +// if (type instanceof WildcardType) { // e.g. +// final WildcardType wt = (WildcardType) type; +// for (Type f : wt.getUpperBounds()) { +// for (int i = 0; i < virGenericTypes.length; i++) { +// if (virGenericTypes[i] == f) return realGenericTypes.length == 0 ? Object.class : realGenericTypes[i]; +// } +// } +// } else if (type instanceof TypeVariable) { // e.g. +// for (int i = 0; i < virGenericTypes.length; i++) { +// if (virGenericTypes[i] == type) return i >= realGenericTypes.length ? Object.class : realGenericTypes[i]; +// } +// } +// return type; +// } + static boolean contains(String[] values, String value) { + for (String str : values) { + if (str.equals(value)) return true; + } + return false; + } + + static String[] findConstructorProperties(Creator creator) { + if (creator == null) return null; + try { + ConstructorParameters cps = creator.getClass().getMethod("create", Object[].class).getAnnotation(ConstructorParameters.class); + return cps == null ? null : cps.value(); + } catch (Exception e) { + return null; + } + } + + static Attribute createAttribute(final ConvertFactory factory, final Type realType, Class clazz, final Field field, final Method getter, final Method setter) { + String fieldalias; + if (field != null) { // public field + ConvertColumnEntry ref = factory.findRef(clazz, field); + fieldalias = ref == null || ref.name().isEmpty() ? field.getName() : ref.name(); + } else if (getter != null) { + ConvertColumnEntry ref = factory.findRef(clazz, getter); + String mfieldname = ConvertFactory.readGetSetFieldName(getter); + if (ref == null) { + try { + ref = factory.findRef(clazz, clazz.getDeclaredField(mfieldname)); + } catch (Exception e) { + } + } + fieldalias = ref == null || ref.name().isEmpty() ? mfieldname : ref.name(); + } else { // setter != null + ConvertColumnEntry ref = factory.findRef(clazz, setter); + String mfieldname = ConvertFactory.readGetSetFieldName(setter); + if (ref == null) { + try { + ref = factory.findRef(clazz, clazz.getDeclaredField(mfieldname)); + } catch (Exception e) { + } + } + fieldalias = ref == null || ref.name().isEmpty() ? mfieldname : ref.name(); + } + + return Attribute.create(realType, clazz, fieldalias, null, field, getter, setter, null); + } + +} diff --git a/src/main/java/org/redkale/convert/OptionalCoder.java b/src/main/java/org/redkale/convert/OptionalCoder.java index 170e69da8..13f5d51f0 100644 --- a/src/main/java/org/redkale/convert/OptionalCoder.java +++ b/src/main/java/org/redkale/convert/OptionalCoder.java @@ -1,106 +1,106 @@ -/* - * 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.convert; - -import java.lang.reflect.*; -import java.util.*; - -/** - * Optional 鐨凷impledCoder瀹炵幇 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Reader杈撳叆鐨勫瓙绫诲瀷 - * @param Writer杈撳嚭鐨勫瓙绫诲瀷 - */ -public class OptionalCoder extends SimpledCoder> { - - protected final Type componentType; - - protected final Class componentClass; - - protected final Decodeable decoder; - - protected final Encodeable encoder; - - protected volatile boolean inited = false; - - private final Object lock = new Object(); - - @SuppressWarnings("unchecked") - public OptionalCoder(final ConvertFactory factory, final Type type) { - this.type = type; - try { - if (type instanceof ParameterizedType) { - final ParameterizedType pt = (ParameterizedType) type; - this.componentType = pt.getActualTypeArguments()[0]; - factory.register(type, this); - this.decoder = factory.loadDecoder(this.componentType); - if (this.componentType instanceof TypeVariable) { - this.encoder = factory.getAnyEncoder(); - this.componentClass = Object.class; - } else { - if (componentType instanceof ParameterizedType) { - final ParameterizedType pt2 = (ParameterizedType) componentType; - this.componentClass = (Class) pt2.getRawType(); - } else { - this.componentClass = (Class) componentType; - } - this.encoder = factory.loadEncoder(this.componentType); - } - } else { - this.componentType = Object.class; - this.componentClass = Object.class; - this.decoder = factory.loadDecoder(this.componentType); - this.encoder = factory.getAnyEncoder(); - } - } finally { - inited = true; - synchronized (lock) { - lock.notifyAll(); - } - } - } - - @Override - public void convertTo(W out, Optional value) { - if (value == null || !value.isPresent()) { - out.writeObjectNull(null); - return; - } - if (this.encoder == null) { - if (!this.inited) { - synchronized (lock) { - try { - lock.wait(); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - } - this.encoder.convertTo(out, value.get()); - } - - @Override - public Optional convertFrom(R in) { - if (this.decoder == null) { - if (!this.inited) { - synchronized (lock) { - try { - lock.wait(); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - } - return Optional.ofNullable(this.decoder.convertFrom(in)); - } - -} +/* + * 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.convert; + +import java.lang.reflect.*; +import java.util.*; + +/** + * Optional 鐨凷impledCoder瀹炵幇 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * @param Writer杈撳嚭鐨勫瓙绫诲瀷 + */ +public class OptionalCoder extends SimpledCoder> { + + protected final Type componentType; + + protected final Class componentClass; + + protected final Decodeable decoder; + + protected final Encodeable encoder; + + protected volatile boolean inited = false; + + private final Object lock = new Object(); + + @SuppressWarnings("unchecked") + public OptionalCoder(final ConvertFactory factory, final Type type) { + this.type = type; + try { + if (type instanceof ParameterizedType) { + final ParameterizedType pt = (ParameterizedType) type; + this.componentType = pt.getActualTypeArguments()[0]; + factory.register(type, this); + this.decoder = factory.loadDecoder(this.componentType); + if (this.componentType instanceof TypeVariable) { + this.encoder = factory.getAnyEncoder(); + this.componentClass = Object.class; + } else { + if (componentType instanceof ParameterizedType) { + final ParameterizedType pt2 = (ParameterizedType) componentType; + this.componentClass = (Class) pt2.getRawType(); + } else { + this.componentClass = (Class) componentType; + } + this.encoder = factory.loadEncoder(this.componentType); + } + } else { + this.componentType = Object.class; + this.componentClass = Object.class; + this.decoder = factory.loadDecoder(this.componentType); + this.encoder = factory.getAnyEncoder(); + } + } finally { + inited = true; + synchronized (lock) { + lock.notifyAll(); + } + } + } + + @Override + public void convertTo(W out, Optional value) { + if (value == null || !value.isPresent()) { + out.writeObjectNull(null); + return; + } + if (this.encoder == null) { + if (!this.inited) { + synchronized (lock) { + try { + lock.wait(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + this.encoder.convertTo(out, value.get()); + } + + @Override + public Optional convertFrom(R in) { + if (this.decoder == null) { + if (!this.inited) { + synchronized (lock) { + try { + lock.wait(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + return Optional.ofNullable(this.decoder.convertFrom(in)); + } + +} diff --git a/src/main/java/org/redkale/convert/Reader.java b/src/main/java/org/redkale/convert/Reader.java index df1a4da14..c9aa9a102 100644 --- a/src/main/java/org/redkale/convert/Reader.java +++ b/src/main/java/org/redkale/convert/Reader.java @@ -1,234 +1,234 @@ -/* - * 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.convert; - -/** - * 鍙嶅簭鍒楀寲鐨勬暟鎹鍙栨祦 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public abstract class Reader { - - public static enum ValueType { - STRING, ARRAY, MAP; - } - - //褰撳墠瀵硅薄瀛楁鍚嶇殑娓告爣 - protected int fieldIndex; - - public static final short SIGN_NULL = -1; - - public static final short SIGN_NOLENGTH = -2; - - public static final short SIGN_NOLENBUTBYTES = -3; //鐩墠鍙傚悎浜巔rotobuf鐨刡oolean[]...double[]绫诲瀷 - - /** - * 鏄惁杩樺瓨鍦ㄤ笅涓厓绱犳垨瀛楁
- * 娉ㄦ剰: 涓昏鐢ㄤ簬Array銆丆ollection銆丼tream鎴朚ap绛夐泦鍚堝璞 - * - * @param startPosition 璧峰浣嶇疆 - * @param contentLength 鍐呭澶у皬锛 涓嶇‘瀹氱殑浼-1 - * - * @return 鏄惁杩樺瓨鍦ㄤ笅涓厓绱犳垨瀛楁 - */ - public abstract boolean hasNext(int startPosition, int contentLength); - - /** - * 鏄惁杩樺瓨鍦ㄤ笅涓厓绱犳垨瀛楁 - * - * - * @return 鏄惁杩樺瓨鍦ㄤ笅涓厓绱犳垨瀛楁 - */ - public boolean hasNext() { - return hasNext(-1, -1); - } - - /** - * 鑾峰彇褰撳墠浣嶇疆 - * - * @return 褰撳墠浣嶇疆 - */ - public abstract int position(); - - /** - * 璇诲彇瀛楁鍊煎唴瀹圭殑瀛楄妭鏁
- * 鍙湁鍦╮eadXXXB鏂规硶杩斿洖SIGN_NOLENBUTBYTES鍊兼墠浼氳皟鐢ㄦ鏂规硶 - * - * @param member DeMember - * @param decoder Decodeable - * - * @return 鍐呭澶у皬锛 涓嶇‘瀹氳繑鍥-1 - */ - public abstract int readMemberContentLength(DeMember member, Decodeable decoder); - - /** - * 璺宠繃鍊(涓嶅寘鍚煎墠闈㈢殑瀛楁) - */ - public abstract void skipValue(); - - /** - * /璺宠繃瀛楁涓庡间箣闂寸殑澶氫綑鍐呭锛 json灏辨槸璺宠繃:绗, map璺宠繃: - */ - public abstract void readBlank(); - - /** - * 璇诲彇涓嬩釜鍊肩殑绫诲瀷 - * - * @return ValueType - */ - public abstract ValueType readType(); - - /** - * 璇诲彇瀵硅薄鐨勭被鍚嶏紝 杩斿洖 null 琛ㄧず瀵硅薄涓簄ull锛 杩斿洖绌哄瓧绗︿覆琛ㄧず褰撳墠class涓庤繑鍥炵殑class涓鑷达紝杩斿洖闈炵┖瀛楃涓茶〃绀篶lass鏄綋鍓峜lass鐨勫瓙绫汇 - * - * @param clazz 绫诲悕 - * - * @return 杩斿洖瀛楁鏁 - */ - public String readObjectB(final Class clazz) { - this.fieldIndex = 0; - return null; - } - - /** - * 璇诲彇瀵硅薄鐨勫熬绔 - * - * @param clazz 绫诲悕 - */ - public abstract void readObjectE(final Class clazz); - - /** - * 璇诲彇鏁扮粍鐨勫紑澶村苟杩斿洖鏁扮粍鐨勯暱搴 - * - * @param member DeMember - * @param typevals byte[] - * @param componentDecoder Decodeable - * - * @return 杩斿洖鏁扮粍鐨勯暱搴 - */ - public abstract int readArrayB(DeMember member, byte[] typevals, Decodeable componentDecoder); - - /** - * 璇诲彇鏁扮粍鐨勫熬绔 - * - */ - public abstract void readArrayE(); - - /** - * 璇诲彇map鐨勫紑澶村苟杩斿洖map鐨剆ize - * - * @param member DeMember - * @param typevals byte[] - * @param keyDecoder Decodeable - * @param valueDecoder Decodeable - * - * @return 杩斿洖map鐨剆ize - */ - public abstract int readMapB(DeMember member, byte[] typevals, Decodeable keyDecoder, Decodeable valueDecoder); - - /** - * 璇诲彇鏁扮粍鐨勫熬绔 - * - */ - public abstract void readMapE(); - - /** - * 鏍规嵁瀛楁璇诲彇瀛楁瀵瑰簲鐨凞eMember - * - * @param members DeMember鐨勫叏閲忛泦鍚 - * - * @return 鍖归厤鐨凞eMember - */ - public abstract DeMember readFieldName(final DeMember[] members); - - /** - * 璇诲彇涓涓猙oolean鍊 - * - * @return boolean鍊 - */ - public abstract boolean readBoolean(); - - /** - * 璇诲彇涓涓猙yte鍊 - * - * @return byte鍊 - */ - public abstract byte readByte(); - - /** - * 璇诲彇byte[] - * - * @return byte[] - */ - public abstract byte[] readByteArray(); - - /** - * 璇诲彇涓涓猚har鍊 - * - * @return char鍊 - */ - public abstract char readChar(); - - /** - * 璇诲彇涓涓猻hort鍊 - * - * @return short鍊 - */ - public abstract short readShort(); - - /** - * 璇诲彇涓涓猧nt鍊 - * - * @return int鍊 - */ - public abstract int readInt(); - - /** - * 璇诲彇涓涓猯ong鍊 - * - * @return long鍊 - */ - public abstract long readLong(); - - /** - * 璇诲彇涓涓猣loat鍊 - * - * @return float鍊 - */ - public abstract float readFloat(); - - /** - * 璇诲彇涓涓猟ouble鍊 - * - * @return double鍊 - */ - public abstract double readDouble(); - - /** - * 璇诲彇鏃犺浆涔夊瓧绗﹂暱搴︿笉瓒呰繃255鐨勫瓧绗︿覆锛 渚嬪鏋氫妇鍊笺佸瓧娈靛悕銆佺被鍚嶅瓧绗︿覆绛 - * - * @return String鍊 - */ - public abstract String readSmallString(); - - /** - * 璇诲彇鍙嶈В鏋愬璞$殑绫诲悕 - * - * @return 绫诲悕 - */ - public abstract String readClassName(); - - /** - * 璇诲彇涓涓猄tring鍊 - * - * @return String鍊 - */ - public abstract String readString(); - -} +/* + * 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.convert; + +/** + * 鍙嶅簭鍒楀寲鐨勬暟鎹鍙栨祦 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public abstract class Reader { + + public static enum ValueType { + STRING, ARRAY, MAP; + } + + //褰撳墠瀵硅薄瀛楁鍚嶇殑娓告爣 + protected int fieldIndex; + + public static final short SIGN_NULL = -1; + + public static final short SIGN_NOLENGTH = -2; + + public static final short SIGN_NOLENBUTBYTES = -3; //鐩墠鍙傚悎浜巔rotobuf鐨刡oolean[]...double[]绫诲瀷 + + /** + * 鏄惁杩樺瓨鍦ㄤ笅涓厓绱犳垨瀛楁
+ * 娉ㄦ剰: 涓昏鐢ㄤ簬Array銆丆ollection銆丼tream鎴朚ap绛夐泦鍚堝璞 + * + * @param startPosition 璧峰浣嶇疆 + * @param contentLength 鍐呭澶у皬锛 涓嶇‘瀹氱殑浼-1 + * + * @return 鏄惁杩樺瓨鍦ㄤ笅涓厓绱犳垨瀛楁 + */ + public abstract boolean hasNext(int startPosition, int contentLength); + + /** + * 鏄惁杩樺瓨鍦ㄤ笅涓厓绱犳垨瀛楁 + * + * + * @return 鏄惁杩樺瓨鍦ㄤ笅涓厓绱犳垨瀛楁 + */ + public boolean hasNext() { + return hasNext(-1, -1); + } + + /** + * 鑾峰彇褰撳墠浣嶇疆 + * + * @return 褰撳墠浣嶇疆 + */ + public abstract int position(); + + /** + * 璇诲彇瀛楁鍊煎唴瀹圭殑瀛楄妭鏁
+ * 鍙湁鍦╮eadXXXB鏂规硶杩斿洖SIGN_NOLENBUTBYTES鍊兼墠浼氳皟鐢ㄦ鏂规硶 + * + * @param member DeMember + * @param decoder Decodeable + * + * @return 鍐呭澶у皬锛 涓嶇‘瀹氳繑鍥-1 + */ + public abstract int readMemberContentLength(DeMember member, Decodeable decoder); + + /** + * 璺宠繃鍊(涓嶅寘鍚煎墠闈㈢殑瀛楁) + */ + public abstract void skipValue(); + + /** + * /璺宠繃瀛楁涓庡间箣闂寸殑澶氫綑鍐呭锛 json灏辨槸璺宠繃:绗, map璺宠繃: + */ + public abstract void readBlank(); + + /** + * 璇诲彇涓嬩釜鍊肩殑绫诲瀷 + * + * @return ValueType + */ + public abstract ValueType readType(); + + /** + * 璇诲彇瀵硅薄鐨勭被鍚嶏紝 杩斿洖 null 琛ㄧず瀵硅薄涓簄ull锛 杩斿洖绌哄瓧绗︿覆琛ㄧず褰撳墠class涓庤繑鍥炵殑class涓鑷达紝杩斿洖闈炵┖瀛楃涓茶〃绀篶lass鏄綋鍓峜lass鐨勫瓙绫汇 + * + * @param clazz 绫诲悕 + * + * @return 杩斿洖瀛楁鏁 + */ + public String readObjectB(final Class clazz) { + this.fieldIndex = 0; + return null; + } + + /** + * 璇诲彇瀵硅薄鐨勫熬绔 + * + * @param clazz 绫诲悕 + */ + public abstract void readObjectE(final Class clazz); + + /** + * 璇诲彇鏁扮粍鐨勫紑澶村苟杩斿洖鏁扮粍鐨勯暱搴 + * + * @param member DeMember + * @param typevals byte[] + * @param componentDecoder Decodeable + * + * @return 杩斿洖鏁扮粍鐨勯暱搴 + */ + public abstract int readArrayB(DeMember member, byte[] typevals, Decodeable componentDecoder); + + /** + * 璇诲彇鏁扮粍鐨勫熬绔 + * + */ + public abstract void readArrayE(); + + /** + * 璇诲彇map鐨勫紑澶村苟杩斿洖map鐨剆ize + * + * @param member DeMember + * @param typevals byte[] + * @param keyDecoder Decodeable + * @param valueDecoder Decodeable + * + * @return 杩斿洖map鐨剆ize + */ + public abstract int readMapB(DeMember member, byte[] typevals, Decodeable keyDecoder, Decodeable valueDecoder); + + /** + * 璇诲彇鏁扮粍鐨勫熬绔 + * + */ + public abstract void readMapE(); + + /** + * 鏍规嵁瀛楁璇诲彇瀛楁瀵瑰簲鐨凞eMember + * + * @param members DeMember鐨勫叏閲忛泦鍚 + * + * @return 鍖归厤鐨凞eMember + */ + public abstract DeMember readFieldName(final DeMember[] members); + + /** + * 璇诲彇涓涓猙oolean鍊 + * + * @return boolean鍊 + */ + public abstract boolean readBoolean(); + + /** + * 璇诲彇涓涓猙yte鍊 + * + * @return byte鍊 + */ + public abstract byte readByte(); + + /** + * 璇诲彇byte[] + * + * @return byte[] + */ + public abstract byte[] readByteArray(); + + /** + * 璇诲彇涓涓猚har鍊 + * + * @return char鍊 + */ + public abstract char readChar(); + + /** + * 璇诲彇涓涓猻hort鍊 + * + * @return short鍊 + */ + public abstract short readShort(); + + /** + * 璇诲彇涓涓猧nt鍊 + * + * @return int鍊 + */ + public abstract int readInt(); + + /** + * 璇诲彇涓涓猯ong鍊 + * + * @return long鍊 + */ + public abstract long readLong(); + + /** + * 璇诲彇涓涓猣loat鍊 + * + * @return float鍊 + */ + public abstract float readFloat(); + + /** + * 璇诲彇涓涓猟ouble鍊 + * + * @return double鍊 + */ + public abstract double readDouble(); + + /** + * 璇诲彇鏃犺浆涔夊瓧绗﹂暱搴︿笉瓒呰繃255鐨勫瓧绗︿覆锛 渚嬪鏋氫妇鍊笺佸瓧娈靛悕銆佺被鍚嶅瓧绗︿覆绛 + * + * @return String鍊 + */ + public abstract String readSmallString(); + + /** + * 璇诲彇鍙嶈В鏋愬璞$殑绫诲悕 + * + * @return 绫诲悕 + */ + public abstract String readClassName(); + + /** + * 璇诲彇涓涓猄tring鍊 + * + * @return String鍊 + */ + public abstract String readString(); + +} diff --git a/src/main/java/org/redkale/convert/SimpledCoder.java b/src/main/java/org/redkale/convert/SimpledCoder.java index 0a1dd8da1..dd1f3bec3 100644 --- a/src/main/java/org/redkale/convert/SimpledCoder.java +++ b/src/main/java/org/redkale/convert/SimpledCoder.java @@ -1,47 +1,47 @@ -/* - * 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.convert; - -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; - -/** - * 绠鏄撶被鐨勫簭鍒楀寲鍜屽弽搴忓垪鍖栨搷浣滅被
- * 鑳藉簭鍒楀寲涓築oolean銆丯umber鎴栬呭瓧绗︿覆鐨勭被瑙嗕负绠鏄撶被
- * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Reader杈撳叆鐨勫瓙绫 - * @param Writer杈撳嚭鐨勫瓙绫 - * @param 搴忓垪鍖/鍙嶈В鏋愮殑鏁版嵁绫诲瀷 - */ -public abstract class SimpledCoder implements Decodeable, Encodeable { - - protected Type type; - - @Override - public abstract void convertTo(final W out, final T value); - - @Override - public abstract T convertFrom(final R in); - - @Override - @SuppressWarnings("unchecked") - public Class getType() { - if (type == null) { - Type[] ts = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments(); - type = ts[ts.length - 1]; - } - return (Class) type; - } - - @Override - public String toString() { - return this.getClass().getSimpleName(); - } -} +/* + * 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.convert; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; + +/** + * 绠鏄撶被鐨勫簭鍒楀寲鍜屽弽搴忓垪鍖栨搷浣滅被
+ * 鑳藉簭鍒楀寲涓築oolean銆丯umber鎴栬呭瓧绗︿覆鐨勭被瑙嗕负绠鏄撶被
+ * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Reader杈撳叆鐨勫瓙绫 + * @param Writer杈撳嚭鐨勫瓙绫 + * @param 搴忓垪鍖/鍙嶈В鏋愮殑鏁版嵁绫诲瀷 + */ +public abstract class SimpledCoder implements Decodeable, Encodeable { + + protected Type type; + + @Override + public abstract void convertTo(final W out, final T value); + + @Override + public abstract T convertFrom(final R in); + + @Override + @SuppressWarnings("unchecked") + public Class getType() { + if (type == null) { + Type[] ts = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments(); + type = ts[ts.length - 1]; + } + return (Class) type; + } + + @Override + public String toString() { + return this.getClass().getSimpleName(); + } +} diff --git a/src/main/java/org/redkale/convert/StreamEncoder.java b/src/main/java/org/redkale/convert/StreamEncoder.java index abb22be9d..e09339dbe 100644 --- a/src/main/java/org/redkale/convert/StreamEncoder.java +++ b/src/main/java/org/redkale/convert/StreamEncoder.java @@ -1,107 +1,107 @@ -/* - * 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.convert; - -import java.lang.reflect.*; -import java.util.stream.Stream; - -/** - * Stream鐨勫簭鍒楀寲鎿嶄綔绫
- * 鏀寔涓瀹氱▼搴︾殑娉涘瀷銆
- * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param 搴忓垪鍖栫殑闆嗗悎鍏冪礌绫诲瀷 - */ -@SuppressWarnings("unchecked") -public class StreamEncoder implements Encodeable> { - - protected final Type type; - - protected final Encodeable componentEncoder; - - protected volatile boolean inited = false; - - protected final Object lock = new Object(); - - public StreamEncoder(final ConvertFactory factory, final Type type) { - this.type = type; - try { - if (type instanceof ParameterizedType) { - Type t = ((ParameterizedType) type).getActualTypeArguments()[0]; - if (t instanceof TypeVariable) { - this.componentEncoder = factory.getAnyEncoder(); - } else { - this.componentEncoder = factory.loadEncoder(t); - } - } else { - this.componentEncoder = factory.getAnyEncoder(); - } - } finally { - inited = true; - synchronized (lock) { - lock.notifyAll(); - } - } - } - - @Override - public void convertTo(Writer out, Stream value) { - convertTo(out, null, value); - } - - public void convertTo(Writer out, EnMember member, Stream value) { - if (value == null) { - out.writeNull(); - return; - } - Object[] array = value.toArray(); - if (array.length == 0) { - out.writeArrayB(0, this, componentEncoder, array); - out.writeArrayE(); - return; - } - if (this.componentEncoder == null) { - if (!this.inited) { - synchronized (lock) { - try { - lock.wait(); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - } - if (out.writeArrayB(array.length, this, componentEncoder, array) < 0) { - boolean first = true; - for (Object v : array) { - if (!first) out.writeArrayMark(); - writeMemberValue(out, member, v, first); - if (first) first = false; - } - } - out.writeArrayE(); - } - - protected void writeMemberValue(Writer out, EnMember member, Object value, boolean first) { - componentEncoder.convertTo(out, value); - } - - @Override - public Type getType() { - return type; - } - - public Encodeable getComponentEncoder() { - return componentEncoder; - } - - public Type getComponentType() { - return componentEncoder == null ? null : componentEncoder.getType(); - } -} +/* + * 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.convert; + +import java.lang.reflect.*; +import java.util.stream.Stream; + +/** + * Stream鐨勫簭鍒楀寲鎿嶄綔绫
+ * 鏀寔涓瀹氱▼搴︾殑娉涘瀷銆
+ * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param 搴忓垪鍖栫殑闆嗗悎鍏冪礌绫诲瀷 + */ +@SuppressWarnings("unchecked") +public class StreamEncoder implements Encodeable> { + + protected final Type type; + + protected final Encodeable componentEncoder; + + protected volatile boolean inited = false; + + protected final Object lock = new Object(); + + public StreamEncoder(final ConvertFactory factory, final Type type) { + this.type = type; + try { + if (type instanceof ParameterizedType) { + Type t = ((ParameterizedType) type).getActualTypeArguments()[0]; + if (t instanceof TypeVariable) { + this.componentEncoder = factory.getAnyEncoder(); + } else { + this.componentEncoder = factory.loadEncoder(t); + } + } else { + this.componentEncoder = factory.getAnyEncoder(); + } + } finally { + inited = true; + synchronized (lock) { + lock.notifyAll(); + } + } + } + + @Override + public void convertTo(Writer out, Stream value) { + convertTo(out, null, value); + } + + public void convertTo(Writer out, EnMember member, Stream value) { + if (value == null) { + out.writeNull(); + return; + } + Object[] array = value.toArray(); + if (array.length == 0) { + out.writeArrayB(0, this, componentEncoder, array); + out.writeArrayE(); + return; + } + if (this.componentEncoder == null) { + if (!this.inited) { + synchronized (lock) { + try { + lock.wait(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + if (out.writeArrayB(array.length, this, componentEncoder, array) < 0) { + boolean first = true; + for (Object v : array) { + if (!first) out.writeArrayMark(); + writeMemberValue(out, member, v, first); + if (first) first = false; + } + } + out.writeArrayE(); + } + + protected void writeMemberValue(Writer out, EnMember member, Object value, boolean first) { + componentEncoder.convertTo(out, value); + } + + @Override + public Type getType() { + return type; + } + + public Encodeable getComponentEncoder() { + return componentEncoder; + } + + public Type getComponentType() { + return componentEncoder == null ? null : componentEncoder.getType(); + } +} diff --git a/src/main/java/org/redkale/convert/TextConvert.java b/src/main/java/org/redkale/convert/TextConvert.java index c6e2e34ef..c6f3b095a 100644 --- a/src/main/java/org/redkale/convert/TextConvert.java +++ b/src/main/java/org/redkale/convert/TextConvert.java @@ -1,35 +1,35 @@ -/* - * 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.convert; - -import java.lang.reflect.Type; - -/** - * 鏂囨湰搴忓垪鍖/鍙嶅簭鍒楀寲鎿嶄綔绫 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Reader杈撳叆鐨勫瓙绫 - * @param Writer杈撳嚭鐨勫瓙绫 - */ -public abstract class TextConvert extends Convert { - - protected TextConvert(ConvertFactory factory) { - super(factory); - } - - @Override - public final boolean isBinary() { - return false; - } - - public abstract String convertTo(final Object value); - - public abstract String convertTo(final Type type, final Object value); - -} +/* + * 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.convert; + +import java.lang.reflect.Type; + +/** + * 鏂囨湰搴忓垪鍖/鍙嶅簭鍒楀寲鎿嶄綔绫 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Reader杈撳叆鐨勫瓙绫 + * @param Writer杈撳嚭鐨勫瓙绫 + */ +public abstract class TextConvert extends Convert { + + protected TextConvert(ConvertFactory factory) { + super(factory); + } + + @Override + public final boolean isBinary() { + return false; + } + + public abstract String convertTo(final Object value); + + public abstract String convertTo(final Type type, final Object value); + +} diff --git a/src/main/java/org/redkale/convert/Writer.java b/src/main/java/org/redkale/convert/Writer.java index 435a2b378..052321df8 100644 --- a/src/main/java/org/redkale/convert/Writer.java +++ b/src/main/java/org/redkale/convert/Writer.java @@ -1,326 +1,326 @@ -/* - * 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.convert; - -import java.lang.reflect.*; -import java.util.function.*; -import org.redkale.util.*; - -/** - * 搴忓垪鍖栫殑鏁版嵁杈撳嚭娴 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public abstract class Writer { - - //褰撳墠瀵硅薄杈撳嚭瀛楁鍚嶄箣鍓嶆槸鍚﹂渶瑕佸垎闅旂锛 JSON瀛楁闂寸殑鍒嗛殧绗︿负,閫楀彿 - protected boolean comma; - - //convertTo鏃舵槸鍚︿互鎸囧畾Type鐨凮bjectEncoder杩涜澶勭悊 - protected Type specify; - - //瀵规煇涓瓧娈靛艰繘琛屽姩鎬佸鐞 - protected BiFunction objFieldFunc; - - //瀵规煇涓璞¤繘琛屽姩鎬佹墿灞曞瓧娈靛煎鐞 - protected Function objExtFunc; - - /** - * 璁剧疆specify - * - * @param value Type - */ - public void specify(Type value) { - if (value instanceof GenericArrayType) { - this.specify = ((GenericArrayType) value).getGenericComponentType(); - } else if (value instanceof Class && ((Class) value).isArray()) { - this.specify = ((Class) value).getComponentType(); - } else { - this.specify = value; - } - } - - protected boolean recycle() { - this.objFieldFunc = null; - return true; - } - - /** - * 杩斿洖specify - * - * @return int - */ - public Type specify() { - return this.specify; - } - - /** - * 褰搕iny=true鏃讹紝 瀛楃涓蹭负绌恒乥oolean涓篺alse鐨勫瓧娈靛奸兘浼氳璺宠繃锛 涓嶄細杈撳嚭銆 - * - * @return 鏄惁绠鍖 - */ - public abstract boolean tiny(); - - /** - * 杈撳嚭null鍊 - */ - public abstract void writeNull(); - - /** - * 鏄惁闇瑕佸啓鍏ョ被鍚, BSON闇瑕侊紝 JSON涓嶉渶瑕 - * - * @return boolean - */ - public abstract boolean needWriteClassName(); - - /** - * 鍐欏叆绫诲悕 - * - * @param clazz 绫诲悕 - */ - public abstract void writeClassName(String clazz); - - /** - * 杈撳嚭涓涓璞″墠鐨勬搷浣 - * 娉細 瑕嗙洊姝ゆ柟娉曞繀椤昏鍏堣皟鐢ㄧ埗鏂规硶 super.writeObjectB(obj); - * - * @param obj 鍐欏叆鐨勫璞 - * - * @return 杩斿洖-1琛ㄧず杩樻病鏈夊啓鍏ュ璞″唴瀹癸紝澶т簬-1琛ㄧず宸插啓鍏ュ璞″唴瀹癸紝杩斿洖瀵硅薄鍐呭澶у皬 - */ - public int writeObjectB(Object obj) { - this.comma = false; - return -1; - } - - /** - * 杈撳嚭涓涓负null鐨勫璞 - * - * @param clazz 瀵硅薄鐨勭被鍚 - */ - public final void writeObjectNull(final Class clazz) { - writeClassName(null); - writeNull(); - } - - /** - * 杈撳嚭涓涓璞$殑鏌愪釜瀛楁 - * - * @param member 瀛楁 - * - * @param obj 鍐欏叆鐨勫璞 - */ - @SuppressWarnings("unchecked") - public void writeObjectField(final EnMember member, Object obj) { - Object value; - if (objFieldFunc == null) { - value = member.attribute.get(obj); - } else { - value = objFieldFunc.apply(member.attribute, obj); - } - if (value == null) return; - if (tiny()) { - if (member.string) { - if (((CharSequence) value).length() == 0) return; - } else if (member.bool) { - if (!((Boolean) value)) return; - } - } - Attribute attr = member.getAttribute(); - this.writeFieldName(member, attr.field(), attr.genericType(), member.getPosition()); - member.encoder.convertTo(this, value); - this.comma = true; - } - - /** - * 杈撳嚭涓涓璞$殑鏌愪釜鎵╁睍瀛楁 - * - * - * @param fieldName 瀛楁鍚嶇О - * @param fieldType 瀛楁绫诲瀷 - * @param fieldPos 瀛楁椤哄簭 - * @param anyEncoder Encoder - * @param value 鍐欏叆鐨勫瓧娈靛璞 - */ - @SuppressWarnings("unchecked") - public void writeObjectField(final String fieldName, Type fieldType, int fieldPos, Encodeable anyEncoder, Object value) { - if (value == null) return; - if (fieldType == null) fieldType = value.getClass(); - if (tiny() && fieldType instanceof Class) { - Class clazz = (Class) fieldType; - if (CharSequence.class.isAssignableFrom(clazz)) { - if (((CharSequence) value).length() == 0) return; - } else if (clazz == boolean.class || clazz == Boolean.class) { - if (!((Boolean) value)) return; - } - } - this.writeFieldName(null, fieldName, fieldType, fieldPos); - anyEncoder.convertTo(this, value); - this.comma = true; - } - - /** - * 杈撳嚭涓涓瓧娈靛悕 - * - * @param member 瀛楁 - */ - public final void writeFieldName(final EnMember member) { - Attribute attr = member.getAttribute(); - this.writeFieldName(member, attr.field(), attr.genericType(), member.getPosition()); - } - - /** - * 杈撳嚭涓涓璞″悗鐨勬搷浣 - * - * @param obj 鍐欏叆鐨勫璞 - */ - public abstract void writeObjectE(Object obj); - - /** - * 杈撳嚭涓涓暟缁勫墠鐨勬搷浣 - * - * @param size 鏁扮粍闀垮害 - * @param arrayEncoder Encodeable 鍙兘鏄疉rrayEncoder銆丆ollectionEncoder鎴朣treamEncoder - * @param componentEncoder Encodeable - * @param obj 瀵硅薄, 涓嶄竴瀹氭槸鏁扮粍銆丆ollection瀵硅薄锛屼篃鍙兘鏄吉Collection瀵硅薄 - * - * @return 杩斿洖-1琛ㄧず杩樻病鏈夊啓鍏ュ璞″唴瀹癸紝澶т簬-1琛ㄧず宸插啓鍏ュ璞″唴瀹癸紝杩斿洖瀵硅薄鍐呭澶у皬 - */ - public abstract int writeArrayB(int size, Encodeable arrayEncoder, Encodeable componentEncoder, Object obj); - - /** - * 杈撳嚭鏁扮粍鍏冪礌闂寸殑闂撮殧绗 - * - */ - public abstract void writeArrayMark(); - - /** - * 杈撳嚭涓涓暟缁勫悗鐨勬搷浣 - * - */ - public abstract void writeArrayE(); - - /** - * 杈撳嚭涓涓狹ap鍓嶇殑鎿嶄綔 - * - * @param size map澶у皬 - * @param keyEncoder Encodeable - * @param valueEncoder Encodeable - * @param obj 瀵硅薄, 涓嶄竴瀹氭槸Map瀵硅薄锛屼篃鍙兘鏄吉Map瀵硅薄 - * - * @return 杩斿洖-1琛ㄧず杩樻病鏈夊啓鍏ュ璞″唴瀹癸紝澶т簬-1琛ㄧず宸插啓鍏ュ璞″唴瀹癸紝杩斿洖瀵硅薄鍐呭澶у皬 - */ - public abstract int writeMapB(int size, Encodeable keyEncoder, Encodeable valueEncoder, Object obj); - - /** - * 杈撳嚭涓涓狹ap涓璳ey涓巚alue闂寸殑闂撮殧绗 - * - */ - public abstract void writeMapMark(); - - /** - * 杈撳嚭涓涓狹ap鍚庣殑鎿嶄綔 - * - */ - public abstract void writeMapE(); - - /** - * 杈撳嚭涓涓瓧娈靛悕 - * - * @param member EnMember - * @param fieldName 瀛楁鍚嶇О - * @param fieldType 瀛楁绫诲瀷 - * @param fieldPos 瀛楁椤哄簭 - */ - public abstract void writeFieldName(EnMember member, String fieldName, Type fieldType, int fieldPos); - - /** - * 鍐欏叆涓涓猙oolean鍊 - * - * @param value boolean鍊 - */ - public abstract void writeBoolean(boolean value); - - /** - * 鍐欏叆涓涓猙yte鍊 - * - * @param value byte鍊 - */ - public abstract void writeByte(byte value); - - /** - * 鍐欏叆byte[] - * - * @param values byte[] - */ - public abstract void writeByteArray(byte[] values); - - /** - * 鍐欏叆涓涓猚har鍊 - * - * @param value char鍊 - */ - public abstract void writeChar(char value); - - /** - * 鍐欏叆涓涓猻hort鍊 - * - * @param value short鍊 - */ - public abstract void writeShort(short value); - - /** - * 鍐欏叆涓涓猧nt鍊 - * - * @param value int鍊 - */ - public abstract void writeInt(int value); - - /** - * 鍐欏叆涓涓猯ong鍊 - * - * @param value long鍊 - */ - public abstract void writeLong(long value); - - /** - * 鍐欏叆涓涓猣loat鍊 - * - * @param value float鍊 - */ - public abstract void writeFloat(float value); - - /** - * 鍐欏叆涓涓猟ouble鍊 - * - * @param value double鍊 - */ - public abstract void writeDouble(double value); - - /** - * 鍐欏叆鏃犺浆涔夊瓧绗﹂暱搴︿笉瓒呰繃255鐨勫瓧绗︿覆锛 渚嬪鏋氫妇鍊笺佸瓧娈靛悕銆佺被鍚嶅瓧绗︿覆绛 * - * - * @param value 闈炵┖涓斾笉鍚渶瑕佽浆涔夌殑瀛楃鐨凷tring鍊 - */ - public abstract void writeSmallString(String value); - - /** - * 鍐欏叆涓涓猄tring鍊 - * - * @param value String鍊 - */ - public abstract void writeString(String value); - - /** - * 鍐欏叆涓涓猄tringConvertWrapper鍊 - * - * @param value StringConvertWrapper鍊 - */ - public abstract void writeWrapper(StringWrapper value); -} +/* + * 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.convert; + +import java.lang.reflect.*; +import java.util.function.*; +import org.redkale.util.*; + +/** + * 搴忓垪鍖栫殑鏁版嵁杈撳嚭娴 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public abstract class Writer { + + //褰撳墠瀵硅薄杈撳嚭瀛楁鍚嶄箣鍓嶆槸鍚﹂渶瑕佸垎闅旂锛 JSON瀛楁闂寸殑鍒嗛殧绗︿负,閫楀彿 + protected boolean comma; + + //convertTo鏃舵槸鍚︿互鎸囧畾Type鐨凮bjectEncoder杩涜澶勭悊 + protected Type specify; + + //瀵规煇涓瓧娈靛艰繘琛屽姩鎬佸鐞 + protected BiFunction objFieldFunc; + + //瀵规煇涓璞¤繘琛屽姩鎬佹墿灞曞瓧娈靛煎鐞 + protected Function objExtFunc; + + /** + * 璁剧疆specify + * + * @param value Type + */ + public void specify(Type value) { + if (value instanceof GenericArrayType) { + this.specify = ((GenericArrayType) value).getGenericComponentType(); + } else if (value instanceof Class && ((Class) value).isArray()) { + this.specify = ((Class) value).getComponentType(); + } else { + this.specify = value; + } + } + + protected boolean recycle() { + this.objFieldFunc = null; + return true; + } + + /** + * 杩斿洖specify + * + * @return int + */ + public Type specify() { + return this.specify; + } + + /** + * 褰搕iny=true鏃讹紝 瀛楃涓蹭负绌恒乥oolean涓篺alse鐨勫瓧娈靛奸兘浼氳璺宠繃锛 涓嶄細杈撳嚭銆 + * + * @return 鏄惁绠鍖 + */ + public abstract boolean tiny(); + + /** + * 杈撳嚭null鍊 + */ + public abstract void writeNull(); + + /** + * 鏄惁闇瑕佸啓鍏ョ被鍚, BSON闇瑕侊紝 JSON涓嶉渶瑕 + * + * @return boolean + */ + public abstract boolean needWriteClassName(); + + /** + * 鍐欏叆绫诲悕 + * + * @param clazz 绫诲悕 + */ + public abstract void writeClassName(String clazz); + + /** + * 杈撳嚭涓涓璞″墠鐨勬搷浣 + * 娉細 瑕嗙洊姝ゆ柟娉曞繀椤昏鍏堣皟鐢ㄧ埗鏂规硶 super.writeObjectB(obj); + * + * @param obj 鍐欏叆鐨勫璞 + * + * @return 杩斿洖-1琛ㄧず杩樻病鏈夊啓鍏ュ璞″唴瀹癸紝澶т簬-1琛ㄧず宸插啓鍏ュ璞″唴瀹癸紝杩斿洖瀵硅薄鍐呭澶у皬 + */ + public int writeObjectB(Object obj) { + this.comma = false; + return -1; + } + + /** + * 杈撳嚭涓涓负null鐨勫璞 + * + * @param clazz 瀵硅薄鐨勭被鍚 + */ + public final void writeObjectNull(final Class clazz) { + writeClassName(null); + writeNull(); + } + + /** + * 杈撳嚭涓涓璞$殑鏌愪釜瀛楁 + * + * @param member 瀛楁 + * + * @param obj 鍐欏叆鐨勫璞 + */ + @SuppressWarnings("unchecked") + public void writeObjectField(final EnMember member, Object obj) { + Object value; + if (objFieldFunc == null) { + value = member.attribute.get(obj); + } else { + value = objFieldFunc.apply(member.attribute, obj); + } + if (value == null) return; + if (tiny()) { + if (member.string) { + if (((CharSequence) value).length() == 0) return; + } else if (member.bool) { + if (!((Boolean) value)) return; + } + } + Attribute attr = member.getAttribute(); + this.writeFieldName(member, attr.field(), attr.genericType(), member.getPosition()); + member.encoder.convertTo(this, value); + this.comma = true; + } + + /** + * 杈撳嚭涓涓璞$殑鏌愪釜鎵╁睍瀛楁 + * + * + * @param fieldName 瀛楁鍚嶇О + * @param fieldType 瀛楁绫诲瀷 + * @param fieldPos 瀛楁椤哄簭 + * @param anyEncoder Encoder + * @param value 鍐欏叆鐨勫瓧娈靛璞 + */ + @SuppressWarnings("unchecked") + public void writeObjectField(final String fieldName, Type fieldType, int fieldPos, Encodeable anyEncoder, Object value) { + if (value == null) return; + if (fieldType == null) fieldType = value.getClass(); + if (tiny() && fieldType instanceof Class) { + Class clazz = (Class) fieldType; + if (CharSequence.class.isAssignableFrom(clazz)) { + if (((CharSequence) value).length() == 0) return; + } else if (clazz == boolean.class || clazz == Boolean.class) { + if (!((Boolean) value)) return; + } + } + this.writeFieldName(null, fieldName, fieldType, fieldPos); + anyEncoder.convertTo(this, value); + this.comma = true; + } + + /** + * 杈撳嚭涓涓瓧娈靛悕 + * + * @param member 瀛楁 + */ + public final void writeFieldName(final EnMember member) { + Attribute attr = member.getAttribute(); + this.writeFieldName(member, attr.field(), attr.genericType(), member.getPosition()); + } + + /** + * 杈撳嚭涓涓璞″悗鐨勬搷浣 + * + * @param obj 鍐欏叆鐨勫璞 + */ + public abstract void writeObjectE(Object obj); + + /** + * 杈撳嚭涓涓暟缁勫墠鐨勬搷浣 + * + * @param size 鏁扮粍闀垮害 + * @param arrayEncoder Encodeable 鍙兘鏄疉rrayEncoder銆丆ollectionEncoder鎴朣treamEncoder + * @param componentEncoder Encodeable + * @param obj 瀵硅薄, 涓嶄竴瀹氭槸鏁扮粍銆丆ollection瀵硅薄锛屼篃鍙兘鏄吉Collection瀵硅薄 + * + * @return 杩斿洖-1琛ㄧず杩樻病鏈夊啓鍏ュ璞″唴瀹癸紝澶т簬-1琛ㄧず宸插啓鍏ュ璞″唴瀹癸紝杩斿洖瀵硅薄鍐呭澶у皬 + */ + public abstract int writeArrayB(int size, Encodeable arrayEncoder, Encodeable componentEncoder, Object obj); + + /** + * 杈撳嚭鏁扮粍鍏冪礌闂寸殑闂撮殧绗 + * + */ + public abstract void writeArrayMark(); + + /** + * 杈撳嚭涓涓暟缁勫悗鐨勬搷浣 + * + */ + public abstract void writeArrayE(); + + /** + * 杈撳嚭涓涓狹ap鍓嶇殑鎿嶄綔 + * + * @param size map澶у皬 + * @param keyEncoder Encodeable + * @param valueEncoder Encodeable + * @param obj 瀵硅薄, 涓嶄竴瀹氭槸Map瀵硅薄锛屼篃鍙兘鏄吉Map瀵硅薄 + * + * @return 杩斿洖-1琛ㄧず杩樻病鏈夊啓鍏ュ璞″唴瀹癸紝澶т簬-1琛ㄧず宸插啓鍏ュ璞″唴瀹癸紝杩斿洖瀵硅薄鍐呭澶у皬 + */ + public abstract int writeMapB(int size, Encodeable keyEncoder, Encodeable valueEncoder, Object obj); + + /** + * 杈撳嚭涓涓狹ap涓璳ey涓巚alue闂寸殑闂撮殧绗 + * + */ + public abstract void writeMapMark(); + + /** + * 杈撳嚭涓涓狹ap鍚庣殑鎿嶄綔 + * + */ + public abstract void writeMapE(); + + /** + * 杈撳嚭涓涓瓧娈靛悕 + * + * @param member EnMember + * @param fieldName 瀛楁鍚嶇О + * @param fieldType 瀛楁绫诲瀷 + * @param fieldPos 瀛楁椤哄簭 + */ + public abstract void writeFieldName(EnMember member, String fieldName, Type fieldType, int fieldPos); + + /** + * 鍐欏叆涓涓猙oolean鍊 + * + * @param value boolean鍊 + */ + public abstract void writeBoolean(boolean value); + + /** + * 鍐欏叆涓涓猙yte鍊 + * + * @param value byte鍊 + */ + public abstract void writeByte(byte value); + + /** + * 鍐欏叆byte[] + * + * @param values byte[] + */ + public abstract void writeByteArray(byte[] values); + + /** + * 鍐欏叆涓涓猚har鍊 + * + * @param value char鍊 + */ + public abstract void writeChar(char value); + + /** + * 鍐欏叆涓涓猻hort鍊 + * + * @param value short鍊 + */ + public abstract void writeShort(short value); + + /** + * 鍐欏叆涓涓猧nt鍊 + * + * @param value int鍊 + */ + public abstract void writeInt(int value); + + /** + * 鍐欏叆涓涓猯ong鍊 + * + * @param value long鍊 + */ + public abstract void writeLong(long value); + + /** + * 鍐欏叆涓涓猣loat鍊 + * + * @param value float鍊 + */ + public abstract void writeFloat(float value); + + /** + * 鍐欏叆涓涓猟ouble鍊 + * + * @param value double鍊 + */ + public abstract void writeDouble(double value); + + /** + * 鍐欏叆鏃犺浆涔夊瓧绗﹂暱搴︿笉瓒呰繃255鐨勫瓧绗︿覆锛 渚嬪鏋氫妇鍊笺佸瓧娈靛悕銆佺被鍚嶅瓧绗︿覆绛 * + * + * @param value 闈炵┖涓斾笉鍚渶瑕佽浆涔夌殑瀛楃鐨凷tring鍊 + */ + public abstract void writeSmallString(String value); + + /** + * 鍐欏叆涓涓猄tring鍊 + * + * @param value String鍊 + */ + public abstract void writeString(String value); + + /** + * 鍐欏叆涓涓猄tringConvertWrapper鍊 + * + * @param value StringConvertWrapper鍊 + */ + public abstract void writeWrapper(StringWrapper value); +} diff --git a/src/main/java/org/redkale/convert/bson/BsonByteBufferReader.java b/src/main/java/org/redkale/convert/bson/BsonByteBufferReader.java index ef60e8456..77bdfe3b9 100644 --- a/src/main/java/org/redkale/convert/bson/BsonByteBufferReader.java +++ b/src/main/java/org/redkale/convert/bson/BsonByteBufferReader.java @@ -1,238 +1,238 @@ -/* - * 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.convert.bson; - -import java.nio.*; -import java.nio.charset.StandardCharsets; -import org.redkale.convert.*; -import static org.redkale.convert.Reader.SIGN_NULL; -import org.redkale.convert.ext.ByteSimpledCoder; - -/** - * 浠yteBuffer涓烘暟鎹浇浣撶殑BsonReader - * - * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public class BsonByteBufferReader extends BsonReader { - - private ByteBuffer[] buffers; - - private int currentIndex = 0; - - private ByteBuffer currentBuffer; - - protected ConvertMask mask; - - protected BsonByteBufferReader(ConvertMask mask, ByteBuffer... buffers) { - this.mask = mask; - this.buffers = buffers; - if (buffers != null && buffers.length > 0) this.currentBuffer = buffers[currentIndex]; - } - - @Override - protected boolean recycle() { - super.recycle(); // this.position 鍒濆鍖栧间负-1 - this.currentIndex = 0; - this.currentBuffer = null; - this.buffers = null; - this.mask = null; - return false; - } - - @Override - protected byte currentByte() { - return mask == null ? currentBuffer.get(currentBuffer.position()) : mask.unmask(currentBuffer.get(currentBuffer.position())); - } - - @Override - public int readMapB(DeMember member, byte[] typevals, Decodeable keyDecoder, Decodeable valueDecoder) { - short bt = readShort(); - if (bt == Reader.SIGN_NULL) return bt; - short lt = readShort(); - byte kt = readByte(); - byte vt = readByte(); - if (typevals != null) { - typevals[0] = kt; - typevals[1] = vt; - } - return (bt & 0xffff) << 16 | (lt & 0xffff); - } - - /** - * 鍒ゆ柇涓嬩竴涓潪绌虹櫧瀛楄妭鏄惁涓篬 - * - * @param member DeMember - * @param typevals byte[] - * @param componentDecoder Decodeable - * - * @return 鏁扮粍闀垮害鎴 SIGN_NULL - */ - @Override - public final int readArrayB(DeMember member, byte[] typevals, Decodeable componentDecoder) { - short bt = readShort(); - if (bt == Reader.SIGN_NULL) return bt; - short lt = readShort(); - if (componentDecoder != null && componentDecoder != ByteSimpledCoder.instance) { - byte comval = readByte(); - if (typevals != null) typevals[0] = comval; - } - return (bt & 0xffff) << 16 | (lt & 0xffff); - } -//------------------------------------------------------------ - - @Override - public final boolean readBoolean() { - return readByte() == 1; - } - - @Override - public byte readByte() { - if (this.currentBuffer.hasRemaining()) { - this.position++; - return mask == null ? this.currentBuffer.get() : mask.unmask(this.currentBuffer.get()); - } - for (;;) { - this.currentBuffer = this.buffers[++this.currentIndex]; - if (this.currentBuffer.hasRemaining()) { - this.position++; - return mask == null ? this.currentBuffer.get() : mask.unmask(this.currentBuffer.get()); - } - } - } - - @Override - public final char readChar() { - if (this.currentBuffer != null) { - int remain = this.currentBuffer.remaining(); - if (remain >= 2) { - this.position += 2; - if (mask == null) { - return this.currentBuffer.getChar(); - } else { - return (char) ((0xff00 & (mask.unmask(this.currentBuffer.get()) << 8)) | (0xff & mask.unmask(this.currentBuffer.get()))); - } - } - } - return (char) ((0xff00 & (readByte() << 8)) | (0xff & readByte())); - } - - @Override - public final short readShort() { - if (this.currentBuffer != null) { - int remain = this.currentBuffer.remaining(); - if (remain >= 2) { - this.position += 2; - if (mask == null) { - return this.currentBuffer.getShort(); - } else { - return (short) ((0xff00 & (mask.unmask(this.currentBuffer.get()) << 8)) | (0xff & mask.unmask(this.currentBuffer.get()))); - } - } - } - return (short) ((0xff00 & (readByte() << 8)) | (0xff & readByte())); - } - - @Override - public final int readInt() { - if (this.currentBuffer != null) { - int remain = this.currentBuffer.remaining(); - if (remain >= 4) { - this.position += 4; - if (mask == null) { - return this.currentBuffer.getInt(); - } else { - return ((mask.unmask(this.currentBuffer.get()) & 0xff) << 24) - | ((mask.unmask(this.currentBuffer.get()) & 0xff) << 16) - | ((mask.unmask(this.currentBuffer.get()) & 0xff) << 8) - | (mask.unmask(this.currentBuffer.get()) & 0xff); - } - } - } - return ((readByte() & 0xff) << 24) | ((readByte() & 0xff) << 16) | ((readByte() & 0xff) << 8) | (readByte() & 0xff); - } - - @Override - public final long readLong() { - if (this.currentBuffer != null) { - int remain = this.currentBuffer.remaining(); - if (remain >= 8) { - this.position += 8; - if (mask == null) { - return this.currentBuffer.getLong(); - } else { - return ((((long) mask.unmask(this.currentBuffer.get()) & 0xff) << 56) - | (((long) mask.unmask(this.currentBuffer.get()) & 0xff) << 48) - | (((long) mask.unmask(this.currentBuffer.get()) & 0xff) << 40) - | (((long) mask.unmask(this.currentBuffer.get()) & 0xff) << 32) - | (((long) mask.unmask(this.currentBuffer.get()) & 0xff) << 24) - | (((long) mask.unmask(this.currentBuffer.get()) & 0xff) << 16) - | (((long) mask.unmask(this.currentBuffer.get()) & 0xff) << 8) - | (((long) mask.unmask(this.currentBuffer.get()) & 0xff))); - } - } - } - return ((((long) readByte() & 0xff) << 56) - | (((long) readByte() & 0xff) << 48) - | (((long) readByte() & 0xff) << 40) - | (((long) readByte() & 0xff) << 32) - | (((long) readByte() & 0xff) << 24) - | (((long) readByte() & 0xff) << 16) - | (((long) readByte() & 0xff) << 8) - | (((long) readByte() & 0xff))); - } - - protected byte[] read(final int len) { - byte[] bs = new byte[len]; - read(bs, 0); - return bs; - } - - private void read(final byte[] bs, final int pos) { - int remain = this.currentBuffer.remaining(); - if (remain < 1) { - this.currentBuffer = this.buffers[++this.currentIndex]; - read(bs, pos); - return; - } - int len = bs.length - pos; - if (remain >= len) { - this.position += len; - this.currentBuffer.get(bs, pos, len); - if (mask != null) { - for (int i = pos, end = pos + len; i < end; i++) { - bs[i] = mask.unmask(bs[i]); - } - } - return; - } - this.currentBuffer.get(bs, pos, remain); - if (mask != null) { - for (int i = pos, end = pos + remain; i < end; i++) { - bs[i] = mask.unmask(bs[i]); - } - } - this.position += remain; - this.currentBuffer = this.buffers[++this.currentIndex]; - read(bs, pos + remain); - } - - @Override - public final String readSmallString() { - int len = 0xff & readByte(); - if (len == 0) return ""; - return new String(read(len)); - } - - @Override - public final String readString() { - int len = readInt(); - if (len == SIGN_NULL) return null; - if (len == 0) return ""; - return new String(read(len), StandardCharsets.UTF_8); - } -} +/* + * 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.convert.bson; + +import java.nio.*; +import java.nio.charset.StandardCharsets; +import org.redkale.convert.*; +import static org.redkale.convert.Reader.SIGN_NULL; +import org.redkale.convert.ext.ByteSimpledCoder; + +/** + * 浠yteBuffer涓烘暟鎹浇浣撶殑BsonReader + * + * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public class BsonByteBufferReader extends BsonReader { + + private ByteBuffer[] buffers; + + private int currentIndex = 0; + + private ByteBuffer currentBuffer; + + protected ConvertMask mask; + + protected BsonByteBufferReader(ConvertMask mask, ByteBuffer... buffers) { + this.mask = mask; + this.buffers = buffers; + if (buffers != null && buffers.length > 0) this.currentBuffer = buffers[currentIndex]; + } + + @Override + protected boolean recycle() { + super.recycle(); // this.position 鍒濆鍖栧间负-1 + this.currentIndex = 0; + this.currentBuffer = null; + this.buffers = null; + this.mask = null; + return false; + } + + @Override + protected byte currentByte() { + return mask == null ? currentBuffer.get(currentBuffer.position()) : mask.unmask(currentBuffer.get(currentBuffer.position())); + } + + @Override + public int readMapB(DeMember member, byte[] typevals, Decodeable keyDecoder, Decodeable valueDecoder) { + short bt = readShort(); + if (bt == Reader.SIGN_NULL) return bt; + short lt = readShort(); + byte kt = readByte(); + byte vt = readByte(); + if (typevals != null) { + typevals[0] = kt; + typevals[1] = vt; + } + return (bt & 0xffff) << 16 | (lt & 0xffff); + } + + /** + * 鍒ゆ柇涓嬩竴涓潪绌虹櫧瀛楄妭鏄惁涓篬 + * + * @param member DeMember + * @param typevals byte[] + * @param componentDecoder Decodeable + * + * @return 鏁扮粍闀垮害鎴 SIGN_NULL + */ + @Override + public final int readArrayB(DeMember member, byte[] typevals, Decodeable componentDecoder) { + short bt = readShort(); + if (bt == Reader.SIGN_NULL) return bt; + short lt = readShort(); + if (componentDecoder != null && componentDecoder != ByteSimpledCoder.instance) { + byte comval = readByte(); + if (typevals != null) typevals[0] = comval; + } + return (bt & 0xffff) << 16 | (lt & 0xffff); + } +//------------------------------------------------------------ + + @Override + public final boolean readBoolean() { + return readByte() == 1; + } + + @Override + public byte readByte() { + if (this.currentBuffer.hasRemaining()) { + this.position++; + return mask == null ? this.currentBuffer.get() : mask.unmask(this.currentBuffer.get()); + } + for (;;) { + this.currentBuffer = this.buffers[++this.currentIndex]; + if (this.currentBuffer.hasRemaining()) { + this.position++; + return mask == null ? this.currentBuffer.get() : mask.unmask(this.currentBuffer.get()); + } + } + } + + @Override + public final char readChar() { + if (this.currentBuffer != null) { + int remain = this.currentBuffer.remaining(); + if (remain >= 2) { + this.position += 2; + if (mask == null) { + return this.currentBuffer.getChar(); + } else { + return (char) ((0xff00 & (mask.unmask(this.currentBuffer.get()) << 8)) | (0xff & mask.unmask(this.currentBuffer.get()))); + } + } + } + return (char) ((0xff00 & (readByte() << 8)) | (0xff & readByte())); + } + + @Override + public final short readShort() { + if (this.currentBuffer != null) { + int remain = this.currentBuffer.remaining(); + if (remain >= 2) { + this.position += 2; + if (mask == null) { + return this.currentBuffer.getShort(); + } else { + return (short) ((0xff00 & (mask.unmask(this.currentBuffer.get()) << 8)) | (0xff & mask.unmask(this.currentBuffer.get()))); + } + } + } + return (short) ((0xff00 & (readByte() << 8)) | (0xff & readByte())); + } + + @Override + public final int readInt() { + if (this.currentBuffer != null) { + int remain = this.currentBuffer.remaining(); + if (remain >= 4) { + this.position += 4; + if (mask == null) { + return this.currentBuffer.getInt(); + } else { + return ((mask.unmask(this.currentBuffer.get()) & 0xff) << 24) + | ((mask.unmask(this.currentBuffer.get()) & 0xff) << 16) + | ((mask.unmask(this.currentBuffer.get()) & 0xff) << 8) + | (mask.unmask(this.currentBuffer.get()) & 0xff); + } + } + } + return ((readByte() & 0xff) << 24) | ((readByte() & 0xff) << 16) | ((readByte() & 0xff) << 8) | (readByte() & 0xff); + } + + @Override + public final long readLong() { + if (this.currentBuffer != null) { + int remain = this.currentBuffer.remaining(); + if (remain >= 8) { + this.position += 8; + if (mask == null) { + return this.currentBuffer.getLong(); + } else { + return ((((long) mask.unmask(this.currentBuffer.get()) & 0xff) << 56) + | (((long) mask.unmask(this.currentBuffer.get()) & 0xff) << 48) + | (((long) mask.unmask(this.currentBuffer.get()) & 0xff) << 40) + | (((long) mask.unmask(this.currentBuffer.get()) & 0xff) << 32) + | (((long) mask.unmask(this.currentBuffer.get()) & 0xff) << 24) + | (((long) mask.unmask(this.currentBuffer.get()) & 0xff) << 16) + | (((long) mask.unmask(this.currentBuffer.get()) & 0xff) << 8) + | (((long) mask.unmask(this.currentBuffer.get()) & 0xff))); + } + } + } + return ((((long) readByte() & 0xff) << 56) + | (((long) readByte() & 0xff) << 48) + | (((long) readByte() & 0xff) << 40) + | (((long) readByte() & 0xff) << 32) + | (((long) readByte() & 0xff) << 24) + | (((long) readByte() & 0xff) << 16) + | (((long) readByte() & 0xff) << 8) + | (((long) readByte() & 0xff))); + } + + protected byte[] read(final int len) { + byte[] bs = new byte[len]; + read(bs, 0); + return bs; + } + + private void read(final byte[] bs, final int pos) { + int remain = this.currentBuffer.remaining(); + if (remain < 1) { + this.currentBuffer = this.buffers[++this.currentIndex]; + read(bs, pos); + return; + } + int len = bs.length - pos; + if (remain >= len) { + this.position += len; + this.currentBuffer.get(bs, pos, len); + if (mask != null) { + for (int i = pos, end = pos + len; i < end; i++) { + bs[i] = mask.unmask(bs[i]); + } + } + return; + } + this.currentBuffer.get(bs, pos, remain); + if (mask != null) { + for (int i = pos, end = pos + remain; i < end; i++) { + bs[i] = mask.unmask(bs[i]); + } + } + this.position += remain; + this.currentBuffer = this.buffers[++this.currentIndex]; + read(bs, pos + remain); + } + + @Override + public final String readSmallString() { + int len = 0xff & readByte(); + if (len == 0) return ""; + return new String(read(len)); + } + + @Override + public final String readString() { + int len = readInt(); + if (len == SIGN_NULL) return null; + if (len == 0) return ""; + return new String(read(len), StandardCharsets.UTF_8); + } +} diff --git a/src/main/java/org/redkale/convert/bson/BsonByteBufferWriter.java b/src/main/java/org/redkale/convert/bson/BsonByteBufferWriter.java index c7a44a213..2058e92ed 100644 --- a/src/main/java/org/redkale/convert/bson/BsonByteBufferWriter.java +++ b/src/main/java/org/redkale/convert/bson/BsonByteBufferWriter.java @@ -1,155 +1,155 @@ -/* - * 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.convert.bson; - -import java.nio.*; -import java.util.function.*; -import org.redkale.util.Utility; - -/** - * 浠yteBuffer涓烘暟鎹浇浣撶殑BsonWriter - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public class BsonByteBufferWriter extends BsonWriter { - - private final Supplier supplier; - - private ByteBuffer[] buffers; - - private int index; - - public BsonByteBufferWriter(Supplier supplier) { - this(false, supplier); - } - - protected BsonByteBufferWriter(boolean tiny, Supplier supplier) { - super((byte[]) null); - this.tiny = tiny; - this.supplier = supplier; - } - - @Override - public ByteBuffer[] toBuffers() { - if (buffers == null) return new ByteBuffer[0]; - for (int i = index; i < this.buffers.length; i++) { - ByteBuffer buf = this.buffers[i]; - if (buf.position() != 0) buf.flip(); - } - return this.buffers; - } - - @Override - public byte[] toArray() { - if (buffers == null) return new byte[0]; - int pos = 0; - byte[] bytes = new byte[this.count]; - for (ByteBuffer buf : toBuffers()) { - int r = buf.remaining(); - buf.get(bytes, pos, r); - buf.flip(); - pos += r; - } - return bytes; - } - - @Override - public String toString() { - return this.getClass().getSimpleName() + "[count=" + this.count + "]"; - } - - @Override - public BsonByteBufferWriter tiny(boolean tiny) { - this.tiny = tiny; - return this; - } - - @Override - protected int expand(final int byteLength) { - if (this.buffers == null) { - this.index = 0; - this.buffers = new ByteBuffer[]{supplier.get()}; - } - ByteBuffer buffer = this.buffers[index]; - if (!buffer.hasRemaining()) { - buffer.flip(); - buffer = supplier.get(); - this.buffers = Utility.append(this.buffers, buffer); - this.index++; - } - int len = buffer.remaining(); - int size = 0; - while (len < byteLength) { - buffer = supplier.get(); - this.buffers = Utility.append(this.buffers, buffer); - len += buffer.remaining(); - size++; - } - return size; - } - - @Override - public void writeTo(final byte[] chs, final int start, final int len) { - if (expand(len) == 0) { - this.buffers[index].put(chs, start, len); - } else { - ByteBuffer buffer = this.buffers[index]; - final int end = start + len; - int remain = len; //杩樺墿澶氬皯娌℃湁鍐 - while (remain > 0) { - final int br = buffer.remaining(); - if (remain > br) { //涓涓猙uffer鍐欎笉瀹 - buffer.put(chs, end - remain, br); - buffer = nextByteBuffer(); - remain -= br; - } else { - buffer.put(chs, end - remain, remain); - remain = 0; - } - } - } - this.count += len; - } - - private ByteBuffer nextByteBuffer() { - this.buffers[this.index].flip(); - return this.buffers[++this.index]; - } - - @Override - public void writeTo(final byte ch) { - expand(1); - this.buffers[index].put(ch); - count++; - } - - @Override - protected boolean recycle() { - super.recycle(); - this.index = 0; - this.specify = null; - this.buffers = null; - return false; - } - - @Override - public byte[] content() { - throw new UnsupportedOperationException("Not supported yet."); //鏃犻渶瀹炵幇 - } - - @Override - public int offset() { - throw new UnsupportedOperationException("Not supported yet.");//鏃犻渶瀹炵幇 - } - - @Override - public int length() { - throw new UnsupportedOperationException("Not supported yet."); //鏃犻渶瀹炵幇 - } -} +/* + * 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.convert.bson; + +import java.nio.*; +import java.util.function.*; +import org.redkale.util.Utility; + +/** + * 浠yteBuffer涓烘暟鎹浇浣撶殑BsonWriter + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public class BsonByteBufferWriter extends BsonWriter { + + private final Supplier supplier; + + private ByteBuffer[] buffers; + + private int index; + + public BsonByteBufferWriter(Supplier supplier) { + this(false, supplier); + } + + protected BsonByteBufferWriter(boolean tiny, Supplier supplier) { + super((byte[]) null); + this.tiny = tiny; + this.supplier = supplier; + } + + @Override + public ByteBuffer[] toBuffers() { + if (buffers == null) return new ByteBuffer[0]; + for (int i = index; i < this.buffers.length; i++) { + ByteBuffer buf = this.buffers[i]; + if (buf.position() != 0) buf.flip(); + } + return this.buffers; + } + + @Override + public byte[] toArray() { + if (buffers == null) return new byte[0]; + int pos = 0; + byte[] bytes = new byte[this.count]; + for (ByteBuffer buf : toBuffers()) { + int r = buf.remaining(); + buf.get(bytes, pos, r); + buf.flip(); + pos += r; + } + return bytes; + } + + @Override + public String toString() { + return this.getClass().getSimpleName() + "[count=" + this.count + "]"; + } + + @Override + public BsonByteBufferWriter tiny(boolean tiny) { + this.tiny = tiny; + return this; + } + + @Override + protected int expand(final int byteLength) { + if (this.buffers == null) { + this.index = 0; + this.buffers = new ByteBuffer[]{supplier.get()}; + } + ByteBuffer buffer = this.buffers[index]; + if (!buffer.hasRemaining()) { + buffer.flip(); + buffer = supplier.get(); + this.buffers = Utility.append(this.buffers, buffer); + this.index++; + } + int len = buffer.remaining(); + int size = 0; + while (len < byteLength) { + buffer = supplier.get(); + this.buffers = Utility.append(this.buffers, buffer); + len += buffer.remaining(); + size++; + } + return size; + } + + @Override + public void writeTo(final byte[] chs, final int start, final int len) { + if (expand(len) == 0) { + this.buffers[index].put(chs, start, len); + } else { + ByteBuffer buffer = this.buffers[index]; + final int end = start + len; + int remain = len; //杩樺墿澶氬皯娌℃湁鍐 + while (remain > 0) { + final int br = buffer.remaining(); + if (remain > br) { //涓涓猙uffer鍐欎笉瀹 + buffer.put(chs, end - remain, br); + buffer = nextByteBuffer(); + remain -= br; + } else { + buffer.put(chs, end - remain, remain); + remain = 0; + } + } + } + this.count += len; + } + + private ByteBuffer nextByteBuffer() { + this.buffers[this.index].flip(); + return this.buffers[++this.index]; + } + + @Override + public void writeTo(final byte ch) { + expand(1); + this.buffers[index].put(ch); + count++; + } + + @Override + protected boolean recycle() { + super.recycle(); + this.index = 0; + this.specify = null; + this.buffers = null; + return false; + } + + @Override + public byte[] content() { + throw new UnsupportedOperationException("Not supported yet."); //鏃犻渶瀹炵幇 + } + + @Override + public int offset() { + throw new UnsupportedOperationException("Not supported yet.");//鏃犻渶瀹炵幇 + } + + @Override + public int length() { + throw new UnsupportedOperationException("Not supported yet."); //鏃犻渶瀹炵幇 + } +} diff --git a/src/main/java/org/redkale/convert/bson/BsonConvert.java b/src/main/java/org/redkale/convert/bson/BsonConvert.java index 2eda622a9..ebd057136 100644 --- a/src/main/java/org/redkale/convert/bson/BsonConvert.java +++ b/src/main/java/org/redkale/convert/bson/BsonConvert.java @@ -1,297 +1,297 @@ -/* - * 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.convert.bson; - -import java.io.*; -import java.lang.reflect.*; -import java.nio.*; -import java.util.function.*; -import org.redkale.convert.*; -import org.redkale.util.*; - -/** - *

- * BSON鍗忚鏍煎紡:
- *  1) 鍩烘湰鏁版嵁绫诲瀷: 鐩存帴杞崲鎴恇yte[]
- *  2) SmallString(鏃犵壒娈婂瓧绗︿笖闀垮害灏忎簬256鐨勫瓧绗︿覆): length(1 byte) + byte[](utf8); 閫氬父鐢ㄤ簬绫诲悕銆佸瓧娈靛悕銆佹灇涓俱
- *  3) String: length(4 bytes) + byte[](utf8);
- *  4) 鏁扮粍: length(4 bytes) + byte[]...
- *  5) Object:
- *      1銆 realclass (SmallString) (濡傛灉鎸囧畾鏍煎紡鍖栫殑class涓庡疄浣撳璞$殑class涓嶄竴鑷存墠浼氭湁璇ュ, 璇ュ煎彲浠ヤ娇鐢ˊConvertEntity缁欏叾鍙栦釜鍒悕)
- *      2銆 绌哄瓧绗︿覆(SmallString)
- *      3銆 SIGN_OBJECTB 鏍囪浣嶏紝鍊煎浐瀹氫负0xBB (short)
- *      4銆 寰幆瀛楁鍊:
- *          4.1 SIGN_HASNEXT 鏍囪浣嶏紝鍊煎浐瀹氫负1 (byte)
- *          4.2 瀛楁绫诲瀷; 1-9涓哄熀鏈被鍨嬪拰瀛楃涓; 101-109涓哄熀鏈被鍨嬪拰瀛楃涓茬殑鏁扮粍; 127涓篛bject
- *          4.3 瀛楁鍚 (SmallString)
- *          4.4 瀛楁鐨勫糘bject
- *      5銆 SIGN_NONEXT 鏍囪浣嶏紝鍊煎浐瀹氫负0 (byte)
- *      6銆 SIGN_OBJECTE 鏍囪浣嶏紝鍊煎浐瀹氫负0xEE (short)
- *
- * 
- *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public class BsonConvert extends BinaryConvert { - - private final ThreadLocal writerPool = ThreadLocal.withInitial(BsonWriter::new); - - private final Consumer offerConsumer = w -> offerBsonWriter(w); - - private final boolean tiny; - - protected BsonConvert(ConvertFactory factory, boolean tiny) { - super(factory); - this.tiny = tiny; - } - - @Override - public BsonFactory getFactory() { - return (BsonFactory) factory; - } - - public static BsonConvert root() { - return BsonFactory.root().getConvert(); - } - - @Override - public BsonConvert newConvert(final BiFunction fieldFunc) { - return newConvert(fieldFunc, null); - } - - @Override - public BsonConvert newConvert(final BiFunction fieldFunc, Function objExtFunc) { - return new BsonConvert(getFactory(), tiny) { - @Override - protected S configWrite(S writer) { - return fieldFunc(writer, fieldFunc, objExtFunc); - } - }; - } - - //------------------------------ reader ----------------------------------------------------------- - public BsonReader pollBsonReader(final ByteBuffer... buffers) { - return new BsonByteBufferReader((ConvertMask) null, buffers); - } - - public BsonReader pollBsonReader(final InputStream in) { - return new BsonStreamReader(in); - } - - public BsonReader pollBsonReader() { - return new BsonReader(); - } - - public void offerBsonReader(final BsonReader in) { - //鏃犻渶鍥炴敹 - } - - //------------------------------ writer ----------------------------------------------------------- - public BsonByteBufferWriter pollBsonWriter(final Supplier supplier) { - return configWrite(new BsonByteBufferWriter(tiny, supplier)); - } - - protected BsonWriter pollBsonWriter(final OutputStream out) { - return configWrite(new BsonStreamWriter(tiny, out)); - } - - public BsonWriter pollBsonWriter() { - BsonWriter writer = writerPool.get(); - if (writer == null) { - writer = new BsonWriter(); - } else { - writerPool.set(null); - } - return configWrite(writer.tiny(tiny)); - } - - public void offerBsonWriter(final BsonWriter out) { - if (out != null) { - out.recycle(); - writerPool.set(out); - } - } - - //------------------------------ convertFrom ----------------------------------------------------------- - @Override - public T convertFrom(final Type type, final byte[] bytes) { - if (bytes == null) return null; - return convertFrom(type, bytes, 0, bytes.length); - } - - @Override - @SuppressWarnings("unchecked") - public T convertFrom(final Type type, final byte[] bytes, final int offset, final int len) { - if (type == null) return null; - final BsonReader in = new BsonReader(bytes, offset, len); - @SuppressWarnings("unchecked") - T rs = (T) factory.loadDecoder(type).convertFrom(in); - return rs; - } - - @SuppressWarnings("unchecked") - public T convertFrom(final Type type, final InputStream in) { - if (type == null || in == null) return null; - return (T) factory.loadDecoder(type).convertFrom(new BsonStreamReader(in)); - } - - @Override - @SuppressWarnings("unchecked") - public T convertFrom(final Type type, final ByteBuffer... buffers) { - if (type == null || buffers.length < 1) return null; - return (T) factory.loadDecoder(type).convertFrom(new BsonByteBufferReader((ConvertMask) null, buffers)); - } - - @Override - @SuppressWarnings("unchecked") - public T convertFrom(final Type type, final ConvertMask mask, final ByteBuffer... buffers) { - if (type == null || buffers.length < 1) return null; - return (T) factory.loadDecoder(type).convertFrom(new BsonByteBufferReader(mask, buffers)); - } - - @SuppressWarnings("unchecked") - public T convertFrom(final Type type, final BsonReader reader) { - if (type == null) return null; - @SuppressWarnings("unchecked") - T rs = (T) factory.loadDecoder(type).convertFrom(reader); - return rs; - } - - //------------------------------ convertTo ----------------------------------------------------------- - @Override - public byte[] convertTo(final Object value) { - if (value == null) { - final BsonWriter out = pollBsonWriter(); - out.writeNull(); - byte[] result = out.toArray(); - offerBsonWriter(out); - return result; - } - return convertTo(value.getClass(), value); - } - - @Override - public byte[] convertTo(final Type type, final Object value) { - if (type == null) return null; - final BsonWriter writer = pollBsonWriter(); - factory.loadEncoder(type).convertTo(writer, value); - byte[] result = writer.toArray(); - offerBsonWriter(writer); - return result; - } - - @Override - public byte[] convertToBytes(final Object value) { - return convertTo(value); - } - - @Override - public byte[] convertToBytes(final Type type, final Object value) { - return convertTo(type, value); - } - - @Override - public void convertToBytes(final Object value, final ConvertBytesHandler handler) { - convertToBytes(value == null ? null : value.getClass(), value, handler); - } - - @Override - public void convertToBytes(final Type type, final Object value, final ConvertBytesHandler handler) { - final BsonWriter writer = pollBsonWriter(); - if (type == null) { - writer.writeNull(); - } else { - factory.loadEncoder(type).convertTo(writer, value); - } - writer.completed(handler, offerConsumer); - } - - @Override - public void convertToBytes(final ByteArray array, final Object value) { - convertToBytes(array, value == null ? null : value.getClass(), value); - } - - @Override - public void convertToBytes(final ByteArray array, final Type type, final Object value) { - final BsonWriter writer = configWrite(new BsonWriter(array).tiny(tiny)); - if (type == null) { - writer.writeNull(); - } else { - factory.loadEncoder(type).convertTo(writer, value); - } - writer.directTo(array); - } - - public void convertTo(final OutputStream out, final Object value) { - if (value == null) { - pollBsonWriter(out).writeNull(); - } else { - factory.loadEncoder(value.getClass()).convertTo(pollBsonWriter(out), value); - } - } - - public void convertTo(final OutputStream out, final Type type, final Object value) { - if (type == null) return; - if (value == null) { - pollBsonWriter(out).writeNull(); - } else { - factory.loadEncoder(type).convertTo(pollBsonWriter(out), value); - } - } - - @Override - public ByteBuffer[] convertTo(final Supplier supplier, final Object value) { - if (supplier == null) return null; - BsonByteBufferWriter out = pollBsonWriter(supplier); - if (value == null) { - out.writeNull(); - } else { - factory.loadEncoder(value.getClass()).convertTo(out, value); - } - return out.toBuffers(); - } - - @Override - public ByteBuffer[] convertTo(final Supplier supplier, final Type type, final Object value) { - if (supplier == null || type == null) return null; - BsonByteBufferWriter writer = pollBsonWriter(supplier); - if (value == null) { - writer.writeNull(); - } else { - factory.loadEncoder(type).convertTo(writer, value); - } - return writer.toBuffers(); - } - - @Override - public void convertTo(final BsonWriter writer, final Object value) { - if (value == null) { - writer.writeNull(); - } else { - factory.loadEncoder(value.getClass()).convertTo(writer, value); - } - } - - @Override - public void convertTo(final BsonWriter writer, final Type type, final Object value) { - if (type == null) return; - factory.loadEncoder(type).convertTo(writer, value); - } - - public BsonWriter convertToWriter(final Object value) { - if (value == null) return null; - return convertToWriter(value.getClass(), value); - } - - public BsonWriter convertToWriter(final Type type, final Object value) { - if (type == null) return null; - final BsonWriter writer = writerPool.get().tiny(tiny); - factory.loadEncoder(type).convertTo(writer, value); - return writer; - } -} +/* + * 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.convert.bson; + +import java.io.*; +import java.lang.reflect.*; +import java.nio.*; +import java.util.function.*; +import org.redkale.convert.*; +import org.redkale.util.*; + +/** + *

+ * BSON鍗忚鏍煎紡:
+ *  1) 鍩烘湰鏁版嵁绫诲瀷: 鐩存帴杞崲鎴恇yte[]
+ *  2) SmallString(鏃犵壒娈婂瓧绗︿笖闀垮害灏忎簬256鐨勫瓧绗︿覆): length(1 byte) + byte[](utf8); 閫氬父鐢ㄤ簬绫诲悕銆佸瓧娈靛悕銆佹灇涓俱
+ *  3) String: length(4 bytes) + byte[](utf8);
+ *  4) 鏁扮粍: length(4 bytes) + byte[]...
+ *  5) Object:
+ *      1銆 realclass (SmallString) (濡傛灉鎸囧畾鏍煎紡鍖栫殑class涓庡疄浣撳璞$殑class涓嶄竴鑷存墠浼氭湁璇ュ, 璇ュ煎彲浠ヤ娇鐢ˊConvertEntity缁欏叾鍙栦釜鍒悕)
+ *      2銆 绌哄瓧绗︿覆(SmallString)
+ *      3銆 SIGN_OBJECTB 鏍囪浣嶏紝鍊煎浐瀹氫负0xBB (short)
+ *      4銆 寰幆瀛楁鍊:
+ *          4.1 SIGN_HASNEXT 鏍囪浣嶏紝鍊煎浐瀹氫负1 (byte)
+ *          4.2 瀛楁绫诲瀷; 1-9涓哄熀鏈被鍨嬪拰瀛楃涓; 101-109涓哄熀鏈被鍨嬪拰瀛楃涓茬殑鏁扮粍; 127涓篛bject
+ *          4.3 瀛楁鍚 (SmallString)
+ *          4.4 瀛楁鐨勫糘bject
+ *      5銆 SIGN_NONEXT 鏍囪浣嶏紝鍊煎浐瀹氫负0 (byte)
+ *      6銆 SIGN_OBJECTE 鏍囪浣嶏紝鍊煎浐瀹氫负0xEE (short)
+ *
+ * 
+ *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public class BsonConvert extends BinaryConvert { + + private final ThreadLocal writerPool = ThreadLocal.withInitial(BsonWriter::new); + + private final Consumer offerConsumer = w -> offerBsonWriter(w); + + private final boolean tiny; + + protected BsonConvert(ConvertFactory factory, boolean tiny) { + super(factory); + this.tiny = tiny; + } + + @Override + public BsonFactory getFactory() { + return (BsonFactory) factory; + } + + public static BsonConvert root() { + return BsonFactory.root().getConvert(); + } + + @Override + public BsonConvert newConvert(final BiFunction fieldFunc) { + return newConvert(fieldFunc, null); + } + + @Override + public BsonConvert newConvert(final BiFunction fieldFunc, Function objExtFunc) { + return new BsonConvert(getFactory(), tiny) { + @Override + protected S configWrite(S writer) { + return fieldFunc(writer, fieldFunc, objExtFunc); + } + }; + } + + //------------------------------ reader ----------------------------------------------------------- + public BsonReader pollBsonReader(final ByteBuffer... buffers) { + return new BsonByteBufferReader((ConvertMask) null, buffers); + } + + public BsonReader pollBsonReader(final InputStream in) { + return new BsonStreamReader(in); + } + + public BsonReader pollBsonReader() { + return new BsonReader(); + } + + public void offerBsonReader(final BsonReader in) { + //鏃犻渶鍥炴敹 + } + + //------------------------------ writer ----------------------------------------------------------- + public BsonByteBufferWriter pollBsonWriter(final Supplier supplier) { + return configWrite(new BsonByteBufferWriter(tiny, supplier)); + } + + protected BsonWriter pollBsonWriter(final OutputStream out) { + return configWrite(new BsonStreamWriter(tiny, out)); + } + + public BsonWriter pollBsonWriter() { + BsonWriter writer = writerPool.get(); + if (writer == null) { + writer = new BsonWriter(); + } else { + writerPool.set(null); + } + return configWrite(writer.tiny(tiny)); + } + + public void offerBsonWriter(final BsonWriter out) { + if (out != null) { + out.recycle(); + writerPool.set(out); + } + } + + //------------------------------ convertFrom ----------------------------------------------------------- + @Override + public T convertFrom(final Type type, final byte[] bytes) { + if (bytes == null) return null; + return convertFrom(type, bytes, 0, bytes.length); + } + + @Override + @SuppressWarnings("unchecked") + public T convertFrom(final Type type, final byte[] bytes, final int offset, final int len) { + if (type == null) return null; + final BsonReader in = new BsonReader(bytes, offset, len); + @SuppressWarnings("unchecked") + T rs = (T) factory.loadDecoder(type).convertFrom(in); + return rs; + } + + @SuppressWarnings("unchecked") + public T convertFrom(final Type type, final InputStream in) { + if (type == null || in == null) return null; + return (T) factory.loadDecoder(type).convertFrom(new BsonStreamReader(in)); + } + + @Override + @SuppressWarnings("unchecked") + public T convertFrom(final Type type, final ByteBuffer... buffers) { + if (type == null || buffers.length < 1) return null; + return (T) factory.loadDecoder(type).convertFrom(new BsonByteBufferReader((ConvertMask) null, buffers)); + } + + @Override + @SuppressWarnings("unchecked") + public T convertFrom(final Type type, final ConvertMask mask, final ByteBuffer... buffers) { + if (type == null || buffers.length < 1) return null; + return (T) factory.loadDecoder(type).convertFrom(new BsonByteBufferReader(mask, buffers)); + } + + @SuppressWarnings("unchecked") + public T convertFrom(final Type type, final BsonReader reader) { + if (type == null) return null; + @SuppressWarnings("unchecked") + T rs = (T) factory.loadDecoder(type).convertFrom(reader); + return rs; + } + + //------------------------------ convertTo ----------------------------------------------------------- + @Override + public byte[] convertTo(final Object value) { + if (value == null) { + final BsonWriter out = pollBsonWriter(); + out.writeNull(); + byte[] result = out.toArray(); + offerBsonWriter(out); + return result; + } + return convertTo(value.getClass(), value); + } + + @Override + public byte[] convertTo(final Type type, final Object value) { + if (type == null) return null; + final BsonWriter writer = pollBsonWriter(); + factory.loadEncoder(type).convertTo(writer, value); + byte[] result = writer.toArray(); + offerBsonWriter(writer); + return result; + } + + @Override + public byte[] convertToBytes(final Object value) { + return convertTo(value); + } + + @Override + public byte[] convertToBytes(final Type type, final Object value) { + return convertTo(type, value); + } + + @Override + public void convertToBytes(final Object value, final ConvertBytesHandler handler) { + convertToBytes(value == null ? null : value.getClass(), value, handler); + } + + @Override + public void convertToBytes(final Type type, final Object value, final ConvertBytesHandler handler) { + final BsonWriter writer = pollBsonWriter(); + if (type == null) { + writer.writeNull(); + } else { + factory.loadEncoder(type).convertTo(writer, value); + } + writer.completed(handler, offerConsumer); + } + + @Override + public void convertToBytes(final ByteArray array, final Object value) { + convertToBytes(array, value == null ? null : value.getClass(), value); + } + + @Override + public void convertToBytes(final ByteArray array, final Type type, final Object value) { + final BsonWriter writer = configWrite(new BsonWriter(array).tiny(tiny)); + if (type == null) { + writer.writeNull(); + } else { + factory.loadEncoder(type).convertTo(writer, value); + } + writer.directTo(array); + } + + public void convertTo(final OutputStream out, final Object value) { + if (value == null) { + pollBsonWriter(out).writeNull(); + } else { + factory.loadEncoder(value.getClass()).convertTo(pollBsonWriter(out), value); + } + } + + public void convertTo(final OutputStream out, final Type type, final Object value) { + if (type == null) return; + if (value == null) { + pollBsonWriter(out).writeNull(); + } else { + factory.loadEncoder(type).convertTo(pollBsonWriter(out), value); + } + } + + @Override + public ByteBuffer[] convertTo(final Supplier supplier, final Object value) { + if (supplier == null) return null; + BsonByteBufferWriter out = pollBsonWriter(supplier); + if (value == null) { + out.writeNull(); + } else { + factory.loadEncoder(value.getClass()).convertTo(out, value); + } + return out.toBuffers(); + } + + @Override + public ByteBuffer[] convertTo(final Supplier supplier, final Type type, final Object value) { + if (supplier == null || type == null) return null; + BsonByteBufferWriter writer = pollBsonWriter(supplier); + if (value == null) { + writer.writeNull(); + } else { + factory.loadEncoder(type).convertTo(writer, value); + } + return writer.toBuffers(); + } + + @Override + public void convertTo(final BsonWriter writer, final Object value) { + if (value == null) { + writer.writeNull(); + } else { + factory.loadEncoder(value.getClass()).convertTo(writer, value); + } + } + + @Override + public void convertTo(final BsonWriter writer, final Type type, final Object value) { + if (type == null) return; + factory.loadEncoder(type).convertTo(writer, value); + } + + public BsonWriter convertToWriter(final Object value) { + if (value == null) return null; + return convertToWriter(value.getClass(), value); + } + + public BsonWriter convertToWriter(final Type type, final Object value) { + if (type == null) return null; + final BsonWriter writer = writerPool.get().tiny(tiny); + factory.loadEncoder(type).convertTo(writer, value); + return writer; + } +} diff --git a/src/main/java/org/redkale/convert/bson/BsonFactory.java b/src/main/java/org/redkale/convert/bson/BsonFactory.java index 6fa59aca3..fcfdc8720 100644 --- a/src/main/java/org/redkale/convert/bson/BsonFactory.java +++ b/src/main/java/org/redkale/convert/bson/BsonFactory.java @@ -1,212 +1,212 @@ -/* - * 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.convert.bson; - -import java.io.Serializable; -import java.lang.reflect.Type; -import java.util.*; -import java.util.stream.Stream; -import org.redkale.convert.*; -import org.redkale.convert.ext.*; -import org.redkale.util.*; - -/** - * BSON鐨凜onvertFactory - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@SuppressWarnings("unchecked") -public final class BsonFactory extends ConvertFactory { - - private static final BsonFactory instance = new BsonFactory(null, getSystemPropertyBoolean("redkale.convert.bson.tiny", "redkale.convert.tiny", true)); - - static final Decodeable objectDecoder = instance.loadDecoder(Object.class); - - static final Encodeable objectEncoder = instance.loadEncoder(Object.class); - - static final Decodeable skipArrayDecoder = new SkipArrayDecoder(instance, Object[].class); - - static final Decodeable skipCollectionDecoder = new SkipCollectionDecoder(instance, new TypeToken>() { - }.getType()); - - static final Decodeable skipStreamDecoder = new SkipStreamDecoder(instance, new TypeToken>() { - }.getType()); - - static final Decodeable skipMapDecoder = new SkipMapDecoder(instance, Map.class); - - static { - instance.register(Serializable.class, objectDecoder); - instance.register(Serializable.class, objectEncoder); - - //instance.register(AnyValue.class, instance.loadDecoder(AnyValue.DefaultAnyValue.class)); - //instance.register(AnyValue.class, instance.loadEncoder(AnyValue.DefaultAnyValue.class)); - } - - private BsonFactory(BsonFactory parent, boolean tiny) { - super(parent, tiny); - } - - @Override - public BsonFactory tiny(boolean tiny) { - this.tiny = tiny; - return this; - } - - @Override - public BsonFactory skipAllIgnore(final boolean skipIgnore) { - this.registerSkipAllIgnore(skipIgnore); - return this; - } - - public static BsonFactory root() { - return instance; - } - - public static BsonFactory create() { - return new BsonFactory(null, getSystemPropertyBoolean("redkale.convert.bson.tiny", "redkale.convert.tiny", true)); - } - - @Override - public final BsonConvert getConvert() { - if (convert == null) convert = new BsonConvert(this, tiny); - return (BsonConvert) convert; - } - - @Override - public BsonFactory createChild() { - return new BsonFactory(this, this.tiny); - } - - @Override - public BsonFactory createChild(boolean tiny) { - return new BsonFactory(this, tiny); - } - - @Override - public ConvertType getConvertType() { - return ConvertType.BSON; - } - - @Override - public boolean isReversible() { - return true; - } - - @Override - public boolean isFieldSort() { - return true; - } - - protected static byte typeEnum(final Type type) { - return typeEnum(TypeToken.typeToClass(type)); - } - - protected static byte typeEnum(final Class type) { - Objects.requireNonNull(type); - byte typeval = 127; //瀛楁鐨勭被鍨嬪 - if (type == boolean.class || type == Boolean.class) { - typeval = 11; - } else if (type == byte.class || type == Byte.class) { - typeval = 12; - } else if (type == short.class || type == Short.class) { - typeval = 13; - } else if (type == char.class || type == Character.class) { - typeval = 14; - } else if (type == int.class || type == Integer.class) { - typeval = 15; - } else if (type == long.class || type == Long.class) { - typeval = 16; - } else if (type == float.class || type == Float.class) { - typeval = 17; - } else if (type == double.class || type == Double.class) { - typeval = 18; - } else if (type == String.class) { - typeval = 19; - } else if (type == boolean[].class || type == Boolean[].class) { - typeval = 21; - } else if (type == byte[].class || type == Byte[].class) { - typeval = 22; - } else if (type == short[].class || type == Short[].class) { - typeval = 23; - } else if (type == char[].class || type == Character[].class) { - typeval = 24; - } else if (type == int[].class || type == Integer[].class) { - typeval = 25; - } else if (type == long[].class || type == Long[].class) { - typeval = 26; - } else if (type == float[].class || type == Float[].class) { - typeval = 27; - } else if (type == double[].class || type == Double[].class) { - typeval = 28; - } else if (type == String[].class) { - typeval = 29; - } else if (type.isArray()) { - typeval = 81; - } else if (Collection.class.isAssignableFrom(type)) { - typeval = 82; - } else if (Stream.class.isAssignableFrom(type)) { - typeval = 83; - } else if (Map.class.isAssignableFrom(type)) { - typeval = 84; - } - return typeval; - } - - protected static Decodeable typeEnum(final byte typeval) { - switch (typeval) { - case 11: - return BoolSimpledCoder.instance; - case 12: - return ByteSimpledCoder.instance; - case 13: - return ShortSimpledCoder.instance; - case 14: - return CharSimpledCoder.instance; - case 15: - return IntSimpledCoder.instance; - case 16: - return LongSimpledCoder.instance; - case 17: - return FloatSimpledCoder.instance; - case 18: - return DoubleSimpledCoder.instance; - case 19: - return StringSimpledCoder.instance; - case 21: - return BoolArraySimpledCoder.instance; - case 22: - return ByteArraySimpledCoder.instance; - case 23: - return ShortArraySimpledCoder.instance; - case 24: - return CharArraySimpledCoder.instance; - case 25: - return IntArraySimpledCoder.instance; - case 26: - return LongArraySimpledCoder.instance; - case 27: - return FloatArraySimpledCoder.instance; - case 28: - return DoubleArraySimpledCoder.instance; - case 29: - return StringArraySimpledCoder.instance; - case 81: - return skipArrayDecoder; - case 82: - return skipCollectionDecoder; - case 83: - return skipStreamDecoder; - case 84: - return skipMapDecoder; - case 127: - return BsonFactory.objectDecoder; - } - return null; - } -} +/* + * 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.convert.bson; + +import java.io.Serializable; +import java.lang.reflect.Type; +import java.util.*; +import java.util.stream.Stream; +import org.redkale.convert.*; +import org.redkale.convert.ext.*; +import org.redkale.util.*; + +/** + * BSON鐨凜onvertFactory + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@SuppressWarnings("unchecked") +public final class BsonFactory extends ConvertFactory { + + private static final BsonFactory instance = new BsonFactory(null, getSystemPropertyBoolean("redkale.convert.bson.tiny", "redkale.convert.tiny", true)); + + static final Decodeable objectDecoder = instance.loadDecoder(Object.class); + + static final Encodeable objectEncoder = instance.loadEncoder(Object.class); + + static final Decodeable skipArrayDecoder = new SkipArrayDecoder(instance, Object[].class); + + static final Decodeable skipCollectionDecoder = new SkipCollectionDecoder(instance, new TypeToken>() { + }.getType()); + + static final Decodeable skipStreamDecoder = new SkipStreamDecoder(instance, new TypeToken>() { + }.getType()); + + static final Decodeable skipMapDecoder = new SkipMapDecoder(instance, Map.class); + + static { + instance.register(Serializable.class, objectDecoder); + instance.register(Serializable.class, objectEncoder); + + //instance.register(AnyValue.class, instance.loadDecoder(AnyValue.DefaultAnyValue.class)); + //instance.register(AnyValue.class, instance.loadEncoder(AnyValue.DefaultAnyValue.class)); + } + + private BsonFactory(BsonFactory parent, boolean tiny) { + super(parent, tiny); + } + + @Override + public BsonFactory tiny(boolean tiny) { + this.tiny = tiny; + return this; + } + + @Override + public BsonFactory skipAllIgnore(final boolean skipIgnore) { + this.registerSkipAllIgnore(skipIgnore); + return this; + } + + public static BsonFactory root() { + return instance; + } + + public static BsonFactory create() { + return new BsonFactory(null, getSystemPropertyBoolean("redkale.convert.bson.tiny", "redkale.convert.tiny", true)); + } + + @Override + public final BsonConvert getConvert() { + if (convert == null) convert = new BsonConvert(this, tiny); + return (BsonConvert) convert; + } + + @Override + public BsonFactory createChild() { + return new BsonFactory(this, this.tiny); + } + + @Override + public BsonFactory createChild(boolean tiny) { + return new BsonFactory(this, tiny); + } + + @Override + public ConvertType getConvertType() { + return ConvertType.BSON; + } + + @Override + public boolean isReversible() { + return true; + } + + @Override + public boolean isFieldSort() { + return true; + } + + protected static byte typeEnum(final Type type) { + return typeEnum(TypeToken.typeToClass(type)); + } + + protected static byte typeEnum(final Class type) { + Objects.requireNonNull(type); + byte typeval = 127; //瀛楁鐨勭被鍨嬪 + if (type == boolean.class || type == Boolean.class) { + typeval = 11; + } else if (type == byte.class || type == Byte.class) { + typeval = 12; + } else if (type == short.class || type == Short.class) { + typeval = 13; + } else if (type == char.class || type == Character.class) { + typeval = 14; + } else if (type == int.class || type == Integer.class) { + typeval = 15; + } else if (type == long.class || type == Long.class) { + typeval = 16; + } else if (type == float.class || type == Float.class) { + typeval = 17; + } else if (type == double.class || type == Double.class) { + typeval = 18; + } else if (type == String.class) { + typeval = 19; + } else if (type == boolean[].class || type == Boolean[].class) { + typeval = 21; + } else if (type == byte[].class || type == Byte[].class) { + typeval = 22; + } else if (type == short[].class || type == Short[].class) { + typeval = 23; + } else if (type == char[].class || type == Character[].class) { + typeval = 24; + } else if (type == int[].class || type == Integer[].class) { + typeval = 25; + } else if (type == long[].class || type == Long[].class) { + typeval = 26; + } else if (type == float[].class || type == Float[].class) { + typeval = 27; + } else if (type == double[].class || type == Double[].class) { + typeval = 28; + } else if (type == String[].class) { + typeval = 29; + } else if (type.isArray()) { + typeval = 81; + } else if (Collection.class.isAssignableFrom(type)) { + typeval = 82; + } else if (Stream.class.isAssignableFrom(type)) { + typeval = 83; + } else if (Map.class.isAssignableFrom(type)) { + typeval = 84; + } + return typeval; + } + + protected static Decodeable typeEnum(final byte typeval) { + switch (typeval) { + case 11: + return BoolSimpledCoder.instance; + case 12: + return ByteSimpledCoder.instance; + case 13: + return ShortSimpledCoder.instance; + case 14: + return CharSimpledCoder.instance; + case 15: + return IntSimpledCoder.instance; + case 16: + return LongSimpledCoder.instance; + case 17: + return FloatSimpledCoder.instance; + case 18: + return DoubleSimpledCoder.instance; + case 19: + return StringSimpledCoder.instance; + case 21: + return BoolArraySimpledCoder.instance; + case 22: + return ByteArraySimpledCoder.instance; + case 23: + return ShortArraySimpledCoder.instance; + case 24: + return CharArraySimpledCoder.instance; + case 25: + return IntArraySimpledCoder.instance; + case 26: + return LongArraySimpledCoder.instance; + case 27: + return FloatArraySimpledCoder.instance; + case 28: + return DoubleArraySimpledCoder.instance; + case 29: + return StringArraySimpledCoder.instance; + case 81: + return skipArrayDecoder; + case 82: + return skipCollectionDecoder; + case 83: + return skipStreamDecoder; + case 84: + return skipMapDecoder; + case 127: + return BsonFactory.objectDecoder; + } + return null; + } +} diff --git a/src/main/java/org/redkale/convert/bson/BsonReader.java b/src/main/java/org/redkale/convert/bson/BsonReader.java index 6490d51ce..51c09abfd 100644 --- a/src/main/java/org/redkale/convert/bson/BsonReader.java +++ b/src/main/java/org/redkale/convert/bson/BsonReader.java @@ -1,355 +1,355 @@ -/* - * 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.convert.bson; - -import java.nio.charset.StandardCharsets; -import org.redkale.convert.*; -import static org.redkale.convert.Reader.SIGN_NULL; -import org.redkale.convert.ext.*; -import org.redkale.util.*; - -/** - * BSON鏁版嵁婧 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public class BsonReader extends Reader { - - public static final short SIGN_OBJECTB = (short) 0xBB; - - public static final short SIGN_OBJECTE = (short) 0xEE; - - public static final byte SIGN_HASNEXT = 1; - - public static final byte SIGN_NONEXT = 0; - - public static final byte VERBOSE_NO = 1; - - public static final byte VERBOSE_YES = 2; - - protected byte typeval; //瀛楁鐨勭被鍨嬪 瀵瑰簲 BsonWriter.writeField - - protected int position = -1; - - private byte[] content; - - public BsonReader() { - } - - public static ObjectPool createPool(int max) { - return ObjectPool.createSafePool(max, (Object... params) -> new BsonReader(), null, (t) -> t.recycle()); - } - - public BsonReader(byte[] bytes) { - setBytes(bytes, 0, bytes.length); - } - - public BsonReader(byte[] bytes, int start, int len) { - setBytes(bytes, start, len); - } - - public final void setBytes(byte[] bytes) { - if (bytes == null) { - this.position = 0; - } else { - setBytes(bytes, 0, bytes.length); - } - } - - public final void setBytes(byte[] bytes, int start, int len) { - if (bytes == null) { - this.position = 0; - } else { - this.content = bytes; - this.position = start - 1; - //this.limit = start + len - 1; - } - } - - protected boolean recycle() { - this.position = -1; - this.typeval = 0; - //this.limit = -1; - this.content = null; - return true; - } - - public void close() { - this.recycle(); - } - - /** - * 璺宠繃灞炴х殑鍊 - */ - @Override - @SuppressWarnings("unchecked") - public final void skipValue() { - if (typeval == 0) return; - final byte val = this.typeval; - this.typeval = 0; - switch (val) { - case 11: readBoolean(); - break; - case 12: readByte(); - break; - case 13: readShort(); - break; - case 14: readChar(); - break; - case 15: readInt(); - break; - case 16: readLong(); - break; - case 17: readFloat(); - break; - case 18: readDouble(); - break; - case 19: readString(); - break; - default: - Decodeable decoder = BsonFactory.typeEnum(val); - if (decoder != null) decoder.convertFrom(this); - break; - } - } - - @Override - public final String readObjectB(final Class clazz) { - this.fieldIndex = 0; //蹇呴』瑕侀噸缃负0 - final String newcls = readClassName(); - if (newcls != null && !newcls.isEmpty()) return newcls; - short bt = readShort(); - if (bt == Reader.SIGN_NULL) return null; - if (bt != SIGN_OBJECTB) { - throw new ConvertException("a bson object must begin with " + (SIGN_OBJECTB) - + " (position = " + position + ") but '" + currentByte() + "'"); - } - return ""; - } - - @Override - public final void readObjectE(final Class clazz) { - if (readShort() != SIGN_OBJECTE) { - throw new ConvertException("a bson object must end with " + (SIGN_OBJECTE) - + " (position = " + position + ") but '" + currentByte() + "'"); - } - } - - protected byte currentByte() { - return this.content[this.position]; - } - - @Override - public int readMapB(DeMember member, byte[] typevals, Decodeable keyDecoder, Decodeable valueDecoder) { - short bt = readShort(); - if (bt == Reader.SIGN_NULL) return bt; - int rs = (bt & 0xffff) << 16 | ((content[++this.position] & 0xff) << 8) | (content[++this.position] & 0xff); - byte kt = readByte(); - byte vt = readByte(); - if (typevals != null) { - typevals[0] = kt; - typevals[1] = vt; - } - return rs; - } - - @Override - public final void readMapE() { - } - - /** - * 鍒ゆ柇涓嬩竴涓潪绌虹櫧瀛楄妭鏄惁涓篬 - * - * @return 鏁扮粍闀垮害鎴朣IGN_NULL - */ - @Override - public int readArrayB(DeMember member, byte[] typevals, Decodeable componentDecoder) { //componentDecoder鍙兘涓簄ull - short bt = readShort(); - if (bt == Reader.SIGN_NULL) return bt; - int rs = (bt & 0xffff) << 16 | ((content[++this.position] & 0xff) << 8) | (content[++this.position] & 0xff); - if (componentDecoder != null && componentDecoder != ByteSimpledCoder.instance) { - byte comval = readByte(); - if (typevals != null) typevals[0] = comval; - } - return rs; - } - - @Override - public final void readArrayE() { - } - - /** - * 鍒ゆ柇涓嬩竴涓潪绌虹櫧瀛楄妭鏄惁: - */ - @Override - public final void readBlank() { - } - - @Override - public int position() { - return this.position; - } - - @Override - public int readMemberContentLength(DeMember member, Decodeable decoder) { - return -1; - } - - /** - * 鍒ゆ柇瀵硅薄鏄惁瀛樺湪涓嬩竴涓睘鎬ф垨鑰呮暟缁勬槸鍚﹀瓨鍦ㄤ笅涓涓厓绱 - * - * @param startPosition 璧峰浣嶇疆 - * @param contentLength 鍐呭澶у皬锛 涓嶇‘瀹氱殑浼-1 - * - * @return 鏄惁瀛樺湪 - */ - @Override - public boolean hasNext(int startPosition, int contentLength) { - byte b = readByte(); - if (b == SIGN_HASNEXT) return true; - if (b != SIGN_NONEXT) throw new ConvertException("hasNext option must be (" + (SIGN_HASNEXT) - + " or " + (SIGN_NONEXT) + ") but '" + b + "' at position(" + this.position + ")"); - return false; - } - - @Override - public final DeMember readFieldName(final DeMember[] members) { - final String exceptedfield = readSmallString(); - this.typeval = readByte(); - final int len = members.length; - if (this.fieldIndex >= len) this.fieldIndex = 0; - for (int k = this.fieldIndex; k < len; k++) { - if (exceptedfield.equals(members[k].getAttribute().field())) { - this.fieldIndex = k; - return members[k]; - } - } - for (int k = 0; k < this.fieldIndex; k++) { - if (exceptedfield.equals(members[k].getAttribute().field())) { - this.fieldIndex = k; - return members[k]; - } - } - return null; - } - - //------------------------------------------------------------ - @Override - public boolean readBoolean() { - return content[++this.position] == 1; - } - - @Override - public byte readByte() { - return content[++this.position]; - } - - @Override - public final byte[] readByteArray() { - int len = readArrayB(null, null, null); - int contentLength = -1; - if (len == Reader.SIGN_NULL) return null; - if (len == Reader.SIGN_NOLENBUTBYTES) { - contentLength = readMemberContentLength(null, null); - len = Reader.SIGN_NOLENGTH; - } - if (len == Reader.SIGN_NOLENGTH) { - int size = 0; - byte[] data = new byte[8]; - int startPosition = position(); - while (hasNext(startPosition, contentLength)) { - if (size >= data.length) { - byte[] newdata = new byte[data.length + 4]; - System.arraycopy(data, 0, newdata, 0, size); - data = newdata; - } - data[size++] = readByte(); - } - readArrayE(); - byte[] newdata = new byte[size]; - System.arraycopy(data, 0, newdata, 0, size); - return newdata; - } else { - byte[] values = new byte[len]; - for (int i = 0; i < values.length; i++) { - values[i] = readByte(); - } - readArrayE(); - return values; - } - } - - @Override - public char readChar() { - return (char) ((0xff00 & (content[++this.position] << 8)) | (0xff & content[++this.position])); - } - - @Override - public short readShort() { - return (short) ((0xff00 & (content[++this.position] << 8)) | (0xff & content[++this.position])); - } - - @Override - public int readInt() { - return ((content[++this.position] & 0xff) << 24) | ((content[++this.position] & 0xff) << 16) - | ((content[++this.position] & 0xff) << 8) | (content[++this.position] & 0xff); - } - - @Override - public long readLong() { - return ((((long) content[++this.position] & 0xff) << 56) - | (((long) content[++this.position] & 0xff) << 48) - | (((long) content[++this.position] & 0xff) << 40) - | (((long) content[++this.position] & 0xff) << 32) - | (((long) content[++this.position] & 0xff) << 24) - | (((long) content[++this.position] & 0xff) << 16) - | (((long) content[++this.position] & 0xff) << 8) - | (((long) content[++this.position] & 0xff))); - } - - @Override - public final float readFloat() { - return Float.intBitsToFloat(readInt()); - } - - @Override - public final double readDouble() { - return Double.longBitsToDouble(readLong()); - } - - @Override - public final String readClassName() { - return readSmallString(); - } - - @Override - public String readSmallString() { - int len = 0xff & readByte(); - if (len == 0) return ""; - String value = new String(content, ++this.position, len); - this.position += len - 1; //涓婁竴琛屽凡缁++this.position锛屾墍浠ユ澶勮-1 - return value; - } - - @Override - public String readString() { - int len = readInt(); - if (len == SIGN_NULL) return null; - if (len == 0) return ""; - String value = new String(content, ++this.position, len, StandardCharsets.UTF_8); - this.position += len - 1;//涓婁竴琛屽凡缁++this.position锛屾墍浠ユ澶勮-1 - return value; - } - - @Override - public ValueType readType() { - throw new UnsupportedOperationException("Not supported yet."); - } - -} +/* + * 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.convert.bson; + +import java.nio.charset.StandardCharsets; +import org.redkale.convert.*; +import static org.redkale.convert.Reader.SIGN_NULL; +import org.redkale.convert.ext.*; +import org.redkale.util.*; + +/** + * BSON鏁版嵁婧 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public class BsonReader extends Reader { + + public static final short SIGN_OBJECTB = (short) 0xBB; + + public static final short SIGN_OBJECTE = (short) 0xEE; + + public static final byte SIGN_HASNEXT = 1; + + public static final byte SIGN_NONEXT = 0; + + public static final byte VERBOSE_NO = 1; + + public static final byte VERBOSE_YES = 2; + + protected byte typeval; //瀛楁鐨勭被鍨嬪 瀵瑰簲 BsonWriter.writeField + + protected int position = -1; + + private byte[] content; + + public BsonReader() { + } + + public static ObjectPool createPool(int max) { + return ObjectPool.createSafePool(max, (Object... params) -> new BsonReader(), null, (t) -> t.recycle()); + } + + public BsonReader(byte[] bytes) { + setBytes(bytes, 0, bytes.length); + } + + public BsonReader(byte[] bytes, int start, int len) { + setBytes(bytes, start, len); + } + + public final void setBytes(byte[] bytes) { + if (bytes == null) { + this.position = 0; + } else { + setBytes(bytes, 0, bytes.length); + } + } + + public final void setBytes(byte[] bytes, int start, int len) { + if (bytes == null) { + this.position = 0; + } else { + this.content = bytes; + this.position = start - 1; + //this.limit = start + len - 1; + } + } + + protected boolean recycle() { + this.position = -1; + this.typeval = 0; + //this.limit = -1; + this.content = null; + return true; + } + + public void close() { + this.recycle(); + } + + /** + * 璺宠繃灞炴х殑鍊 + */ + @Override + @SuppressWarnings("unchecked") + public final void skipValue() { + if (typeval == 0) return; + final byte val = this.typeval; + this.typeval = 0; + switch (val) { + case 11: readBoolean(); + break; + case 12: readByte(); + break; + case 13: readShort(); + break; + case 14: readChar(); + break; + case 15: readInt(); + break; + case 16: readLong(); + break; + case 17: readFloat(); + break; + case 18: readDouble(); + break; + case 19: readString(); + break; + default: + Decodeable decoder = BsonFactory.typeEnum(val); + if (decoder != null) decoder.convertFrom(this); + break; + } + } + + @Override + public final String readObjectB(final Class clazz) { + this.fieldIndex = 0; //蹇呴』瑕侀噸缃负0 + final String newcls = readClassName(); + if (newcls != null && !newcls.isEmpty()) return newcls; + short bt = readShort(); + if (bt == Reader.SIGN_NULL) return null; + if (bt != SIGN_OBJECTB) { + throw new ConvertException("a bson object must begin with " + (SIGN_OBJECTB) + + " (position = " + position + ") but '" + currentByte() + "'"); + } + return ""; + } + + @Override + public final void readObjectE(final Class clazz) { + if (readShort() != SIGN_OBJECTE) { + throw new ConvertException("a bson object must end with " + (SIGN_OBJECTE) + + " (position = " + position + ") but '" + currentByte() + "'"); + } + } + + protected byte currentByte() { + return this.content[this.position]; + } + + @Override + public int readMapB(DeMember member, byte[] typevals, Decodeable keyDecoder, Decodeable valueDecoder) { + short bt = readShort(); + if (bt == Reader.SIGN_NULL) return bt; + int rs = (bt & 0xffff) << 16 | ((content[++this.position] & 0xff) << 8) | (content[++this.position] & 0xff); + byte kt = readByte(); + byte vt = readByte(); + if (typevals != null) { + typevals[0] = kt; + typevals[1] = vt; + } + return rs; + } + + @Override + public final void readMapE() { + } + + /** + * 鍒ゆ柇涓嬩竴涓潪绌虹櫧瀛楄妭鏄惁涓篬 + * + * @return 鏁扮粍闀垮害鎴朣IGN_NULL + */ + @Override + public int readArrayB(DeMember member, byte[] typevals, Decodeable componentDecoder) { //componentDecoder鍙兘涓簄ull + short bt = readShort(); + if (bt == Reader.SIGN_NULL) return bt; + int rs = (bt & 0xffff) << 16 | ((content[++this.position] & 0xff) << 8) | (content[++this.position] & 0xff); + if (componentDecoder != null && componentDecoder != ByteSimpledCoder.instance) { + byte comval = readByte(); + if (typevals != null) typevals[0] = comval; + } + return rs; + } + + @Override + public final void readArrayE() { + } + + /** + * 鍒ゆ柇涓嬩竴涓潪绌虹櫧瀛楄妭鏄惁: + */ + @Override + public final void readBlank() { + } + + @Override + public int position() { + return this.position; + } + + @Override + public int readMemberContentLength(DeMember member, Decodeable decoder) { + return -1; + } + + /** + * 鍒ゆ柇瀵硅薄鏄惁瀛樺湪涓嬩竴涓睘鎬ф垨鑰呮暟缁勬槸鍚﹀瓨鍦ㄤ笅涓涓厓绱 + * + * @param startPosition 璧峰浣嶇疆 + * @param contentLength 鍐呭澶у皬锛 涓嶇‘瀹氱殑浼-1 + * + * @return 鏄惁瀛樺湪 + */ + @Override + public boolean hasNext(int startPosition, int contentLength) { + byte b = readByte(); + if (b == SIGN_HASNEXT) return true; + if (b != SIGN_NONEXT) throw new ConvertException("hasNext option must be (" + (SIGN_HASNEXT) + + " or " + (SIGN_NONEXT) + ") but '" + b + "' at position(" + this.position + ")"); + return false; + } + + @Override + public final DeMember readFieldName(final DeMember[] members) { + final String exceptedfield = readSmallString(); + this.typeval = readByte(); + final int len = members.length; + if (this.fieldIndex >= len) this.fieldIndex = 0; + for (int k = this.fieldIndex; k < len; k++) { + if (exceptedfield.equals(members[k].getAttribute().field())) { + this.fieldIndex = k; + return members[k]; + } + } + for (int k = 0; k < this.fieldIndex; k++) { + if (exceptedfield.equals(members[k].getAttribute().field())) { + this.fieldIndex = k; + return members[k]; + } + } + return null; + } + + //------------------------------------------------------------ + @Override + public boolean readBoolean() { + return content[++this.position] == 1; + } + + @Override + public byte readByte() { + return content[++this.position]; + } + + @Override + public final byte[] readByteArray() { + int len = readArrayB(null, null, null); + int contentLength = -1; + if (len == Reader.SIGN_NULL) return null; + if (len == Reader.SIGN_NOLENBUTBYTES) { + contentLength = readMemberContentLength(null, null); + len = Reader.SIGN_NOLENGTH; + } + if (len == Reader.SIGN_NOLENGTH) { + int size = 0; + byte[] data = new byte[8]; + int startPosition = position(); + while (hasNext(startPosition, contentLength)) { + if (size >= data.length) { + byte[] newdata = new byte[data.length + 4]; + System.arraycopy(data, 0, newdata, 0, size); + data = newdata; + } + data[size++] = readByte(); + } + readArrayE(); + byte[] newdata = new byte[size]; + System.arraycopy(data, 0, newdata, 0, size); + return newdata; + } else { + byte[] values = new byte[len]; + for (int i = 0; i < values.length; i++) { + values[i] = readByte(); + } + readArrayE(); + return values; + } + } + + @Override + public char readChar() { + return (char) ((0xff00 & (content[++this.position] << 8)) | (0xff & content[++this.position])); + } + + @Override + public short readShort() { + return (short) ((0xff00 & (content[++this.position] << 8)) | (0xff & content[++this.position])); + } + + @Override + public int readInt() { + return ((content[++this.position] & 0xff) << 24) | ((content[++this.position] & 0xff) << 16) + | ((content[++this.position] & 0xff) << 8) | (content[++this.position] & 0xff); + } + + @Override + public long readLong() { + return ((((long) content[++this.position] & 0xff) << 56) + | (((long) content[++this.position] & 0xff) << 48) + | (((long) content[++this.position] & 0xff) << 40) + | (((long) content[++this.position] & 0xff) << 32) + | (((long) content[++this.position] & 0xff) << 24) + | (((long) content[++this.position] & 0xff) << 16) + | (((long) content[++this.position] & 0xff) << 8) + | (((long) content[++this.position] & 0xff))); + } + + @Override + public final float readFloat() { + return Float.intBitsToFloat(readInt()); + } + + @Override + public final double readDouble() { + return Double.longBitsToDouble(readLong()); + } + + @Override + public final String readClassName() { + return readSmallString(); + } + + @Override + public String readSmallString() { + int len = 0xff & readByte(); + if (len == 0) return ""; + String value = new String(content, ++this.position, len); + this.position += len - 1; //涓婁竴琛屽凡缁++this.position锛屾墍浠ユ澶勮-1 + return value; + } + + @Override + public String readString() { + int len = readInt(); + if (len == SIGN_NULL) return null; + if (len == 0) return ""; + String value = new String(content, ++this.position, len, StandardCharsets.UTF_8); + this.position += len - 1;//涓婁竴琛屽凡缁++this.position锛屾墍浠ユ澶勮-1 + return value; + } + + @Override + public ValueType readType() { + throw new UnsupportedOperationException("Not supported yet."); + } + +} diff --git a/src/main/java/org/redkale/convert/bson/BsonSimpledCoder.java b/src/main/java/org/redkale/convert/bson/BsonSimpledCoder.java index 3f63b5a83..140e00c82 100644 --- a/src/main/java/org/redkale/convert/bson/BsonSimpledCoder.java +++ b/src/main/java/org/redkale/convert/bson/BsonSimpledCoder.java @@ -1,20 +1,20 @@ -/* - * 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.convert.bson; - -import org.redkale.convert.SimpledCoder; - -/** - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param 搴忓垪鍖/鍙嶈В鏋愮殑鏁版嵁绫诲瀷 - */ -public abstract class BsonSimpledCoder extends SimpledCoder { - -} +/* + * 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.convert.bson; + +import org.redkale.convert.SimpledCoder; + +/** + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param 搴忓垪鍖/鍙嶈В鏋愮殑鏁版嵁绫诲瀷 + */ +public abstract class BsonSimpledCoder extends SimpledCoder { + +} diff --git a/src/main/java/org/redkale/convert/bson/BsonStreamReader.java b/src/main/java/org/redkale/convert/bson/BsonStreamReader.java index 7a704b3af..b717e61a9 100644 --- a/src/main/java/org/redkale/convert/bson/BsonStreamReader.java +++ b/src/main/java/org/redkale/convert/bson/BsonStreamReader.java @@ -1,63 +1,63 @@ -/* - * 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.convert.bson; - -import java.io.*; -import org.redkale.convert.*; - -/** - * - * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -class BsonStreamReader extends BsonByteBufferReader { - - private InputStream in; - - private byte currByte; - - protected BsonStreamReader(InputStream in) { - super((ConvertMask) null); - this.in = in; - } - - @Override - protected boolean recycle() { - super.recycle(); // this.position 鍒濆鍖栧间负-1 - this.in = null; - this.currByte = 0; - return false; - } - - @Override - public byte readByte() { - try { - byte b = (currByte = (byte) in.read()); - this.position++; - return b; - } catch (IOException e) { - throw new ConvertException(e); - } - } - - @Override - protected byte currentByte() { - return currByte; - } - - @Override - protected byte[] read(final int len) { - byte[] bs = new byte[len]; - try { - in.read(bs); - this.position += len; - } catch (IOException e) { - throw new ConvertException(e); - } - return bs; - } -} +/* + * 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.convert.bson; + +import java.io.*; +import org.redkale.convert.*; + +/** + * + * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +class BsonStreamReader extends BsonByteBufferReader { + + private InputStream in; + + private byte currByte; + + protected BsonStreamReader(InputStream in) { + super((ConvertMask) null); + this.in = in; + } + + @Override + protected boolean recycle() { + super.recycle(); // this.position 鍒濆鍖栧间负-1 + this.in = null; + this.currByte = 0; + return false; + } + + @Override + public byte readByte() { + try { + byte b = (currByte = (byte) in.read()); + this.position++; + return b; + } catch (IOException e) { + throw new ConvertException(e); + } + } + + @Override + protected byte currentByte() { + return currByte; + } + + @Override + protected byte[] read(final int len) { + byte[] bs = new byte[len]; + try { + in.read(bs); + this.position += len; + } catch (IOException e) { + throw new ConvertException(e); + } + return bs; + } +} diff --git a/src/main/java/org/redkale/convert/bson/BsonStreamWriter.java b/src/main/java/org/redkale/convert/bson/BsonStreamWriter.java index e3ccf4547..35b828d13 100644 --- a/src/main/java/org/redkale/convert/bson/BsonStreamWriter.java +++ b/src/main/java/org/redkale/convert/bson/BsonStreamWriter.java @@ -1,50 +1,50 @@ -/* - * 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.convert.bson; - -import java.io.*; -import org.redkale.convert.*; - -/** - * - * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -class BsonStreamWriter extends BsonByteBufferWriter { - - private OutputStream out; - - protected BsonStreamWriter(boolean tiny, OutputStream out) { - super(tiny, null); - this.out = out; - } - - @Override - protected boolean recycle() { - super.recycle(); - this.out = null; - return false; - } - - @Override - public void writeTo(final byte[] chs, final int start, final int len) { - try { - out.write(chs, start, len); - } catch (IOException e) { - throw new ConvertException(e); - } - } - - @Override - public void writeTo(final byte ch) { - try { - out.write((byte) ch); - } catch (IOException e) { - throw new ConvertException(e); - } - } -} +/* + * 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.convert.bson; + +import java.io.*; +import org.redkale.convert.*; + +/** + * + * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +class BsonStreamWriter extends BsonByteBufferWriter { + + private OutputStream out; + + protected BsonStreamWriter(boolean tiny, OutputStream out) { + super(tiny, null); + this.out = out; + } + + @Override + protected boolean recycle() { + super.recycle(); + this.out = null; + return false; + } + + @Override + public void writeTo(final byte[] chs, final int start, final int len) { + try { + out.write(chs, start, len); + } catch (IOException e) { + throw new ConvertException(e); + } + } + + @Override + public void writeTo(final byte ch) { + try { + out.write((byte) ch); + } catch (IOException e) { + throw new ConvertException(e); + } + } +} diff --git a/src/main/java/org/redkale/convert/bson/BsonWriter.java b/src/main/java/org/redkale/convert/bson/BsonWriter.java index 77ae8f6ce..2b46c4f89 100644 --- a/src/main/java/org/redkale/convert/bson/BsonWriter.java +++ b/src/main/java/org/redkale/convert/bson/BsonWriter.java @@ -1,336 +1,336 @@ -/* - * 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.convert.bson; - -import java.lang.reflect.Type; -import java.nio.ByteBuffer; -import java.util.function.Consumer; -import org.redkale.convert.*; -import org.redkale.convert.ext.ByteSimpledCoder; -import org.redkale.util.*; - -/** - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public class BsonWriter extends Writer implements ByteTuple { - - private static final int defaultSize = Integer.getInteger("redkale.convert.bson.writer.buffer.defsize", Integer.getInteger("redkale.convert.writer.buffer.defsize", 1024)); - - private byte[] content; - - protected int count; - - protected boolean tiny; - - public static ObjectPool createPool(int max) { - return ObjectPool.createSafePool(max, (Object... params) -> new BsonWriter(), null, (t) -> t.recycle()); - } - - @Override - public byte[] content() { - return content; - } - - @Override - public int offset() { - return 0; - } - - @Override - public int length() { - return count; - } - - /** - * 鐩存帴鑾峰彇鍏ㄩ儴鏁版嵁, 瀹為檯鏁版嵁闇瑕佹牴鎹甤ount闀垮害鏉ユ埅鍙 - * - * @return byte[] - */ - public byte[] directBytes() { - return content; - } - - /** - * 灏嗘湰瀵硅薄鐨勫唴瀹瑰紩鐢ㄥ鍒剁粰array - * - * @param array ByteArray - */ - public void directTo(ByteArray array) { - array.directFrom(content, count); - } - - public void completed(ConvertBytesHandler handler, Consumer callback) { - handler.completed(content, 0, count, callback, this); - } - - public ByteArray toByteArray() { - return new ByteArray(this); - } - - public byte[] toArray() { - if (count == content.length) return content; - byte[] newdata = new byte[count]; - System.arraycopy(content, 0, newdata, 0, count); - return newdata; - } - - public ByteBuffer[] toBuffers() { - return new ByteBuffer[]{ByteBuffer.wrap(content, 0, count)}; - } - - protected BsonWriter(byte[] bs) { - this.content = bs == null ? new byte[0] : bs; - } - - public BsonWriter() { - this(defaultSize); - } - - public BsonWriter(int size) { - this.content = new byte[size > 128 ? size : 128]; - } - - public BsonWriter(ByteArray array) { - this.content = array.content(); - this.count = array.length(); - } - - @Override - public final boolean tiny() { - return tiny; - } - - public BsonWriter tiny(boolean tiny) { - this.tiny = tiny; - return this; - } - - //----------------------------------------------------------------------- - //----------------------------------------------------------------------- - /** - * 鎵╁厖鎸囧畾闀垮害鐨勭紦鍐插尯 - * - * @param len 鎵╁闀垮害 - * - * @return 鍥哄畾0 - */ - protected int expand(int len) { - int newcount = count + len; - if (newcount <= content.length) return 0; - byte[] newdata = new byte[Math.max(content.length * 3 / 2, newcount)]; - System.arraycopy(content, 0, newdata, 0, count); - this.content = newdata; - return 0; - } - - public void writeTo(final byte ch) { - expand(1); - content[count++] = ch; - } - - public final void writeTo(final byte... chs) { - writeTo(chs, 0, chs.length); - } - - public void writeTo(final byte[] chs, final int start, final int len) { - expand(len); - System.arraycopy(chs, start, content, count, len); - count += len; - } - - @Override - protected boolean recycle() { - super.recycle(); - this.count = 0; - this.specify = null; - if (this.content != null && this.content.length > defaultSize) { - this.content = new byte[defaultSize]; - } - return true; - } - - @Override - public String toString() { - return this.getClass().getSimpleName() + "[count=" + this.count + "]"; - } - - //------------------------------------------------------------------------ - public final int count() { - return this.count; - } - - @Override - public final void writeBoolean(boolean value) { - writeTo(value ? (byte) 1 : (byte) 0); - } - - @Override - public final void writeByte(byte value) { - writeTo(value); - } - - @Override - public final void writeByteArray(byte[] values) { - if (values == null) { - writeNull(); - return; - } - writeArrayB(values.length, null, null, values); - boolean flag = false; - for (byte v : values) { - if (flag) writeArrayMark(); - writeByte(v); - flag = true; - } - writeArrayE(); - } - - @Override - public final void writeChar(final char value) { - writeTo((byte) ((value & 0xFF00) >> 8), (byte) (value & 0xFF)); - } - - @Override - public final void writeShort(short value) { - writeTo((byte) (value >> 8), (byte) value); - } - - @Override - public final void writeInt(int value) { - writeTo((byte) (value >> 24), (byte) (value >> 16), (byte) (value >> 8), (byte) value); - } - - @Override - public final void writeLong(long value) { - writeTo((byte) (value >> 56), (byte) (value >> 48), (byte) (value >> 40), (byte) (value >> 32), - (byte) (value >> 24), (byte) (value >> 16), (byte) (value >> 8), (byte) value); - } - - @Override - public final void writeFloat(float value) { - writeInt(Float.floatToIntBits(value)); - } - - @Override - public final void writeDouble(double value) { - writeLong(Double.doubleToLongBits(value)); - } - - @Override - public final boolean needWriteClassName() { - return true; - } - - @Override - public final void writeClassName(String clazz) { - writeSmallString(clazz == null ? "" : clazz); - } - - @Override - public final int writeObjectB(Object obj) { - super.writeObjectB(obj); - writeSmallString(""); - writeShort(BsonReader.SIGN_OBJECTB); - return -1; - } - - @Override - public final void writeObjectE(Object obj) { - writeByte(BsonReader.SIGN_NONEXT); - writeShort(BsonReader.SIGN_OBJECTE); - } - - @Override - public final void writeFieldName(EnMember member, String fieldName, Type fieldType, int fieldPos) { - writeByte(BsonReader.SIGN_HASNEXT); - writeSmallString(fieldName); - writeByte(BsonFactory.typeEnum(fieldType)); - } - - /** - * 瀵逛簬绫荤殑瀛楁鍚嶃佹灇涓惧艰繖浜涢暱搴︿竴鑸笉瓒呰繃255涓斾笉浼氬嚭鐜板弻瀛楄妭瀛楃鐨勫瓧绗︿覆閲囩敤writeSmallString澶勭悊, readSmallString鐢ㄤ簬璇诲彇 - * - * @param value String鍊 - */ - @Override - public final void writeSmallString(String value) { - if (value.isEmpty()) { - writeTo((byte) 0); - return; - } - char[] chars = Utility.charArray(value); - if (chars.length > 255) throw new ConvertException("'" + value + "' have very long length"); - byte[] bytes = new byte[chars.length + 1]; - bytes[0] = (byte) chars.length; - for (int i = 0; i < chars.length; i++) { - if (chars[i] > Byte.MAX_VALUE) throw new ConvertException("'" + value + "' have double-word"); - bytes[i + 1] = (byte) chars[i]; - } - writeTo(bytes); - } - - @Override - public final void writeString(String value) { - if (value == null) { - writeInt(Reader.SIGN_NULL); - return; - } else if (value.isEmpty()) { - writeInt(0); - return; - } - byte[] bytes = Utility.encodeUTF8(value); - writeInt(bytes.length); - writeTo(bytes); - } - - @Override - public final void writeWrapper(StringWrapper value) { - this.writeString(value == null ? null : value.getValue()); - } - - @Override - public final void writeNull() { - writeShort(Reader.SIGN_NULL); - } - - @Override - public final int writeArrayB(int size, Encodeable arrayEncoder, Encodeable componentEncoder, Object obj) { - writeInt(size); - if (componentEncoder != null && componentEncoder != ByteSimpledCoder.instance) { - writeByte(BsonFactory.typeEnum(componentEncoder.getType())); - } - return -1; - } - - @Override - public final void writeArrayMark() { - } - - @Override - public final void writeArrayE() { - } - - @Override - public int writeMapB(int size, Encodeable keyEncoder, Encodeable valueEncoder, Object obj) { - writeInt(size); - writeByte(BsonFactory.typeEnum(keyEncoder.getType())); - writeByte(BsonFactory.typeEnum(valueEncoder.getType())); - return -1; - } - - @Override - public final void writeMapMark() { - } - - @Override - public final void writeMapE() { - } - -} +/* + * 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.convert.bson; + +import java.lang.reflect.Type; +import java.nio.ByteBuffer; +import java.util.function.Consumer; +import org.redkale.convert.*; +import org.redkale.convert.ext.ByteSimpledCoder; +import org.redkale.util.*; + +/** + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public class BsonWriter extends Writer implements ByteTuple { + + private static final int defaultSize = Integer.getInteger("redkale.convert.bson.writer.buffer.defsize", Integer.getInteger("redkale.convert.writer.buffer.defsize", 1024)); + + private byte[] content; + + protected int count; + + protected boolean tiny; + + public static ObjectPool createPool(int max) { + return ObjectPool.createSafePool(max, (Object... params) -> new BsonWriter(), null, (t) -> t.recycle()); + } + + @Override + public byte[] content() { + return content; + } + + @Override + public int offset() { + return 0; + } + + @Override + public int length() { + return count; + } + + /** + * 鐩存帴鑾峰彇鍏ㄩ儴鏁版嵁, 瀹為檯鏁版嵁闇瑕佹牴鎹甤ount闀垮害鏉ユ埅鍙 + * + * @return byte[] + */ + public byte[] directBytes() { + return content; + } + + /** + * 灏嗘湰瀵硅薄鐨勫唴瀹瑰紩鐢ㄥ鍒剁粰array + * + * @param array ByteArray + */ + public void directTo(ByteArray array) { + array.directFrom(content, count); + } + + public void completed(ConvertBytesHandler handler, Consumer callback) { + handler.completed(content, 0, count, callback, this); + } + + public ByteArray toByteArray() { + return new ByteArray(this); + } + + public byte[] toArray() { + if (count == content.length) return content; + byte[] newdata = new byte[count]; + System.arraycopy(content, 0, newdata, 0, count); + return newdata; + } + + public ByteBuffer[] toBuffers() { + return new ByteBuffer[]{ByteBuffer.wrap(content, 0, count)}; + } + + protected BsonWriter(byte[] bs) { + this.content = bs == null ? new byte[0] : bs; + } + + public BsonWriter() { + this(defaultSize); + } + + public BsonWriter(int size) { + this.content = new byte[size > 128 ? size : 128]; + } + + public BsonWriter(ByteArray array) { + this.content = array.content(); + this.count = array.length(); + } + + @Override + public final boolean tiny() { + return tiny; + } + + public BsonWriter tiny(boolean tiny) { + this.tiny = tiny; + return this; + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + /** + * 鎵╁厖鎸囧畾闀垮害鐨勭紦鍐插尯 + * + * @param len 鎵╁闀垮害 + * + * @return 鍥哄畾0 + */ + protected int expand(int len) { + int newcount = count + len; + if (newcount <= content.length) return 0; + byte[] newdata = new byte[Math.max(content.length * 3 / 2, newcount)]; + System.arraycopy(content, 0, newdata, 0, count); + this.content = newdata; + return 0; + } + + public void writeTo(final byte ch) { + expand(1); + content[count++] = ch; + } + + public final void writeTo(final byte... chs) { + writeTo(chs, 0, chs.length); + } + + public void writeTo(final byte[] chs, final int start, final int len) { + expand(len); + System.arraycopy(chs, start, content, count, len); + count += len; + } + + @Override + protected boolean recycle() { + super.recycle(); + this.count = 0; + this.specify = null; + if (this.content != null && this.content.length > defaultSize) { + this.content = new byte[defaultSize]; + } + return true; + } + + @Override + public String toString() { + return this.getClass().getSimpleName() + "[count=" + this.count + "]"; + } + + //------------------------------------------------------------------------ + public final int count() { + return this.count; + } + + @Override + public final void writeBoolean(boolean value) { + writeTo(value ? (byte) 1 : (byte) 0); + } + + @Override + public final void writeByte(byte value) { + writeTo(value); + } + + @Override + public final void writeByteArray(byte[] values) { + if (values == null) { + writeNull(); + return; + } + writeArrayB(values.length, null, null, values); + boolean flag = false; + for (byte v : values) { + if (flag) writeArrayMark(); + writeByte(v); + flag = true; + } + writeArrayE(); + } + + @Override + public final void writeChar(final char value) { + writeTo((byte) ((value & 0xFF00) >> 8), (byte) (value & 0xFF)); + } + + @Override + public final void writeShort(short value) { + writeTo((byte) (value >> 8), (byte) value); + } + + @Override + public final void writeInt(int value) { + writeTo((byte) (value >> 24), (byte) (value >> 16), (byte) (value >> 8), (byte) value); + } + + @Override + public final void writeLong(long value) { + writeTo((byte) (value >> 56), (byte) (value >> 48), (byte) (value >> 40), (byte) (value >> 32), + (byte) (value >> 24), (byte) (value >> 16), (byte) (value >> 8), (byte) value); + } + + @Override + public final void writeFloat(float value) { + writeInt(Float.floatToIntBits(value)); + } + + @Override + public final void writeDouble(double value) { + writeLong(Double.doubleToLongBits(value)); + } + + @Override + public final boolean needWriteClassName() { + return true; + } + + @Override + public final void writeClassName(String clazz) { + writeSmallString(clazz == null ? "" : clazz); + } + + @Override + public final int writeObjectB(Object obj) { + super.writeObjectB(obj); + writeSmallString(""); + writeShort(BsonReader.SIGN_OBJECTB); + return -1; + } + + @Override + public final void writeObjectE(Object obj) { + writeByte(BsonReader.SIGN_NONEXT); + writeShort(BsonReader.SIGN_OBJECTE); + } + + @Override + public final void writeFieldName(EnMember member, String fieldName, Type fieldType, int fieldPos) { + writeByte(BsonReader.SIGN_HASNEXT); + writeSmallString(fieldName); + writeByte(BsonFactory.typeEnum(fieldType)); + } + + /** + * 瀵逛簬绫荤殑瀛楁鍚嶃佹灇涓惧艰繖浜涢暱搴︿竴鑸笉瓒呰繃255涓斾笉浼氬嚭鐜板弻瀛楄妭瀛楃鐨勫瓧绗︿覆閲囩敤writeSmallString澶勭悊, readSmallString鐢ㄤ簬璇诲彇 + * + * @param value String鍊 + */ + @Override + public final void writeSmallString(String value) { + if (value.isEmpty()) { + writeTo((byte) 0); + return; + } + char[] chars = Utility.charArray(value); + if (chars.length > 255) throw new ConvertException("'" + value + "' have very long length"); + byte[] bytes = new byte[chars.length + 1]; + bytes[0] = (byte) chars.length; + for (int i = 0; i < chars.length; i++) { + if (chars[i] > Byte.MAX_VALUE) throw new ConvertException("'" + value + "' have double-word"); + bytes[i + 1] = (byte) chars[i]; + } + writeTo(bytes); + } + + @Override + public final void writeString(String value) { + if (value == null) { + writeInt(Reader.SIGN_NULL); + return; + } else if (value.isEmpty()) { + writeInt(0); + return; + } + byte[] bytes = Utility.encodeUTF8(value); + writeInt(bytes.length); + writeTo(bytes); + } + + @Override + public final void writeWrapper(StringWrapper value) { + this.writeString(value == null ? null : value.getValue()); + } + + @Override + public final void writeNull() { + writeShort(Reader.SIGN_NULL); + } + + @Override + public final int writeArrayB(int size, Encodeable arrayEncoder, Encodeable componentEncoder, Object obj) { + writeInt(size); + if (componentEncoder != null && componentEncoder != ByteSimpledCoder.instance) { + writeByte(BsonFactory.typeEnum(componentEncoder.getType())); + } + return -1; + } + + @Override + public final void writeArrayMark() { + } + + @Override + public final void writeArrayE() { + } + + @Override + public int writeMapB(int size, Encodeable keyEncoder, Encodeable valueEncoder, Object obj) { + writeInt(size); + writeByte(BsonFactory.typeEnum(keyEncoder.getType())); + writeByte(BsonFactory.typeEnum(valueEncoder.getType())); + return -1; + } + + @Override + public final void writeMapMark() { + } + + @Override + public final void writeMapE() { + } + +} diff --git a/src/main/java/org/redkale/convert/bson/SkipArrayDecoder.java b/src/main/java/org/redkale/convert/bson/SkipArrayDecoder.java index 1c65babaf..5efe46d80 100644 --- a/src/main/java/org/redkale/convert/bson/SkipArrayDecoder.java +++ b/src/main/java/org/redkale/convert/bson/SkipArrayDecoder.java @@ -1,33 +1,33 @@ -/* - * 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.convert.bson; - -import java.lang.reflect.Type; -import org.redkale.convert.*; - -/** - * 鏁扮粍鐨勫弽搴忓垪鍖栨搷浣滅被
- * 瀵硅薄鏁扮粍鐨勫弽搴忓垪鍖栵紝涓嶅寘鍚玦nt[]銆乴ong[]杩欐牱鐨刾rimitive class鏁扮粍銆
- * 鏀寔涓瀹氱▼搴︾殑娉涘瀷銆
- * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param 鍙嶈В鏋愮殑鏁扮粍鍏冪礌绫诲瀷 - */ -public class SkipArrayDecoder extends ArrayDecoder { - - public SkipArrayDecoder(final ConvertFactory factory, final Type type) { - super(factory, type); - } - - @Override - protected Decodeable getComponentDecoder(Decodeable decoder, byte[] typevals) { - if (typevals != null) return BsonFactory.typeEnum(typevals[0]); - return decoder; - } -} +/* + * 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.convert.bson; + +import java.lang.reflect.Type; +import org.redkale.convert.*; + +/** + * 鏁扮粍鐨勫弽搴忓垪鍖栨搷浣滅被
+ * 瀵硅薄鏁扮粍鐨勫弽搴忓垪鍖栵紝涓嶅寘鍚玦nt[]銆乴ong[]杩欐牱鐨刾rimitive class鏁扮粍銆
+ * 鏀寔涓瀹氱▼搴︾殑娉涘瀷銆
+ * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param 鍙嶈В鏋愮殑鏁扮粍鍏冪礌绫诲瀷 + */ +public class SkipArrayDecoder extends ArrayDecoder { + + public SkipArrayDecoder(final ConvertFactory factory, final Type type) { + super(factory, type); + } + + @Override + protected Decodeable getComponentDecoder(Decodeable decoder, byte[] typevals) { + if (typevals != null) return BsonFactory.typeEnum(typevals[0]); + return decoder; + } +} diff --git a/src/main/java/org/redkale/convert/bson/SkipCollectionDecoder.java b/src/main/java/org/redkale/convert/bson/SkipCollectionDecoder.java index c16a562ff..0b74fe110 100644 --- a/src/main/java/org/redkale/convert/bson/SkipCollectionDecoder.java +++ b/src/main/java/org/redkale/convert/bson/SkipCollectionDecoder.java @@ -1,32 +1,32 @@ -/* - * 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.convert.bson; - -import java.lang.reflect.Type; -import org.redkale.convert.*; - -/** - * Collection鐨勫弽搴忓垪鍖栨搷浣滅被
- * 鏀寔涓瀹氱▼搴︾殑娉涘瀷銆
- * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param 鍙嶈В鏋愮殑闆嗗悎鍏冪礌绫诲瀷 - */ -public class SkipCollectionDecoder extends CollectionDecoder { - - public SkipCollectionDecoder(final ConvertFactory factory, final Type type) { - super(factory, type); - } - - @Override - protected Decodeable getComponentDecoder(Decodeable decoder, byte[] typevals) { - if (typevals != null) return BsonFactory.typeEnum(typevals[0]); - return decoder; - } -} +/* + * 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.convert.bson; + +import java.lang.reflect.Type; +import org.redkale.convert.*; + +/** + * Collection鐨勫弽搴忓垪鍖栨搷浣滅被
+ * 鏀寔涓瀹氱▼搴︾殑娉涘瀷銆
+ * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param 鍙嶈В鏋愮殑闆嗗悎鍏冪礌绫诲瀷 + */ +public class SkipCollectionDecoder extends CollectionDecoder { + + public SkipCollectionDecoder(final ConvertFactory factory, final Type type) { + super(factory, type); + } + + @Override + protected Decodeable getComponentDecoder(Decodeable decoder, byte[] typevals) { + if (typevals != null) return BsonFactory.typeEnum(typevals[0]); + return decoder; + } +} diff --git a/src/main/java/org/redkale/convert/bson/SkipMapDecoder.java b/src/main/java/org/redkale/convert/bson/SkipMapDecoder.java index e92225d1c..a0b352849 100644 --- a/src/main/java/org/redkale/convert/bson/SkipMapDecoder.java +++ b/src/main/java/org/redkale/convert/bson/SkipMapDecoder.java @@ -1,38 +1,38 @@ -/* - * 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.convert.bson; - -import java.lang.reflect.Type; -import org.redkale.convert.*; - -/** - * Map鐨勫弽搴忓垪鍖栨搷浣滅被
- * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Map key鐨勬暟鎹被鍨 - * @param Map value鐨勬暟鎹被鍨 - */ -public class SkipMapDecoder extends MapDecoder { - - public SkipMapDecoder(final ConvertFactory factory, final Type type) { - super(factory, type); - } - - @Override - protected Decodeable getKeyDecoder(Decodeable decoder, byte[] typevals) { - if (typevals != null) return BsonFactory.typeEnum(typevals[0]); - return decoder; - } - - @Override - protected Decodeable getValueDecoder(Decodeable decoder, byte[] typevals) { - if (typevals != null) return BsonFactory.typeEnum(typevals[1]); - return decoder; - } -} +/* + * 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.convert.bson; + +import java.lang.reflect.Type; +import org.redkale.convert.*; + +/** + * Map鐨勫弽搴忓垪鍖栨搷浣滅被
+ * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Map key鐨勬暟鎹被鍨 + * @param Map value鐨勬暟鎹被鍨 + */ +public class SkipMapDecoder extends MapDecoder { + + public SkipMapDecoder(final ConvertFactory factory, final Type type) { + super(factory, type); + } + + @Override + protected Decodeable getKeyDecoder(Decodeable decoder, byte[] typevals) { + if (typevals != null) return BsonFactory.typeEnum(typevals[0]); + return decoder; + } + + @Override + protected Decodeable getValueDecoder(Decodeable decoder, byte[] typevals) { + if (typevals != null) return BsonFactory.typeEnum(typevals[1]); + return decoder; + } +} diff --git a/src/main/java/org/redkale/convert/bson/SkipStreamDecoder.java b/src/main/java/org/redkale/convert/bson/SkipStreamDecoder.java index 08eb62d21..8a42ace7f 100644 --- a/src/main/java/org/redkale/convert/bson/SkipStreamDecoder.java +++ b/src/main/java/org/redkale/convert/bson/SkipStreamDecoder.java @@ -1,32 +1,32 @@ -/* - * 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.convert.bson; - -import java.lang.reflect.Type; -import org.redkale.convert.*; - -/** - * Stream鐨勫弽搴忓垪鍖栨搷浣滅被
- * 鏀寔涓瀹氱▼搴︾殑娉涘瀷銆
- * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param 鍙嶈В鏋愮殑闆嗗悎鍏冪礌绫诲瀷 - */ -public class SkipStreamDecoder extends StreamDecoder { - - public SkipStreamDecoder(final ConvertFactory factory, final Type type) { - super(factory, type); - } - - @Override - protected Decodeable getComponentDecoder(Decodeable decoder, byte[] typevals) { - if (typevals != null) return BsonFactory.typeEnum(typevals[0]); - return decoder; - } -} +/* + * 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.convert.bson; + +import java.lang.reflect.Type; +import org.redkale.convert.*; + +/** + * Stream鐨勫弽搴忓垪鍖栨搷浣滅被
+ * 鏀寔涓瀹氱▼搴︾殑娉涘瀷銆
+ * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param 鍙嶈В鏋愮殑闆嗗悎鍏冪礌绫诲瀷 + */ +public class SkipStreamDecoder extends StreamDecoder { + + public SkipStreamDecoder(final ConvertFactory factory, final Type type) { + super(factory, type); + } + + @Override + protected Decodeable getComponentDecoder(Decodeable decoder, byte[] typevals) { + if (typevals != null) return BsonFactory.typeEnum(typevals[0]); + return decoder; + } +} diff --git a/src/main/java/org/redkale/convert/bson/package-info.java b/src/main/java/org/redkale/convert/bson/package-info.java index fa92a2f44..6518406c1 100644 --- a/src/main/java/org/redkale/convert/bson/package-info.java +++ b/src/main/java/org/redkale/convert/bson/package-info.java @@ -1,4 +1,4 @@ -/** - * 鎻愪緵BSON鐨勫簭鍒楀寲鍜屽弽瑙f瀽鍔熻兘 - */ -package org.redkale.convert.bson; +/** + * 鎻愪緵BSON鐨勫簭鍒楀寲鍜屽弽瑙f瀽鍔熻兘 + */ +package org.redkale.convert.bson; diff --git a/src/main/java/org/redkale/convert/ext/AtomicIntegerSimpledCoder.java b/src/main/java/org/redkale/convert/ext/AtomicIntegerSimpledCoder.java index 2445b41dc..29b879e6e 100644 --- a/src/main/java/org/redkale/convert/ext/AtomicIntegerSimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/AtomicIntegerSimpledCoder.java @@ -1,35 +1,35 @@ -/* - * 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.convert.ext; - -import java.util.concurrent.atomic.AtomicInteger; -import org.redkale.convert.*; - -/** - * AtomicInteger 鐨凷impledCoder瀹炵幇 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Reader杈撳叆鐨勫瓙绫诲瀷 - * @param Writer杈撳嚭鐨勫瓙绫诲瀷 - */ -public class AtomicIntegerSimpledCoder extends SimpledCoder { - - public static final AtomicIntegerSimpledCoder instance = new AtomicIntegerSimpledCoder(); - - @Override - public void convertTo(W out, AtomicInteger value) { - out.writeInt(value == null ? 0 : value.get()); - } - - @Override - public AtomicInteger convertFrom(R in) { - return new AtomicInteger(in.readInt()); - } - -} +/* + * 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.convert.ext; + +import java.util.concurrent.atomic.AtomicInteger; +import org.redkale.convert.*; + +/** + * AtomicInteger 鐨凷impledCoder瀹炵幇 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * @param Writer杈撳嚭鐨勫瓙绫诲瀷 + */ +public class AtomicIntegerSimpledCoder extends SimpledCoder { + + public static final AtomicIntegerSimpledCoder instance = new AtomicIntegerSimpledCoder(); + + @Override + public void convertTo(W out, AtomicInteger value) { + out.writeInt(value == null ? 0 : value.get()); + } + + @Override + public AtomicInteger convertFrom(R in) { + return new AtomicInteger(in.readInt()); + } + +} diff --git a/src/main/java/org/redkale/convert/ext/AtomicLongSimpledCoder.java b/src/main/java/org/redkale/convert/ext/AtomicLongSimpledCoder.java index 503cdfea0..914b81262 100644 --- a/src/main/java/org/redkale/convert/ext/AtomicLongSimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/AtomicLongSimpledCoder.java @@ -1,35 +1,35 @@ -/* - * 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.convert.ext; - -import java.util.concurrent.atomic.AtomicLong; -import org.redkale.convert.*; - -/** - * AtomicLong 鐨凷impledCoder瀹炵幇 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Reader杈撳叆鐨勫瓙绫诲瀷 - * @param Writer杈撳嚭鐨勫瓙绫诲瀷 - */ -public final class AtomicLongSimpledCoder extends SimpledCoder { - - public static final AtomicLongSimpledCoder instance = new AtomicLongSimpledCoder(); - - @Override - public void convertTo(W out, AtomicLong value) { - out.writeLong(value == null ? 0 : value.get()); - } - - @Override - public AtomicLong convertFrom(R in) { - return new AtomicLong(in.readLong()); - } - -} +/* + * 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.convert.ext; + +import java.util.concurrent.atomic.AtomicLong; +import org.redkale.convert.*; + +/** + * AtomicLong 鐨凷impledCoder瀹炵幇 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * @param Writer杈撳嚭鐨勫瓙绫诲瀷 + */ +public final class AtomicLongSimpledCoder extends SimpledCoder { + + public static final AtomicLongSimpledCoder instance = new AtomicLongSimpledCoder(); + + @Override + public void convertTo(W out, AtomicLong value) { + out.writeLong(value == null ? 0 : value.get()); + } + + @Override + public AtomicLong convertFrom(R in) { + return new AtomicLong(in.readLong()); + } + +} diff --git a/src/main/java/org/redkale/convert/ext/BigDecimalSimpledCoder.java b/src/main/java/org/redkale/convert/ext/BigDecimalSimpledCoder.java index 32b6aaaf8..07aa95aa7 100644 --- a/src/main/java/org/redkale/convert/ext/BigDecimalSimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/BigDecimalSimpledCoder.java @@ -1,44 +1,44 @@ -/* - * 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.convert.ext; - -import org.redkale.convert.SimpledCoder; -import org.redkale.convert.Writer; -import org.redkale.convert.Reader; -import java.math.BigDecimal; -import org.redkale.util.Utility; - -/** - * BigDecimal 鐨凷impledCoder瀹炵幇 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Reader杈撳叆鐨勫瓙绫诲瀷 - * @param Writer杈撳嚭鐨勫瓙绫诲瀷 - */ -public final class BigDecimalSimpledCoder extends SimpledCoder { - - public static final BigDecimalSimpledCoder instance = new BigDecimalSimpledCoder(); - - @Override - public void convertTo(W out, BigDecimal value) { - if (value == null) { - out.writeNull(); - return; - } - out.writeSmallString(value.toString()); - } - - @Override - public BigDecimal convertFrom(R in) { - String value = in.readSmallString(); - if (value == null) return null; - return new BigDecimal(Utility.charArray(value)); - } - -} +/* + * 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.convert.ext; + +import org.redkale.convert.SimpledCoder; +import org.redkale.convert.Writer; +import org.redkale.convert.Reader; +import java.math.BigDecimal; +import org.redkale.util.Utility; + +/** + * BigDecimal 鐨凷impledCoder瀹炵幇 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * @param Writer杈撳嚭鐨勫瓙绫诲瀷 + */ +public final class BigDecimalSimpledCoder extends SimpledCoder { + + public static final BigDecimalSimpledCoder instance = new BigDecimalSimpledCoder(); + + @Override + public void convertTo(W out, BigDecimal value) { + if (value == null) { + out.writeNull(); + return; + } + out.writeSmallString(value.toString()); + } + + @Override + public BigDecimal convertFrom(R in) { + String value = in.readSmallString(); + if (value == null) return null; + return new BigDecimal(Utility.charArray(value)); + } + +} diff --git a/src/main/java/org/redkale/convert/ext/BigIntegerSimpledCoder.java b/src/main/java/org/redkale/convert/ext/BigIntegerSimpledCoder.java index 7795e3f74..a6ea50d1e 100644 --- a/src/main/java/org/redkale/convert/ext/BigIntegerSimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/BigIntegerSimpledCoder.java @@ -1,70 +1,70 @@ -/* - * 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.convert.ext; - -import org.redkale.convert.SimpledCoder; -import org.redkale.convert.Writer; -import org.redkale.convert.Reader; -import java.math.BigInteger; - -/** - * BigInteger 鐨凷impledCoder瀹炵幇 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Reader杈撳叆鐨勫瓙绫诲瀷 - * @param Writer杈撳嚭鐨勫瓙绫诲瀷 - */ -public final class BigIntegerSimpledCoder extends SimpledCoder { - - public static final BigIntegerSimpledCoder instance = new BigIntegerSimpledCoder(); - - @Override - @SuppressWarnings("unchecked") - public void convertTo(W out, BigInteger value) { - if (value == null) { - out.writeNull(); - return; - } - ByteArraySimpledCoder.instance.convertTo(out, value.toByteArray()); - } - - @Override - @SuppressWarnings("unchecked") - public BigInteger convertFrom(R in) { - byte[] bytes = ByteArraySimpledCoder.instance.convertFrom(in); - return bytes == null ? null : new BigInteger(bytes); - } - - /** - * BigInteger 鐨凧sonSimpledCoder瀹炵幇 - * - * @param Reader杈撳叆鐨勫瓙绫诲瀷 - * @param Writer杈撳嚭鐨勫瓙绫诲瀷 - */ - public static class BigIntegerJsonSimpledCoder extends SimpledCoder { - - public static final BigIntegerJsonSimpledCoder instance = new BigIntegerJsonSimpledCoder(); - - @Override - public void convertTo(final Writer out, final BigInteger value) { - if (value == null) { - out.writeNull(); - } else { - out.writeString(value.toString()); - } - } - - @Override - public BigInteger convertFrom(Reader in) { - final String str = in.readString(); - if (str == null) return null; - return new BigInteger(str); - } - } -} +/* + * 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.convert.ext; + +import org.redkale.convert.SimpledCoder; +import org.redkale.convert.Writer; +import org.redkale.convert.Reader; +import java.math.BigInteger; + +/** + * BigInteger 鐨凷impledCoder瀹炵幇 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * @param Writer杈撳嚭鐨勫瓙绫诲瀷 + */ +public final class BigIntegerSimpledCoder extends SimpledCoder { + + public static final BigIntegerSimpledCoder instance = new BigIntegerSimpledCoder(); + + @Override + @SuppressWarnings("unchecked") + public void convertTo(W out, BigInteger value) { + if (value == null) { + out.writeNull(); + return; + } + ByteArraySimpledCoder.instance.convertTo(out, value.toByteArray()); + } + + @Override + @SuppressWarnings("unchecked") + public BigInteger convertFrom(R in) { + byte[] bytes = ByteArraySimpledCoder.instance.convertFrom(in); + return bytes == null ? null : new BigInteger(bytes); + } + + /** + * BigInteger 鐨凧sonSimpledCoder瀹炵幇 + * + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * @param Writer杈撳嚭鐨勫瓙绫诲瀷 + */ + public static class BigIntegerJsonSimpledCoder extends SimpledCoder { + + public static final BigIntegerJsonSimpledCoder instance = new BigIntegerJsonSimpledCoder(); + + @Override + public void convertTo(final Writer out, final BigInteger value) { + if (value == null) { + out.writeNull(); + } else { + out.writeString(value.toString()); + } + } + + @Override + public BigInteger convertFrom(Reader in) { + final String str = in.readString(); + if (str == null) return null; + return new BigInteger(str); + } + } +} diff --git a/src/main/java/org/redkale/convert/ext/BoolArraySimpledCoder.java b/src/main/java/org/redkale/convert/ext/BoolArraySimpledCoder.java index 856acc260..bf0ad401d 100644 --- a/src/main/java/org/redkale/convert/ext/BoolArraySimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/BoolArraySimpledCoder.java @@ -1,78 +1,78 @@ -/* - * 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.convert.ext; - -import org.redkale.convert.Reader; -import org.redkale.convert.SimpledCoder; -import org.redkale.convert.Writer; - -/** - * boolean[] 鐨凷impledCoder瀹炵幇 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Reader杈撳叆鐨勫瓙绫诲瀷 - * @param Writer杈撳嚭鐨勫瓙绫诲瀷 - */ -public final class BoolArraySimpledCoder extends SimpledCoder { - - public static final BoolArraySimpledCoder instance = new BoolArraySimpledCoder(); - - @Override - public void convertTo(W out, boolean[] values) { - if (values == null) { - out.writeNull(); - return; - } - if (out.writeArrayB(values.length, this, BoolSimpledCoder.instance, values) < 0) { - boolean flag = false; - for (boolean v : values) { - if (flag) out.writeArrayMark(); - out.writeBoolean(v); - flag = true; - } - } - out.writeArrayE(); - } - - @Override - public boolean[] convertFrom(R in) { - int len = in.readArrayB(null, null, BoolSimpledCoder.instance); - int contentLength = -1; - if (len == Reader.SIGN_NULL) return null; - if (len == Reader.SIGN_NOLENBUTBYTES) { - contentLength = in.readMemberContentLength(null, BoolSimpledCoder.instance); - len = Reader.SIGN_NOLENGTH; - } - if (len == Reader.SIGN_NOLENGTH) { - int size = 0; - boolean[] data = new boolean[8]; - int startPosition = in.position(); - while (in.hasNext(startPosition, contentLength)) { - if (size >= data.length) { - boolean[] newdata = new boolean[data.length + 4]; - System.arraycopy(data, 0, newdata, 0, size); - data = newdata; - } - data[size++] = in.readBoolean(); - } - in.readArrayE(); - boolean[] newdata = new boolean[size]; - System.arraycopy(data, 0, newdata, 0, size); - return newdata; - } else { - boolean[] values = new boolean[len]; - for (int i = 0; i < values.length; i++) { - values[i] = in.readBoolean(); - } - in.readArrayE(); - return values; - } - } - -} +/* + * 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.convert.ext; + +import org.redkale.convert.Reader; +import org.redkale.convert.SimpledCoder; +import org.redkale.convert.Writer; + +/** + * boolean[] 鐨凷impledCoder瀹炵幇 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * @param Writer杈撳嚭鐨勫瓙绫诲瀷 + */ +public final class BoolArraySimpledCoder extends SimpledCoder { + + public static final BoolArraySimpledCoder instance = new BoolArraySimpledCoder(); + + @Override + public void convertTo(W out, boolean[] values) { + if (values == null) { + out.writeNull(); + return; + } + if (out.writeArrayB(values.length, this, BoolSimpledCoder.instance, values) < 0) { + boolean flag = false; + for (boolean v : values) { + if (flag) out.writeArrayMark(); + out.writeBoolean(v); + flag = true; + } + } + out.writeArrayE(); + } + + @Override + public boolean[] convertFrom(R in) { + int len = in.readArrayB(null, null, BoolSimpledCoder.instance); + int contentLength = -1; + if (len == Reader.SIGN_NULL) return null; + if (len == Reader.SIGN_NOLENBUTBYTES) { + contentLength = in.readMemberContentLength(null, BoolSimpledCoder.instance); + len = Reader.SIGN_NOLENGTH; + } + if (len == Reader.SIGN_NOLENGTH) { + int size = 0; + boolean[] data = new boolean[8]; + int startPosition = in.position(); + while (in.hasNext(startPosition, contentLength)) { + if (size >= data.length) { + boolean[] newdata = new boolean[data.length + 4]; + System.arraycopy(data, 0, newdata, 0, size); + data = newdata; + } + data[size++] = in.readBoolean(); + } + in.readArrayE(); + boolean[] newdata = new boolean[size]; + System.arraycopy(data, 0, newdata, 0, size); + return newdata; + } else { + boolean[] values = new boolean[len]; + for (int i = 0; i < values.length; i++) { + values[i] = in.readBoolean(); + } + in.readArrayE(); + return values; + } + } + +} diff --git a/src/main/java/org/redkale/convert/ext/BoolSimpledCoder.java b/src/main/java/org/redkale/convert/ext/BoolSimpledCoder.java index a675fffa0..fe61d083f 100644 --- a/src/main/java/org/redkale/convert/ext/BoolSimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/BoolSimpledCoder.java @@ -1,36 +1,36 @@ -/* - * 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.convert.ext; - -import org.redkale.convert.Reader; -import org.redkale.convert.SimpledCoder; -import org.redkale.convert.Writer; - -/** - * boolean 鐨凷impledCoder瀹炵幇 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Reader杈撳叆鐨勫瓙绫诲瀷 - * @param Writer杈撳嚭鐨勫瓙绫诲瀷 - */ -public final class BoolSimpledCoder extends SimpledCoder { - - public static final BoolSimpledCoder instance = new BoolSimpledCoder(); - - @Override - public void convertTo(W out, Boolean value) { - out.writeBoolean(value); - } - - @Override - public Boolean convertFrom(R in) { - return in.readBoolean(); - } - -} +/* + * 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.convert.ext; + +import org.redkale.convert.Reader; +import org.redkale.convert.SimpledCoder; +import org.redkale.convert.Writer; + +/** + * boolean 鐨凷impledCoder瀹炵幇 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * @param Writer杈撳嚭鐨勫瓙绫诲瀷 + */ +public final class BoolSimpledCoder extends SimpledCoder { + + public static final BoolSimpledCoder instance = new BoolSimpledCoder(); + + @Override + public void convertTo(W out, Boolean value) { + out.writeBoolean(value); + } + + @Override + public Boolean convertFrom(R in) { + return in.readBoolean(); + } + +} diff --git a/src/main/java/org/redkale/convert/ext/ByteArraySimpledCoder.java b/src/main/java/org/redkale/convert/ext/ByteArraySimpledCoder.java index ddcfa9046..088c0d273 100644 --- a/src/main/java/org/redkale/convert/ext/ByteArraySimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/ByteArraySimpledCoder.java @@ -1,36 +1,36 @@ -/* - * 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.convert.ext; - -import org.redkale.convert.Reader; -import org.redkale.convert.SimpledCoder; -import org.redkale.convert.Writer; - -/** - * byte[] 鐨凷impledCoder瀹炵幇 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Reader杈撳叆鐨勫瓙绫诲瀷 - * @param Writer杈撳嚭鐨勫瓙绫诲瀷 - */ -public final class ByteArraySimpledCoder extends SimpledCoder { - - public static final ByteArraySimpledCoder instance = new ByteArraySimpledCoder(); - - @Override - public void convertTo(W out, byte[] values) { - out.writeByteArray(values); - } - - @Override - public byte[] convertFrom(R in) { - return in.readByteArray(); - } - -} +/* + * 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.convert.ext; + +import org.redkale.convert.Reader; +import org.redkale.convert.SimpledCoder; +import org.redkale.convert.Writer; + +/** + * byte[] 鐨凷impledCoder瀹炵幇 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * @param Writer杈撳嚭鐨勫瓙绫诲瀷 + */ +public final class ByteArraySimpledCoder extends SimpledCoder { + + public static final ByteArraySimpledCoder instance = new ByteArraySimpledCoder(); + + @Override + public void convertTo(W out, byte[] values) { + out.writeByteArray(values); + } + + @Override + public byte[] convertFrom(R in) { + return in.readByteArray(); + } + +} diff --git a/src/main/java/org/redkale/convert/ext/ByteBufferSimpledCoder.java b/src/main/java/org/redkale/convert/ext/ByteBufferSimpledCoder.java index ab3812dd6..0d7583664 100644 --- a/src/main/java/org/redkale/convert/ext/ByteBufferSimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/ByteBufferSimpledCoder.java @@ -1,77 +1,77 @@ -/* - * 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.convert.ext; - -import java.nio.ByteBuffer; -import org.redkale.convert.Reader; -import org.redkale.convert.SimpledCoder; -import org.redkale.convert.Writer; - -/** - * ByteBuffer 鐨凷impledCoder瀹炵幇 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Reader杈撳叆鐨勫瓙绫诲瀷 - * @param Writer杈撳嚭鐨勫瓙绫诲瀷 - */ -public final class ByteBufferSimpledCoder extends SimpledCoder { - - public static final ByteBufferSimpledCoder instance = new ByteBufferSimpledCoder(); - - @Override - public void convertTo(W out, ByteBuffer value) { - if (value == null) { - out.writeNull(); - return; - } - if (out.writeArrayB(value.remaining(), this, ByteSimpledCoder.instance, value) < 0) { - boolean flag = false; - for (byte v : value.array()) { - if (flag) out.writeArrayMark(); - out.writeByte(v); - flag = true; - } - } - out.writeArrayE(); - } - - @Override - public ByteBuffer convertFrom(R in) { - int len = in.readArrayB(null, null, ByteSimpledCoder.instance); - int contentLength = -1; - if (len == Reader.SIGN_NULL) return null; - if (len == Reader.SIGN_NOLENBUTBYTES) { - contentLength = in.readMemberContentLength(null, ByteSimpledCoder.instance); - len = Reader.SIGN_NOLENGTH; - } - if (len == Reader.SIGN_NOLENGTH) { - int size = 0; - byte[] data = new byte[8]; - int startPosition = in.position(); - while (in.hasNext(startPosition, contentLength)) { - if (size >= data.length) { - byte[] newdata = new byte[data.length + 4]; - System.arraycopy(data, 0, newdata, 0, size); - data = newdata; - } - data[size++] = in.readByte(); - } - in.readArrayE(); - return ByteBuffer.wrap(data, 0, size); - } else { - byte[] values = new byte[len]; - for (int i = 0; i < values.length; i++) { - values[i] = in.readByte(); - } - in.readArrayE(); - return ByteBuffer.wrap(values); - } - } - -} +/* + * 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.convert.ext; + +import java.nio.ByteBuffer; +import org.redkale.convert.Reader; +import org.redkale.convert.SimpledCoder; +import org.redkale.convert.Writer; + +/** + * ByteBuffer 鐨凷impledCoder瀹炵幇 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * @param Writer杈撳嚭鐨勫瓙绫诲瀷 + */ +public final class ByteBufferSimpledCoder extends SimpledCoder { + + public static final ByteBufferSimpledCoder instance = new ByteBufferSimpledCoder(); + + @Override + public void convertTo(W out, ByteBuffer value) { + if (value == null) { + out.writeNull(); + return; + } + if (out.writeArrayB(value.remaining(), this, ByteSimpledCoder.instance, value) < 0) { + boolean flag = false; + for (byte v : value.array()) { + if (flag) out.writeArrayMark(); + out.writeByte(v); + flag = true; + } + } + out.writeArrayE(); + } + + @Override + public ByteBuffer convertFrom(R in) { + int len = in.readArrayB(null, null, ByteSimpledCoder.instance); + int contentLength = -1; + if (len == Reader.SIGN_NULL) return null; + if (len == Reader.SIGN_NOLENBUTBYTES) { + contentLength = in.readMemberContentLength(null, ByteSimpledCoder.instance); + len = Reader.SIGN_NOLENGTH; + } + if (len == Reader.SIGN_NOLENGTH) { + int size = 0; + byte[] data = new byte[8]; + int startPosition = in.position(); + while (in.hasNext(startPosition, contentLength)) { + if (size >= data.length) { + byte[] newdata = new byte[data.length + 4]; + System.arraycopy(data, 0, newdata, 0, size); + data = newdata; + } + data[size++] = in.readByte(); + } + in.readArrayE(); + return ByteBuffer.wrap(data, 0, size); + } else { + byte[] values = new byte[len]; + for (int i = 0; i < values.length; i++) { + values[i] = in.readByte(); + } + in.readArrayE(); + return ByteBuffer.wrap(values); + } + } + +} diff --git a/src/main/java/org/redkale/convert/ext/ByteSimpledCoder.java b/src/main/java/org/redkale/convert/ext/ByteSimpledCoder.java index bee075834..ff630f072 100644 --- a/src/main/java/org/redkale/convert/ext/ByteSimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/ByteSimpledCoder.java @@ -1,36 +1,36 @@ -/* - * 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.convert.ext; - -import org.redkale.convert.Reader; -import org.redkale.convert.SimpledCoder; -import org.redkale.convert.Writer; - -/** - * byte 鐨凷impledCoder瀹炵幇 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Reader杈撳叆鐨勫瓙绫诲瀷 - * @param Writer杈撳嚭鐨勫瓙绫诲瀷 - */ -public final class ByteSimpledCoder extends SimpledCoder { - - public static final ByteSimpledCoder instance = new ByteSimpledCoder(); - - @Override - public void convertTo(W out, Byte value) { - out.writeByte(value); - } - - @Override - public Byte convertFrom(R in) { - return in.readByte(); - } - -} +/* + * 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.convert.ext; + +import org.redkale.convert.Reader; +import org.redkale.convert.SimpledCoder; +import org.redkale.convert.Writer; + +/** + * byte 鐨凷impledCoder瀹炵幇 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * @param Writer杈撳嚭鐨勫瓙绫诲瀷 + */ +public final class ByteSimpledCoder extends SimpledCoder { + + public static final ByteSimpledCoder instance = new ByteSimpledCoder(); + + @Override + public void convertTo(W out, Byte value) { + out.writeByte(value); + } + + @Override + public Byte convertFrom(R in) { + return in.readByte(); + } + +} diff --git a/src/main/java/org/redkale/convert/ext/CharArraySimpledCoder.java b/src/main/java/org/redkale/convert/ext/CharArraySimpledCoder.java index c60039d16..1199ccde8 100644 --- a/src/main/java/org/redkale/convert/ext/CharArraySimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/CharArraySimpledCoder.java @@ -1,78 +1,78 @@ -/* - * 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.convert.ext; - -import org.redkale.convert.Reader; -import org.redkale.convert.SimpledCoder; -import org.redkale.convert.Writer; - -/** - * char[] 鐨凷impledCoder瀹炵幇 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Reader杈撳叆鐨勫瓙绫诲瀷 - * @param Writer杈撳嚭鐨勫瓙绫诲瀷 - */ -public final class CharArraySimpledCoder extends SimpledCoder { - - public static final CharArraySimpledCoder instance = new CharArraySimpledCoder(); - - @Override - public void convertTo(W out, char[] values) { - if (values == null) { - out.writeNull(); - return; - } - if (out.writeArrayB(values.length, this, CharSimpledCoder.instance, values) < 0) { - boolean flag = false; - for (char v : values) { - if (flag) out.writeArrayMark(); - out.writeChar(v); - flag = true; - } - } - out.writeArrayE(); - } - - @Override - public char[] convertFrom(R in) { - int len = in.readArrayB(null, null, CharSimpledCoder.instance); - int contentLength = -1; - if (len == Reader.SIGN_NULL) return null; - if (len == Reader.SIGN_NOLENBUTBYTES) { - contentLength = in.readMemberContentLength(null, CharSimpledCoder.instance); - len = Reader.SIGN_NOLENGTH; - } - if (len == Reader.SIGN_NOLENGTH) { - int size = 0; - char[] data = new char[8]; - int startPosition = in.position(); - while (in.hasNext(startPosition, contentLength)) { - if (size >= data.length) { - char[] newdata = new char[data.length + 4]; - System.arraycopy(data, 0, newdata, 0, size); - data = newdata; - } - data[size++] = in.readChar(); - } - in.readArrayE(); - char[] newdata = new char[size]; - System.arraycopy(data, 0, newdata, 0, size); - return newdata; - } else { - char[] values = new char[len]; - for (int i = 0; i < values.length; i++) { - values[i] = in.readChar(); - } - in.readArrayE(); - return values; - } - } - -} +/* + * 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.convert.ext; + +import org.redkale.convert.Reader; +import org.redkale.convert.SimpledCoder; +import org.redkale.convert.Writer; + +/** + * char[] 鐨凷impledCoder瀹炵幇 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * @param Writer杈撳嚭鐨勫瓙绫诲瀷 + */ +public final class CharArraySimpledCoder extends SimpledCoder { + + public static final CharArraySimpledCoder instance = new CharArraySimpledCoder(); + + @Override + public void convertTo(W out, char[] values) { + if (values == null) { + out.writeNull(); + return; + } + if (out.writeArrayB(values.length, this, CharSimpledCoder.instance, values) < 0) { + boolean flag = false; + for (char v : values) { + if (flag) out.writeArrayMark(); + out.writeChar(v); + flag = true; + } + } + out.writeArrayE(); + } + + @Override + public char[] convertFrom(R in) { + int len = in.readArrayB(null, null, CharSimpledCoder.instance); + int contentLength = -1; + if (len == Reader.SIGN_NULL) return null; + if (len == Reader.SIGN_NOLENBUTBYTES) { + contentLength = in.readMemberContentLength(null, CharSimpledCoder.instance); + len = Reader.SIGN_NOLENGTH; + } + if (len == Reader.SIGN_NOLENGTH) { + int size = 0; + char[] data = new char[8]; + int startPosition = in.position(); + while (in.hasNext(startPosition, contentLength)) { + if (size >= data.length) { + char[] newdata = new char[data.length + 4]; + System.arraycopy(data, 0, newdata, 0, size); + data = newdata; + } + data[size++] = in.readChar(); + } + in.readArrayE(); + char[] newdata = new char[size]; + System.arraycopy(data, 0, newdata, 0, size); + return newdata; + } else { + char[] values = new char[len]; + for (int i = 0; i < values.length; i++) { + values[i] = in.readChar(); + } + in.readArrayE(); + return values; + } + } + +} diff --git a/src/main/java/org/redkale/convert/ext/CharSequenceSimpledCoder.java b/src/main/java/org/redkale/convert/ext/CharSequenceSimpledCoder.java index a74a6f7bd..2250ee0fa 100644 --- a/src/main/java/org/redkale/convert/ext/CharSequenceSimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/CharSequenceSimpledCoder.java @@ -1,49 +1,49 @@ -/* - * 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.convert.ext; - -import org.redkale.convert.*; - -/** - * CharSequence 鐨凷impledCoder瀹炵幇 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Reader杈撳叆鐨勫瓙绫诲瀷 - * @param Writer杈撳嚭鐨勫瓙绫诲瀷 - */ -public class CharSequenceSimpledCoder extends SimpledCoder { - - public static final CharSequenceSimpledCoder instance = new CharSequenceSimpledCoder(); - - @Override - public void convertTo(W out, CharSequence value) { - out.writeString(value == null ? null : value.toString()); - } - - @Override - public CharSequence convertFrom(R in) { - return in.readString(); - } - - public static class StringBuilderSimpledCoder extends SimpledCoder { - - public static final StringBuilderSimpledCoder instance = new StringBuilderSimpledCoder(); - - @Override - public void convertTo(W out, StringBuilder value) { - out.writeString(value == null ? null : value.toString()); - } - - @Override - public StringBuilder convertFrom(R in) { - String rs = in.readString(); - return rs == null ? null : new StringBuilder(rs); - } - } -} +/* + * 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.convert.ext; + +import org.redkale.convert.*; + +/** + * CharSequence 鐨凷impledCoder瀹炵幇 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * @param Writer杈撳嚭鐨勫瓙绫诲瀷 + */ +public class CharSequenceSimpledCoder extends SimpledCoder { + + public static final CharSequenceSimpledCoder instance = new CharSequenceSimpledCoder(); + + @Override + public void convertTo(W out, CharSequence value) { + out.writeString(value == null ? null : value.toString()); + } + + @Override + public CharSequence convertFrom(R in) { + return in.readString(); + } + + public static class StringBuilderSimpledCoder extends SimpledCoder { + + public static final StringBuilderSimpledCoder instance = new StringBuilderSimpledCoder(); + + @Override + public void convertTo(W out, StringBuilder value) { + out.writeString(value == null ? null : value.toString()); + } + + @Override + public StringBuilder convertFrom(R in) { + String rs = in.readString(); + return rs == null ? null : new StringBuilder(rs); + } + } +} diff --git a/src/main/java/org/redkale/convert/ext/CharSimpledCoder.java b/src/main/java/org/redkale/convert/ext/CharSimpledCoder.java index 78badf4d8..8c25c5a35 100644 --- a/src/main/java/org/redkale/convert/ext/CharSimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/CharSimpledCoder.java @@ -1,35 +1,35 @@ -/* - * 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.convert.ext; - -import org.redkale.convert.Reader; -import org.redkale.convert.SimpledCoder; -import org.redkale.convert.Writer; - -/** - * char 鐨凷impledCoder瀹炵幇 - * - *

璇︽儏瑙: https://redkale.org - * @author zhangjx - * @param Reader杈撳叆鐨勫瓙绫诲瀷 - * @param Writer杈撳嚭鐨勫瓙绫诲瀷 - */ -public final class CharSimpledCoder extends SimpledCoder { - - public static final CharSimpledCoder instance = new CharSimpledCoder(); - - @Override - public void convertTo(W out, Character value) { - out.writeChar(value); - } - - @Override - public Character convertFrom(R in) { - return in.readChar(); - } - -} +/* + * 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.convert.ext; + +import org.redkale.convert.Reader; +import org.redkale.convert.SimpledCoder; +import org.redkale.convert.Writer; + +/** + * char 鐨凷impledCoder瀹炵幇 + * + *

璇︽儏瑙: https://redkale.org + * @author zhangjx + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * @param Writer杈撳嚭鐨勫瓙绫诲瀷 + */ +public final class CharSimpledCoder extends SimpledCoder { + + public static final CharSimpledCoder instance = new CharSimpledCoder(); + + @Override + public void convertTo(W out, Character value) { + out.writeChar(value); + } + + @Override + public Character convertFrom(R in) { + return in.readChar(); + } + +} diff --git a/src/main/java/org/redkale/convert/ext/CompletionHandlerSimpledCoder.java b/src/main/java/org/redkale/convert/ext/CompletionHandlerSimpledCoder.java index a72831989..5ea8116fc 100644 --- a/src/main/java/org/redkale/convert/ext/CompletionHandlerSimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/CompletionHandlerSimpledCoder.java @@ -1,36 +1,36 @@ -/* - * 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.convert.ext; - -import java.nio.channels.*; -import org.redkale.convert.*; - -/** - * java.nio.channels.CompletionHandler 鐨凷impledCoder瀹炵幇, 鍙緭鍑簄ull - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Reader杈撳叆鐨勫瓙绫诲瀷 - * @param Writer杈撳嚭鐨勫瓙绫诲瀷 - */ -public final class CompletionHandlerSimpledCoder extends SimpledCoder { - - public static final CompletionHandlerSimpledCoder instance = new CompletionHandlerSimpledCoder(); - - @Override - public void convertTo(W out, CompletionHandler value) { - out.writeObjectNull(CompletionHandler.class); - } - - @Override - public CompletionHandler convertFrom(R in) { - in.readObjectB(CompletionHandler.class); - return null; - } - -} +/* + * 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.convert.ext; + +import java.nio.channels.*; +import org.redkale.convert.*; + +/** + * java.nio.channels.CompletionHandler 鐨凷impledCoder瀹炵幇, 鍙緭鍑簄ull + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * @param Writer杈撳嚭鐨勫瓙绫诲瀷 + */ +public final class CompletionHandlerSimpledCoder extends SimpledCoder { + + public static final CompletionHandlerSimpledCoder instance = new CompletionHandlerSimpledCoder(); + + @Override + public void convertTo(W out, CompletionHandler value) { + out.writeObjectNull(CompletionHandler.class); + } + + @Override + public CompletionHandler convertFrom(R in) { + in.readObjectB(CompletionHandler.class); + return null; + } + +} diff --git a/src/main/java/org/redkale/convert/ext/DLongSimpledCoder.java b/src/main/java/org/redkale/convert/ext/DLongSimpledCoder.java index 0daf717a4..cbf9a8eb3 100644 --- a/src/main/java/org/redkale/convert/ext/DLongSimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/DLongSimpledCoder.java @@ -1,73 +1,73 @@ -/* - * 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.convert.ext; - -import org.redkale.convert.Reader; -import org.redkale.convert.Writer; -import org.redkale.convert.SimpledCoder; -import org.redkale.util.*; - -/** - * Dlong 鐨凷impledCoder瀹炵幇 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Reader杈撳叆鐨勫瓙绫诲瀷 - * @param Writer杈撳嚭鐨勫瓙绫诲瀷 - */ -public final class DLongSimpledCoder extends SimpledCoder { - - private static final ByteArraySimpledCoder bsSimpledCoder = ByteArraySimpledCoder.instance; - - public static final DLongSimpledCoder instance = new DLongSimpledCoder(); - - @Override - @SuppressWarnings("unchecked") - public void convertTo(final W out, final DLong value) { - if (value == null) { - out.writeNull(); - } else { - bsSimpledCoder.convertTo(out, value.directBytes()); - } - } - - @Override - @SuppressWarnings("unchecked") - public DLong convertFrom(R in) { - byte[] bs = bsSimpledCoder.convertFrom(in); - if (bs == null) return null; - return DLong.create(bs); - } - - /** - * DLong 鐨凧sonSimpledCoder瀹炵幇 - * - * @param Reader杈撳叆鐨勫瓙绫诲瀷 - * @param Writer杈撳嚭鐨勫瓙绫诲瀷 - */ - public static class DLongJsonSimpledCoder extends SimpledCoder { - - public static final DLongJsonSimpledCoder instance = new DLongJsonSimpledCoder(); - - @Override - public void convertTo(final Writer out, final DLong value) { - if (value == null) { - out.writeNull(); - } else { - out.writeSmallString(value.toString()); - } - } - - @Override - public DLong convertFrom(Reader in) { - final String str = in.readSmallString(); - if (str == null) return null; - return DLong.create(Utility.hexToBin(str)); - } - } -} +/* + * 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.convert.ext; + +import org.redkale.convert.Reader; +import org.redkale.convert.Writer; +import org.redkale.convert.SimpledCoder; +import org.redkale.util.*; + +/** + * Dlong 鐨凷impledCoder瀹炵幇 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * @param Writer杈撳嚭鐨勫瓙绫诲瀷 + */ +public final class DLongSimpledCoder extends SimpledCoder { + + private static final ByteArraySimpledCoder bsSimpledCoder = ByteArraySimpledCoder.instance; + + public static final DLongSimpledCoder instance = new DLongSimpledCoder(); + + @Override + @SuppressWarnings("unchecked") + public void convertTo(final W out, final DLong value) { + if (value == null) { + out.writeNull(); + } else { + bsSimpledCoder.convertTo(out, value.directBytes()); + } + } + + @Override + @SuppressWarnings("unchecked") + public DLong convertFrom(R in) { + byte[] bs = bsSimpledCoder.convertFrom(in); + if (bs == null) return null; + return DLong.create(bs); + } + + /** + * DLong 鐨凧sonSimpledCoder瀹炵幇 + * + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * @param Writer杈撳嚭鐨勫瓙绫诲瀷 + */ + public static class DLongJsonSimpledCoder extends SimpledCoder { + + public static final DLongJsonSimpledCoder instance = new DLongJsonSimpledCoder(); + + @Override + public void convertTo(final Writer out, final DLong value) { + if (value == null) { + out.writeNull(); + } else { + out.writeSmallString(value.toString()); + } + } + + @Override + public DLong convertFrom(Reader in) { + final String str = in.readSmallString(); + if (str == null) return null; + return DLong.create(Utility.hexToBin(str)); + } + } +} diff --git a/src/main/java/org/redkale/convert/ext/DateSimpledCoder.java b/src/main/java/org/redkale/convert/ext/DateSimpledCoder.java index 68bc48167..83ff0c8c2 100644 --- a/src/main/java/org/redkale/convert/ext/DateSimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/DateSimpledCoder.java @@ -1,38 +1,38 @@ -/* - * 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.convert.ext; - -import org.redkale.convert.Reader; -import org.redkale.convert.SimpledCoder; -import org.redkale.convert.Writer; -import java.util.Date; - -/** - * java.util.Date 鐨凷impledCoder瀹炵幇 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Reader杈撳叆鐨勫瓙绫诲瀷 - * @param Writer杈撳嚭鐨勫瓙绫诲瀷 - */ -public final class DateSimpledCoder extends SimpledCoder { - - public static final DateSimpledCoder instance = new DateSimpledCoder(); - - @Override - public void convertTo(W out, Date value) { - out.writeLong(value == null ? 0L : value.getTime()); - } - - @Override - public Date convertFrom(R in) { - long t = in.readLong(); - return t == 0 ? null : new Date(t); - } - -} +/* + * 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.convert.ext; + +import org.redkale.convert.Reader; +import org.redkale.convert.SimpledCoder; +import org.redkale.convert.Writer; +import java.util.Date; + +/** + * java.util.Date 鐨凷impledCoder瀹炵幇 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * @param Writer杈撳嚭鐨勫瓙绫诲瀷 + */ +public final class DateSimpledCoder extends SimpledCoder { + + public static final DateSimpledCoder instance = new DateSimpledCoder(); + + @Override + public void convertTo(W out, Date value) { + out.writeLong(value == null ? 0L : value.getTime()); + } + + @Override + public Date convertFrom(R in) { + long t = in.readLong(); + return t == 0 ? null : new Date(t); + } + +} diff --git a/src/main/java/org/redkale/convert/ext/DoubleArraySimpledCoder.java b/src/main/java/org/redkale/convert/ext/DoubleArraySimpledCoder.java index a9aa2b083..c5db2c821 100644 --- a/src/main/java/org/redkale/convert/ext/DoubleArraySimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/DoubleArraySimpledCoder.java @@ -1,101 +1,101 @@ -/* - * 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.convert.ext; - -import java.util.stream.DoubleStream; -import org.redkale.convert.Reader; -import org.redkale.convert.SimpledCoder; -import org.redkale.convert.Writer; - -/** - * double[] 鐨凷impledCoder瀹炵幇 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Reader杈撳叆鐨勫瓙绫诲瀷 - * @param Writer杈撳嚭鐨勫瓙绫诲瀷 - */ -public final class DoubleArraySimpledCoder extends SimpledCoder { - - public static final DoubleArraySimpledCoder instance = new DoubleArraySimpledCoder(); - - @Override - public void convertTo(W out, double[] values) { - if (values == null) { - out.writeNull(); - return; - } - if (out.writeArrayB(values.length, this, DoubleSimpledCoder.instance, values) < 0) { - boolean flag = false; - for (double v : values) { - if (flag) out.writeArrayMark(); - out.writeDouble(v); - flag = true; - } - } - out.writeArrayE(); - } - - @Override - public double[] convertFrom(R in) { - int len = in.readArrayB(null, null, DoubleSimpledCoder.instance); - int contentLength = -1; - if (len == Reader.SIGN_NULL) return null; - if (len == Reader.SIGN_NOLENBUTBYTES) { - contentLength = in.readMemberContentLength(null, DoubleSimpledCoder.instance); - len = Reader.SIGN_NOLENGTH; - } - if (len == Reader.SIGN_NOLENGTH) { - int size = 0; - double[] data = new double[8]; - int startPosition = in.position(); - while (in.hasNext(startPosition, contentLength)) { - if (size >= data.length) { - double[] newdata = new double[data.length + 4]; - System.arraycopy(data, 0, newdata, 0, size); - data = newdata; - } - data[size++] = in.readDouble(); - } - in.readArrayE(); - double[] newdata = new double[size]; - System.arraycopy(data, 0, newdata, 0, size); - return newdata; - } else { - double[] values = new double[len]; - for (int i = 0; i < values.length; i++) { - values[i] = in.readDouble(); - } - in.readArrayE(); - return values; - } - } - - public final static class DoubleStreamSimpledCoder extends SimpledCoder { - - public static final DoubleStreamSimpledCoder instance = new DoubleStreamSimpledCoder(); - - @Override - @SuppressWarnings("unchecked") - public void convertTo(W out, DoubleStream values) { - if (values == null) { - out.writeNull(); - return; - } - DoubleArraySimpledCoder.instance.convertTo(out, values.toArray()); - } - - @Override - @SuppressWarnings("unchecked") - public DoubleStream convertFrom(R in) { - double[] value = DoubleArraySimpledCoder.instance.convertFrom(in); - return value == null ? null : DoubleStream.of(value); - } - - } -} +/* + * 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.convert.ext; + +import java.util.stream.DoubleStream; +import org.redkale.convert.Reader; +import org.redkale.convert.SimpledCoder; +import org.redkale.convert.Writer; + +/** + * double[] 鐨凷impledCoder瀹炵幇 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * @param Writer杈撳嚭鐨勫瓙绫诲瀷 + */ +public final class DoubleArraySimpledCoder extends SimpledCoder { + + public static final DoubleArraySimpledCoder instance = new DoubleArraySimpledCoder(); + + @Override + public void convertTo(W out, double[] values) { + if (values == null) { + out.writeNull(); + return; + } + if (out.writeArrayB(values.length, this, DoubleSimpledCoder.instance, values) < 0) { + boolean flag = false; + for (double v : values) { + if (flag) out.writeArrayMark(); + out.writeDouble(v); + flag = true; + } + } + out.writeArrayE(); + } + + @Override + public double[] convertFrom(R in) { + int len = in.readArrayB(null, null, DoubleSimpledCoder.instance); + int contentLength = -1; + if (len == Reader.SIGN_NULL) return null; + if (len == Reader.SIGN_NOLENBUTBYTES) { + contentLength = in.readMemberContentLength(null, DoubleSimpledCoder.instance); + len = Reader.SIGN_NOLENGTH; + } + if (len == Reader.SIGN_NOLENGTH) { + int size = 0; + double[] data = new double[8]; + int startPosition = in.position(); + while (in.hasNext(startPosition, contentLength)) { + if (size >= data.length) { + double[] newdata = new double[data.length + 4]; + System.arraycopy(data, 0, newdata, 0, size); + data = newdata; + } + data[size++] = in.readDouble(); + } + in.readArrayE(); + double[] newdata = new double[size]; + System.arraycopy(data, 0, newdata, 0, size); + return newdata; + } else { + double[] values = new double[len]; + for (int i = 0; i < values.length; i++) { + values[i] = in.readDouble(); + } + in.readArrayE(); + return values; + } + } + + public final static class DoubleStreamSimpledCoder extends SimpledCoder { + + public static final DoubleStreamSimpledCoder instance = new DoubleStreamSimpledCoder(); + + @Override + @SuppressWarnings("unchecked") + public void convertTo(W out, DoubleStream values) { + if (values == null) { + out.writeNull(); + return; + } + DoubleArraySimpledCoder.instance.convertTo(out, values.toArray()); + } + + @Override + @SuppressWarnings("unchecked") + public DoubleStream convertFrom(R in) { + double[] value = DoubleArraySimpledCoder.instance.convertFrom(in); + return value == null ? null : DoubleStream.of(value); + } + + } +} diff --git a/src/main/java/org/redkale/convert/ext/DoubleSimpledCoder.java b/src/main/java/org/redkale/convert/ext/DoubleSimpledCoder.java index 3a04ef4bf..0b0a6fc6a 100644 --- a/src/main/java/org/redkale/convert/ext/DoubleSimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/DoubleSimpledCoder.java @@ -1,34 +1,34 @@ -/* - * 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.convert.ext; - -import org.redkale.convert.Reader; -import org.redkale.convert.SimpledCoder; -import org.redkale.convert.Writer; - -/** - * double 鐨凷impledCoder瀹炵幇 - * - *

璇︽儏瑙: https://redkale.org - * @author zhangjx - * @param Reader杈撳叆鐨勫瓙绫诲瀷 - * @param Writer杈撳嚭鐨勫瓙绫诲瀷 - */ -public final class DoubleSimpledCoder extends SimpledCoder { - - public static final DoubleSimpledCoder instance = new DoubleSimpledCoder(); - - @Override - public void convertTo(W out, Double value) { - out.writeDouble(value); - } - - @Override - public Double convertFrom(R in) { - return in.readDouble(); - } - -} +/* + * 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.convert.ext; + +import org.redkale.convert.Reader; +import org.redkale.convert.SimpledCoder; +import org.redkale.convert.Writer; + +/** + * double 鐨凷impledCoder瀹炵幇 + * + *

璇︽儏瑙: https://redkale.org + * @author zhangjx + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * @param Writer杈撳嚭鐨勫瓙绫诲瀷 + */ +public final class DoubleSimpledCoder extends SimpledCoder { + + public static final DoubleSimpledCoder instance = new DoubleSimpledCoder(); + + @Override + public void convertTo(W out, Double value) { + out.writeDouble(value); + } + + @Override + public Double convertFrom(R in) { + return in.readDouble(); + } + +} diff --git a/src/main/java/org/redkale/convert/ext/DurationSimpledCoder.java b/src/main/java/org/redkale/convert/ext/DurationSimpledCoder.java index d8ed4b2bf..631d41965 100644 --- a/src/main/java/org/redkale/convert/ext/DurationSimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/DurationSimpledCoder.java @@ -1,41 +1,41 @@ -/* - * 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.convert.ext; - -import java.time.Duration; -import org.redkale.convert.*; - -/** - * Duration 鐨凷impledCoder瀹炵幇 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Reader杈撳叆鐨勫瓙绫诲瀷 - * @param Writer杈撳嚭鐨勫瓙绫诲瀷 - */ -public class DurationSimpledCoder extends SimpledCoder { - - public static final DurationSimpledCoder instance = new DurationSimpledCoder(); - - @Override - public void convertTo(W out, Duration value) { - if (value == null) { - out.writeNull(); - } else { - out.writeLong(value.toNanos()); - } - } - - @Override - public Duration convertFrom(R in) { - String value = in.readSmallString(); - if (value == null) return null; - return Duration.ofNanos(Long.parseLong(value)); - } - -} +/* + * 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.convert.ext; + +import java.time.Duration; +import org.redkale.convert.*; + +/** + * Duration 鐨凷impledCoder瀹炵幇 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * @param Writer杈撳嚭鐨勫瓙绫诲瀷 + */ +public class DurationSimpledCoder extends SimpledCoder { + + public static final DurationSimpledCoder instance = new DurationSimpledCoder(); + + @Override + public void convertTo(W out, Duration value) { + if (value == null) { + out.writeNull(); + } else { + out.writeLong(value.toNanos()); + } + } + + @Override + public Duration convertFrom(R in) { + String value = in.readSmallString(); + if (value == null) return null; + return Duration.ofNanos(Long.parseLong(value)); + } + +} diff --git a/src/main/java/org/redkale/convert/ext/EnumSimpledCoder.java b/src/main/java/org/redkale/convert/ext/EnumSimpledCoder.java index a4b8a2200..3c8090bb5 100644 --- a/src/main/java/org/redkale/convert/ext/EnumSimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/EnumSimpledCoder.java @@ -1,50 +1,50 @@ -/* - * 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.convert.ext; - -import org.redkale.convert.Reader; -import org.redkale.convert.SimpledCoder; -import org.redkale.convert.Writer; - -/** - * 鏋氫妇 鐨凷impledCoder瀹炵幇 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Reader杈撳叆鐨勫瓙绫诲瀷 - * @param Writer杈撳嚭鐨勫瓙绫诲瀷 - * @param Enum鐨勫瓙绫 - */ -public final class EnumSimpledCoder extends SimpledCoder { - - public EnumSimpledCoder(Class type) { - this.type = type; - } - - @Override - public void convertTo(final W out, final E value) { - if (value == null) { - out.writeNull(); - } else { - out.writeSmallString(value.toString()); - } - } - - @Override - @SuppressWarnings("unchecked") - public E convertFrom(final R in) { - String value = in.readSmallString(); - if (value == null) return null; - return (E) Enum.valueOf((Class) type, value); - } - - @Override - public Class getType() { - return (Class) type; - } -} +/* + * 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.convert.ext; + +import org.redkale.convert.Reader; +import org.redkale.convert.SimpledCoder; +import org.redkale.convert.Writer; + +/** + * 鏋氫妇 鐨凷impledCoder瀹炵幇 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * @param Writer杈撳嚭鐨勫瓙绫诲瀷 + * @param Enum鐨勫瓙绫 + */ +public final class EnumSimpledCoder extends SimpledCoder { + + public EnumSimpledCoder(Class type) { + this.type = type; + } + + @Override + public void convertTo(final W out, final E value) { + if (value == null) { + out.writeNull(); + } else { + out.writeSmallString(value.toString()); + } + } + + @Override + @SuppressWarnings("unchecked") + public E convertFrom(final R in) { + String value = in.readSmallString(); + if (value == null) return null; + return (E) Enum.valueOf((Class) type, value); + } + + @Override + public Class getType() { + return (Class) type; + } +} diff --git a/src/main/java/org/redkale/convert/ext/FileSimpledCoder.java b/src/main/java/org/redkale/convert/ext/FileSimpledCoder.java index a7ae3f9b8..b5885b2e7 100644 --- a/src/main/java/org/redkale/convert/ext/FileSimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/FileSimpledCoder.java @@ -1,41 +1,41 @@ -/* - * 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.convert.ext; - -import java.io.File; -import org.redkale.convert.*; - -/** - * 鏂囦欢 鐨凷impledCoder瀹炵幇 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Reader杈撳叆鐨勫瓙绫诲瀷 - * @param Writer杈撳嚭鐨勫瓙绫诲瀷 - */ -public class FileSimpledCoder extends SimpledCoder { - - public static final FileSimpledCoder instance = new FileSimpledCoder(); - - @Override - public void convertTo(W out, File value) { - if (value == null) { - out.writeNull(); - } else { - out.writeString(value.getPath()); - } - } - - @Override - public File convertFrom(R in) { - String value = in.readString(); - if (value == null) return null; - return new File(value); - } - -} +/* + * 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.convert.ext; + +import java.io.File; +import org.redkale.convert.*; + +/** + * 鏂囦欢 鐨凷impledCoder瀹炵幇 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * @param Writer杈撳嚭鐨勫瓙绫诲瀷 + */ +public class FileSimpledCoder extends SimpledCoder { + + public static final FileSimpledCoder instance = new FileSimpledCoder(); + + @Override + public void convertTo(W out, File value) { + if (value == null) { + out.writeNull(); + } else { + out.writeString(value.getPath()); + } + } + + @Override + public File convertFrom(R in) { + String value = in.readString(); + if (value == null) return null; + return new File(value); + } + +} diff --git a/src/main/java/org/redkale/convert/ext/FloatArraySimpledCoder.java b/src/main/java/org/redkale/convert/ext/FloatArraySimpledCoder.java index f8d1e46ab..b7892a0ae 100644 --- a/src/main/java/org/redkale/convert/ext/FloatArraySimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/FloatArraySimpledCoder.java @@ -1,78 +1,78 @@ -/* - * 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.convert.ext; - -import org.redkale.convert.Reader; -import org.redkale.convert.SimpledCoder; -import org.redkale.convert.Writer; - -/** - * float[] 鐨凷impledCoder瀹炵幇 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Reader杈撳叆鐨勫瓙绫诲瀷 - * @param Writer杈撳嚭鐨勫瓙绫诲瀷 - */ -public final class FloatArraySimpledCoder extends SimpledCoder { - - public static final FloatArraySimpledCoder instance = new FloatArraySimpledCoder(); - - @Override - public void convertTo(W out, float[] values) { - if (values == null) { - out.writeNull(); - return; - } - if (out.writeArrayB(values.length, this, FloatSimpledCoder.instance, values) < 0) { - boolean flag = false; - for (float v : values) { - if (flag) out.writeArrayMark(); - out.writeFloat(v); - flag = true; - } - } - out.writeArrayE(); - } - - @Override - public float[] convertFrom(R in) { - int len = in.readArrayB(null, null, FloatSimpledCoder.instance); - int contentLength = -1; - if (len == Reader.SIGN_NULL) return null; - if (len == Reader.SIGN_NOLENBUTBYTES) { - contentLength = in.readMemberContentLength(null, FloatSimpledCoder.instance); - len = Reader.SIGN_NOLENGTH; - } - if (len == Reader.SIGN_NOLENGTH) { - int size = 0; - float[] data = new float[8]; - int startPosition = in.position(); - while (in.hasNext(startPosition, contentLength)) { - if (size >= data.length) { - float[] newdata = new float[data.length + 4]; - System.arraycopy(data, 0, newdata, 0, size); - data = newdata; - } - data[size++] = in.readFloat(); - } - in.readArrayE(); - float[] newdata = new float[size]; - System.arraycopy(data, 0, newdata, 0, size); - return newdata; - } else { - float[] values = new float[len]; - for (int i = 0; i < values.length; i++) { - values[i] = in.readFloat(); - } - in.readArrayE(); - return values; - } - } - -} +/* + * 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.convert.ext; + +import org.redkale.convert.Reader; +import org.redkale.convert.SimpledCoder; +import org.redkale.convert.Writer; + +/** + * float[] 鐨凷impledCoder瀹炵幇 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * @param Writer杈撳嚭鐨勫瓙绫诲瀷 + */ +public final class FloatArraySimpledCoder extends SimpledCoder { + + public static final FloatArraySimpledCoder instance = new FloatArraySimpledCoder(); + + @Override + public void convertTo(W out, float[] values) { + if (values == null) { + out.writeNull(); + return; + } + if (out.writeArrayB(values.length, this, FloatSimpledCoder.instance, values) < 0) { + boolean flag = false; + for (float v : values) { + if (flag) out.writeArrayMark(); + out.writeFloat(v); + flag = true; + } + } + out.writeArrayE(); + } + + @Override + public float[] convertFrom(R in) { + int len = in.readArrayB(null, null, FloatSimpledCoder.instance); + int contentLength = -1; + if (len == Reader.SIGN_NULL) return null; + if (len == Reader.SIGN_NOLENBUTBYTES) { + contentLength = in.readMemberContentLength(null, FloatSimpledCoder.instance); + len = Reader.SIGN_NOLENGTH; + } + if (len == Reader.SIGN_NOLENGTH) { + int size = 0; + float[] data = new float[8]; + int startPosition = in.position(); + while (in.hasNext(startPosition, contentLength)) { + if (size >= data.length) { + float[] newdata = new float[data.length + 4]; + System.arraycopy(data, 0, newdata, 0, size); + data = newdata; + } + data[size++] = in.readFloat(); + } + in.readArrayE(); + float[] newdata = new float[size]; + System.arraycopy(data, 0, newdata, 0, size); + return newdata; + } else { + float[] values = new float[len]; + for (int i = 0; i < values.length; i++) { + values[i] = in.readFloat(); + } + in.readArrayE(); + return values; + } + } + +} diff --git a/src/main/java/org/redkale/convert/ext/FloatSimpledCoder.java b/src/main/java/org/redkale/convert/ext/FloatSimpledCoder.java index 682e6f816..9169a2258 100644 --- a/src/main/java/org/redkale/convert/ext/FloatSimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/FloatSimpledCoder.java @@ -1,34 +1,34 @@ -/* - * 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.convert.ext; - -import org.redkale.convert.Reader; -import org.redkale.convert.SimpledCoder; -import org.redkale.convert.Writer; - -/** - * float 鐨凷impledCoder瀹炵幇 - * - *

璇︽儏瑙: https://redkale.org - * @author zhangjx - * @param Reader杈撳叆鐨勫瓙绫诲瀷 - * @param Writer杈撳嚭鐨勫瓙绫诲瀷 - */ -public final class FloatSimpledCoder extends SimpledCoder { - - public static final FloatSimpledCoder instance = new FloatSimpledCoder(); - - @Override - public void convertTo(W out, Float value) { - out.writeFloat(value); - } - - @Override - public Float convertFrom(R in) { - return in.readFloat(); - } - -} +/* + * 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.convert.ext; + +import org.redkale.convert.Reader; +import org.redkale.convert.SimpledCoder; +import org.redkale.convert.Writer; + +/** + * float 鐨凷impledCoder瀹炵幇 + * + *

璇︽儏瑙: https://redkale.org + * @author zhangjx + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * @param Writer杈撳嚭鐨勫瓙绫诲瀷 + */ +public final class FloatSimpledCoder extends SimpledCoder { + + public static final FloatSimpledCoder instance = new FloatSimpledCoder(); + + @Override + public void convertTo(W out, Float value) { + out.writeFloat(value); + } + + @Override + public Float convertFrom(R in) { + return in.readFloat(); + } + +} diff --git a/src/main/java/org/redkale/convert/ext/InetAddressSimpledCoder.java b/src/main/java/org/redkale/convert/ext/InetAddressSimpledCoder.java index a010d720f..3baec531a 100644 --- a/src/main/java/org/redkale/convert/ext/InetAddressSimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/InetAddressSimpledCoder.java @@ -1,148 +1,148 @@ -/* - * 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.convert.ext; - -import org.redkale.convert.SimpledCoder; -import org.redkale.convert.Writer; -import org.redkale.convert.Reader; -import java.net.*; -import org.redkale.util.StringWrapper; - -/** - * InetAddress 鐨凷impledCoder瀹炵幇 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Reader杈撳叆鐨勫瓙绫诲瀷 - * @param Writer杈撳嚭鐨勫瓙绫诲瀷 - */ -@SuppressWarnings("unchecked") -public final class InetAddressSimpledCoder extends SimpledCoder { - - public static final InetAddressSimpledCoder instance = new InetAddressSimpledCoder(); - - @Override - public void convertTo(W out, InetAddress value) { - if (value == null) { - out.writeNull(); - return; - } - ByteArraySimpledCoder.instance.convertTo(out, value.getAddress()); - } - - @Override - public InetAddress convertFrom(R in) { - byte[] bytes = ByteArraySimpledCoder.instance.convertFrom(in); - if (bytes == null) return null; - try { - return InetAddress.getByAddress(bytes); - } catch (Exception ex) { - return null; - } - } - - /** - * InetSocketAddress 鐨凷impledCoder瀹炵幇 - * - * @param Reader杈撳叆鐨勫瓙绫诲瀷 - * @param Writer杈撳嚭鐨勫瓙绫诲瀷 - */ - @SuppressWarnings("unchecked") - public final static class InetSocketAddressSimpledCoder extends SimpledCoder { - - public static final InetSocketAddressSimpledCoder instance = new InetSocketAddressSimpledCoder(); - - @Override - public void convertTo(W out, InetSocketAddress value) { - if (value == null) { - out.writeNull(); - return; - } - ByteArraySimpledCoder.instance.convertTo(out, value.getAddress().getAddress()); - out.writeInt(value.getPort()); - } - - @Override - public InetSocketAddress convertFrom(R in) { - byte[] bytes = ByteArraySimpledCoder.instance.convertFrom(in); - if (bytes == null) return null; - int port = in.readInt(); - try { - return new InetSocketAddress(InetAddress.getByAddress(bytes), port); - } catch (Exception ex) { - return null; - } - } - - } - - /** - * InetAddress 鐨凧sonSimpledCoder瀹炵幇 - * - * @param Reader杈撳叆鐨勫瓙绫诲瀷 - * @param Writer杈撳嚭鐨勫瓙绫诲瀷 - */ - public final static class InetAddressJsonSimpledCoder extends SimpledCoder { - - public static final InetAddressJsonSimpledCoder instance = new InetAddressJsonSimpledCoder(); - - @Override - public void convertTo(W out, InetAddress value) { - if (value == null) { - out.writeNull(); - return; - } - out.writeWrapper(new StringWrapper(value.getHostAddress())); - } - - @Override - public InetAddress convertFrom(R in) { - String str = in.readString(); - if (str == null) return null; - try { - return InetAddress.getByName(str); - } catch (Exception ex) { - return null; - } - } - - } - - /** - * InetSocketAddress 鐨凧sonSimpledCoder瀹炵幇 - * - * @param Reader杈撳叆鐨勫瓙绫诲瀷 - * @param Writer杈撳嚭鐨勫瓙绫诲瀷 - */ - public final static class InetSocketAddressJsonSimpledCoder extends SimpledCoder { - - public static final InetSocketAddressJsonSimpledCoder instance = new InetSocketAddressJsonSimpledCoder(); - - @Override - public void convertTo(W out, InetSocketAddress value) { - if (value == null) { - out.writeNull(); - return; - } - StringSimpledCoder.instance.convertTo(out, value.getHostString() + ":" + value.getPort()); - } - - @Override - public InetSocketAddress convertFrom(R in) { - String str = StringSimpledCoder.instance.convertFrom(in); - if (str == null) return null; - try { - int pos = str.indexOf(':'); - return new InetSocketAddress(str.substring(0, pos), Integer.parseInt(str.substring(pos + 1))); - } catch (Exception ex) { - return null; - } - } - - } -} +/* + * 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.convert.ext; + +import org.redkale.convert.SimpledCoder; +import org.redkale.convert.Writer; +import org.redkale.convert.Reader; +import java.net.*; +import org.redkale.util.StringWrapper; + +/** + * InetAddress 鐨凷impledCoder瀹炵幇 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * @param Writer杈撳嚭鐨勫瓙绫诲瀷 + */ +@SuppressWarnings("unchecked") +public final class InetAddressSimpledCoder extends SimpledCoder { + + public static final InetAddressSimpledCoder instance = new InetAddressSimpledCoder(); + + @Override + public void convertTo(W out, InetAddress value) { + if (value == null) { + out.writeNull(); + return; + } + ByteArraySimpledCoder.instance.convertTo(out, value.getAddress()); + } + + @Override + public InetAddress convertFrom(R in) { + byte[] bytes = ByteArraySimpledCoder.instance.convertFrom(in); + if (bytes == null) return null; + try { + return InetAddress.getByAddress(bytes); + } catch (Exception ex) { + return null; + } + } + + /** + * InetSocketAddress 鐨凷impledCoder瀹炵幇 + * + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * @param Writer杈撳嚭鐨勫瓙绫诲瀷 + */ + @SuppressWarnings("unchecked") + public final static class InetSocketAddressSimpledCoder extends SimpledCoder { + + public static final InetSocketAddressSimpledCoder instance = new InetSocketAddressSimpledCoder(); + + @Override + public void convertTo(W out, InetSocketAddress value) { + if (value == null) { + out.writeNull(); + return; + } + ByteArraySimpledCoder.instance.convertTo(out, value.getAddress().getAddress()); + out.writeInt(value.getPort()); + } + + @Override + public InetSocketAddress convertFrom(R in) { + byte[] bytes = ByteArraySimpledCoder.instance.convertFrom(in); + if (bytes == null) return null; + int port = in.readInt(); + try { + return new InetSocketAddress(InetAddress.getByAddress(bytes), port); + } catch (Exception ex) { + return null; + } + } + + } + + /** + * InetAddress 鐨凧sonSimpledCoder瀹炵幇 + * + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * @param Writer杈撳嚭鐨勫瓙绫诲瀷 + */ + public final static class InetAddressJsonSimpledCoder extends SimpledCoder { + + public static final InetAddressJsonSimpledCoder instance = new InetAddressJsonSimpledCoder(); + + @Override + public void convertTo(W out, InetAddress value) { + if (value == null) { + out.writeNull(); + return; + } + out.writeWrapper(new StringWrapper(value.getHostAddress())); + } + + @Override + public InetAddress convertFrom(R in) { + String str = in.readString(); + if (str == null) return null; + try { + return InetAddress.getByName(str); + } catch (Exception ex) { + return null; + } + } + + } + + /** + * InetSocketAddress 鐨凧sonSimpledCoder瀹炵幇 + * + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * @param Writer杈撳嚭鐨勫瓙绫诲瀷 + */ + public final static class InetSocketAddressJsonSimpledCoder extends SimpledCoder { + + public static final InetSocketAddressJsonSimpledCoder instance = new InetSocketAddressJsonSimpledCoder(); + + @Override + public void convertTo(W out, InetSocketAddress value) { + if (value == null) { + out.writeNull(); + return; + } + StringSimpledCoder.instance.convertTo(out, value.getHostString() + ":" + value.getPort()); + } + + @Override + public InetSocketAddress convertFrom(R in) { + String str = StringSimpledCoder.instance.convertFrom(in); + if (str == null) return null; + try { + int pos = str.indexOf(':'); + return new InetSocketAddress(str.substring(0, pos), Integer.parseInt(str.substring(pos + 1))); + } catch (Exception ex) { + return null; + } + } + + } +} diff --git a/src/main/java/org/redkale/convert/ext/IntArraySimpledCoder.java b/src/main/java/org/redkale/convert/ext/IntArraySimpledCoder.java index 5cd7fd4f6..d3820dbc5 100644 --- a/src/main/java/org/redkale/convert/ext/IntArraySimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/IntArraySimpledCoder.java @@ -1,101 +1,101 @@ -/* - * 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.convert.ext; - -import java.util.stream.IntStream; -import org.redkale.convert.Reader; -import org.redkale.convert.SimpledCoder; -import org.redkale.convert.Writer; - -/** - * int[] 鐨凷impledCoder瀹炵幇 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Reader杈撳叆鐨勫瓙绫诲瀷 - * @param Writer杈撳嚭鐨勫瓙绫诲瀷 - */ -public final class IntArraySimpledCoder extends SimpledCoder { - - public static final IntArraySimpledCoder instance = new IntArraySimpledCoder(); - - @Override - public void convertTo(W out, int[] values) { - if (values == null) { - out.writeNull(); - return; - } - if (out.writeArrayB(values.length, this, IntSimpledCoder.instance, values) < 0) { - boolean flag = false; - for (int v : values) { - if (flag) out.writeArrayMark(); - out.writeInt(v); - flag = true; - } - } - out.writeArrayE(); - } - - @Override - public int[] convertFrom(R in) { - int len = in.readArrayB(null, null, IntSimpledCoder.instance); - int contentLength = -1; - if (len == Reader.SIGN_NULL) return null; - if (len == Reader.SIGN_NOLENBUTBYTES) { - contentLength = in.readMemberContentLength(null, IntSimpledCoder.instance); - len = Reader.SIGN_NOLENGTH; - } - if (len == Reader.SIGN_NOLENGTH) { - int size = 0; - int[] data = new int[8]; - int startPosition = in.position(); - while (in.hasNext(startPosition, contentLength)) { - if (size >= data.length) { - int[] newdata = new int[data.length + 4]; - System.arraycopy(data, 0, newdata, 0, size); - data = newdata; - } - data[size++] = in.readInt(); - } - in.readArrayE(); - int[] newdata = new int[size]; - System.arraycopy(data, 0, newdata, 0, size); - return newdata; - } else { - int[] values = new int[len]; - for (int i = 0; i < values.length; i++) { - values[i] = in.readInt(); - } - in.readArrayE(); - return values; - } - } - - public final static class IntStreamSimpledCoder extends SimpledCoder { - - public static final IntStreamSimpledCoder instance = new IntStreamSimpledCoder(); - - @Override - @SuppressWarnings("unchecked") - public void convertTo(W out, IntStream values) { - if (values == null) { - out.writeNull(); - return; - } - IntArraySimpledCoder.instance.convertTo(out, values.toArray()); - } - - @Override - @SuppressWarnings("unchecked") - public IntStream convertFrom(R in) { - int[] value = IntArraySimpledCoder.instance.convertFrom(in); - return value == null ? null : IntStream.of(value); - } - - } -} +/* + * 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.convert.ext; + +import java.util.stream.IntStream; +import org.redkale.convert.Reader; +import org.redkale.convert.SimpledCoder; +import org.redkale.convert.Writer; + +/** + * int[] 鐨凷impledCoder瀹炵幇 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * @param Writer杈撳嚭鐨勫瓙绫诲瀷 + */ +public final class IntArraySimpledCoder extends SimpledCoder { + + public static final IntArraySimpledCoder instance = new IntArraySimpledCoder(); + + @Override + public void convertTo(W out, int[] values) { + if (values == null) { + out.writeNull(); + return; + } + if (out.writeArrayB(values.length, this, IntSimpledCoder.instance, values) < 0) { + boolean flag = false; + for (int v : values) { + if (flag) out.writeArrayMark(); + out.writeInt(v); + flag = true; + } + } + out.writeArrayE(); + } + + @Override + public int[] convertFrom(R in) { + int len = in.readArrayB(null, null, IntSimpledCoder.instance); + int contentLength = -1; + if (len == Reader.SIGN_NULL) return null; + if (len == Reader.SIGN_NOLENBUTBYTES) { + contentLength = in.readMemberContentLength(null, IntSimpledCoder.instance); + len = Reader.SIGN_NOLENGTH; + } + if (len == Reader.SIGN_NOLENGTH) { + int size = 0; + int[] data = new int[8]; + int startPosition = in.position(); + while (in.hasNext(startPosition, contentLength)) { + if (size >= data.length) { + int[] newdata = new int[data.length + 4]; + System.arraycopy(data, 0, newdata, 0, size); + data = newdata; + } + data[size++] = in.readInt(); + } + in.readArrayE(); + int[] newdata = new int[size]; + System.arraycopy(data, 0, newdata, 0, size); + return newdata; + } else { + int[] values = new int[len]; + for (int i = 0; i < values.length; i++) { + values[i] = in.readInt(); + } + in.readArrayE(); + return values; + } + } + + public final static class IntStreamSimpledCoder extends SimpledCoder { + + public static final IntStreamSimpledCoder instance = new IntStreamSimpledCoder(); + + @Override + @SuppressWarnings("unchecked") + public void convertTo(W out, IntStream values) { + if (values == null) { + out.writeNull(); + return; + } + IntArraySimpledCoder.instance.convertTo(out, values.toArray()); + } + + @Override + @SuppressWarnings("unchecked") + public IntStream convertFrom(R in) { + int[] value = IntArraySimpledCoder.instance.convertFrom(in); + return value == null ? null : IntStream.of(value); + } + + } +} diff --git a/src/main/java/org/redkale/convert/ext/IntSimpledCoder.java b/src/main/java/org/redkale/convert/ext/IntSimpledCoder.java index de9368807..c7889ec27 100644 --- a/src/main/java/org/redkale/convert/ext/IntSimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/IntSimpledCoder.java @@ -1,34 +1,34 @@ -/* - * 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.convert.ext; - -import org.redkale.convert.Reader; -import org.redkale.convert.SimpledCoder; -import org.redkale.convert.Writer; - -/** - * int 鐨凷impledCoder瀹炵幇 - * - *

璇︽儏瑙: https://redkale.org - * @author zhangjx - * @param Reader杈撳叆鐨勫瓙绫诲瀷 - * @param Writer杈撳嚭鐨勫瓙绫诲瀷 - */ -public final class IntSimpledCoder extends SimpledCoder { - - public static final IntSimpledCoder instance = new IntSimpledCoder(); - - @Override - public void convertTo(W out, Integer value) { - out.writeInt(value); - } - - @Override - public Integer convertFrom(R in) { - return in.readInt(); - } - -} +/* + * 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.convert.ext; + +import org.redkale.convert.Reader; +import org.redkale.convert.SimpledCoder; +import org.redkale.convert.Writer; + +/** + * int 鐨凷impledCoder瀹炵幇 + * + *

璇︽儏瑙: https://redkale.org + * @author zhangjx + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * @param Writer杈撳嚭鐨勫瓙绫诲瀷 + */ +public final class IntSimpledCoder extends SimpledCoder { + + public static final IntSimpledCoder instance = new IntSimpledCoder(); + + @Override + public void convertTo(W out, Integer value) { + out.writeInt(value); + } + + @Override + public Integer convertFrom(R in) { + return in.readInt(); + } + +} diff --git a/src/main/java/org/redkale/convert/ext/LongArraySimpledCoder.java b/src/main/java/org/redkale/convert/ext/LongArraySimpledCoder.java index 4921894c7..33a91961d 100644 --- a/src/main/java/org/redkale/convert/ext/LongArraySimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/LongArraySimpledCoder.java @@ -1,101 +1,101 @@ -/* - * 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.convert.ext; - -import java.util.stream.LongStream; -import org.redkale.convert.Reader; -import org.redkale.convert.SimpledCoder; -import org.redkale.convert.Writer; - -/** - * long[] 鐨凷impledCoder瀹炵幇 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Reader杈撳叆鐨勫瓙绫诲瀷 - * @param Writer杈撳嚭鐨勫瓙绫诲瀷 - */ -public final class LongArraySimpledCoder extends SimpledCoder { - - public static final LongArraySimpledCoder instance = new LongArraySimpledCoder(); - - @Override - public void convertTo(W out, long[] values) { - if (values == null) { - out.writeNull(); - return; - } - if (out.writeArrayB(values.length, this, LongSimpledCoder.instance, values) < 0) { - boolean flag = false; - for (long v : values) { - if (flag) out.writeArrayMark(); - out.writeLong(v); - flag = true; - } - } - out.writeArrayE(); - } - - @Override - public long[] convertFrom(R in) { - int len = in.readArrayB(null, null, LongSimpledCoder.instance); - int contentLength = -1; - if (len == Reader.SIGN_NULL) return null; - if (len == Reader.SIGN_NOLENBUTBYTES) { - contentLength = in.readMemberContentLength(null, LongSimpledCoder.instance); - len = Reader.SIGN_NOLENGTH; - } - if (len == Reader.SIGN_NOLENGTH) { - int size = 0; - long[] data = new long[8]; - int startPosition = in.position(); - while (in.hasNext(startPosition, contentLength)) { - if (size >= data.length) { - long[] newdata = new long[data.length + 4]; - System.arraycopy(data, 0, newdata, 0, size); - data = newdata; - } - data[size++] = in.readLong(); - } - in.readArrayE(); - long[] newdata = new long[size]; - System.arraycopy(data, 0, newdata, 0, size); - return newdata; - } else { - long[] values = new long[len]; - for (int i = 0; i < values.length; i++) { - values[i] = in.readLong(); - } - in.readArrayE(); - return values; - } - } - - public final static class LongStreamSimpledCoder extends SimpledCoder { - - public static final LongStreamSimpledCoder instance = new LongStreamSimpledCoder(); - - @Override - @SuppressWarnings("unchecked") - public void convertTo(W out, LongStream values) { - if (values == null) { - out.writeNull(); - return; - } - LongArraySimpledCoder.instance.convertTo(out, values.toArray()); - } - - @Override - @SuppressWarnings("unchecked") - public LongStream convertFrom(R in) { - long[] value = LongArraySimpledCoder.instance.convertFrom(in); - return value == null ? null : LongStream.of(value); - } - - } -} +/* + * 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.convert.ext; + +import java.util.stream.LongStream; +import org.redkale.convert.Reader; +import org.redkale.convert.SimpledCoder; +import org.redkale.convert.Writer; + +/** + * long[] 鐨凷impledCoder瀹炵幇 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * @param Writer杈撳嚭鐨勫瓙绫诲瀷 + */ +public final class LongArraySimpledCoder extends SimpledCoder { + + public static final LongArraySimpledCoder instance = new LongArraySimpledCoder(); + + @Override + public void convertTo(W out, long[] values) { + if (values == null) { + out.writeNull(); + return; + } + if (out.writeArrayB(values.length, this, LongSimpledCoder.instance, values) < 0) { + boolean flag = false; + for (long v : values) { + if (flag) out.writeArrayMark(); + out.writeLong(v); + flag = true; + } + } + out.writeArrayE(); + } + + @Override + public long[] convertFrom(R in) { + int len = in.readArrayB(null, null, LongSimpledCoder.instance); + int contentLength = -1; + if (len == Reader.SIGN_NULL) return null; + if (len == Reader.SIGN_NOLENBUTBYTES) { + contentLength = in.readMemberContentLength(null, LongSimpledCoder.instance); + len = Reader.SIGN_NOLENGTH; + } + if (len == Reader.SIGN_NOLENGTH) { + int size = 0; + long[] data = new long[8]; + int startPosition = in.position(); + while (in.hasNext(startPosition, contentLength)) { + if (size >= data.length) { + long[] newdata = new long[data.length + 4]; + System.arraycopy(data, 0, newdata, 0, size); + data = newdata; + } + data[size++] = in.readLong(); + } + in.readArrayE(); + long[] newdata = new long[size]; + System.arraycopy(data, 0, newdata, 0, size); + return newdata; + } else { + long[] values = new long[len]; + for (int i = 0; i < values.length; i++) { + values[i] = in.readLong(); + } + in.readArrayE(); + return values; + } + } + + public final static class LongStreamSimpledCoder extends SimpledCoder { + + public static final LongStreamSimpledCoder instance = new LongStreamSimpledCoder(); + + @Override + @SuppressWarnings("unchecked") + public void convertTo(W out, LongStream values) { + if (values == null) { + out.writeNull(); + return; + } + LongArraySimpledCoder.instance.convertTo(out, values.toArray()); + } + + @Override + @SuppressWarnings("unchecked") + public LongStream convertFrom(R in) { + long[] value = LongArraySimpledCoder.instance.convertFrom(in); + return value == null ? null : LongStream.of(value); + } + + } +} diff --git a/src/main/java/org/redkale/convert/ext/LongSimpledCoder.java b/src/main/java/org/redkale/convert/ext/LongSimpledCoder.java index 125f296b6..b335564da 100644 --- a/src/main/java/org/redkale/convert/ext/LongSimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/LongSimpledCoder.java @@ -1,35 +1,35 @@ -/* - * 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.convert.ext; - -import org.redkale.convert.Reader; -import org.redkale.convert.SimpledCoder; -import org.redkale.convert.Writer; - -/** - * long 鐨凷impledCoder瀹炵幇 - * - *

璇︽儏瑙: https://redkale.org - * @author zhangjx - * @param Reader杈撳叆鐨勫瓙绫诲瀷 - * @param Writer杈撳嚭鐨勫瓙绫诲瀷 - */ -public final class LongSimpledCoder extends SimpledCoder { - - public static final LongSimpledCoder instance = new LongSimpledCoder(); - - @Override - public void convertTo(W out, Long value) { - out.writeLong(value); - } - - @Override - public Long convertFrom(R in) { - return in.readLong(); - } - -} +/* + * 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.convert.ext; + +import org.redkale.convert.Reader; +import org.redkale.convert.SimpledCoder; +import org.redkale.convert.Writer; + +/** + * long 鐨凷impledCoder瀹炵幇 + * + *

璇︽儏瑙: https://redkale.org + * @author zhangjx + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * @param Writer杈撳嚭鐨勫瓙绫诲瀷 + */ +public final class LongSimpledCoder extends SimpledCoder { + + public static final LongSimpledCoder instance = new LongSimpledCoder(); + + @Override + public void convertTo(W out, Long value) { + out.writeLong(value); + } + + @Override + public Long convertFrom(R in) { + return in.readLong(); + } + +} diff --git a/src/main/java/org/redkale/convert/ext/NumberSimpledCoder.java b/src/main/java/org/redkale/convert/ext/NumberSimpledCoder.java index e3fd4d544..ae628333d 100644 --- a/src/main/java/org/redkale/convert/ext/NumberSimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/NumberSimpledCoder.java @@ -1,36 +1,36 @@ -/* - * 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.convert.ext; - -import org.redkale.convert.Reader; -import org.redkale.convert.SimpledCoder; -import org.redkale.convert.Writer; - -/** - * Number 鐨凷impledCoder瀹炵幇 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Reader杈撳叆鐨勫瓙绫诲瀷 - * @param Writer杈撳嚭鐨勫瓙绫诲瀷 - */ -public final class NumberSimpledCoder extends SimpledCoder { - - public static final NumberSimpledCoder instance = new NumberSimpledCoder(); - - @Override - public void convertTo(W out, Number value) { - out.writeLong(value == null ? 0L : value.longValue()); - } - - @Override - public Number convertFrom(R in) { - return in.readLong(); - } - -} +/* + * 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.convert.ext; + +import org.redkale.convert.Reader; +import org.redkale.convert.SimpledCoder; +import org.redkale.convert.Writer; + +/** + * Number 鐨凷impledCoder瀹炵幇 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * @param Writer杈撳嚭鐨勫瓙绫诲瀷 + */ +public final class NumberSimpledCoder extends SimpledCoder { + + public static final NumberSimpledCoder instance = new NumberSimpledCoder(); + + @Override + public void convertTo(W out, Number value) { + out.writeLong(value == null ? 0L : value.longValue()); + } + + @Override + public Number convertFrom(R in) { + return in.readLong(); + } + +} diff --git a/src/main/java/org/redkale/convert/ext/PatternSimpledCoder.java b/src/main/java/org/redkale/convert/ext/PatternSimpledCoder.java index 70b6459fd..9d6daa5e2 100644 --- a/src/main/java/org/redkale/convert/ext/PatternSimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/PatternSimpledCoder.java @@ -1,40 +1,40 @@ -/* - * 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.convert.ext; - -import java.util.regex.*; -import org.redkale.convert.*; - -/** - * Pattern 鐨凷impledCoder瀹炵幇 - * - *

璇︽儏瑙: https://redkale.org - * @author zhangjx - * @param Reader杈撳叆鐨勫瓙绫诲瀷 - * @param Writer杈撳嚭鐨勫瓙绫诲瀷 - */ -public class PatternSimpledCoder extends SimpledCoder { - - public static final PatternSimpledCoder instance = new PatternSimpledCoder(); - - @Override - public void convertTo(W out, Pattern value) { - if (value == null) { - out.writeNull(); - } else { - out.writeString(value.flags() + "," + value.pattern()); - } - } - - @Override - public Pattern convertFrom(R in) { - String value = in.readString(); - if (value == null) return null; - int pos = value.indexOf(','); - return Pattern.compile(value.substring(pos + 1), Integer.parseInt(value.substring(0, pos))); - } - -} +/* + * 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.convert.ext; + +import java.util.regex.*; +import org.redkale.convert.*; + +/** + * Pattern 鐨凷impledCoder瀹炵幇 + * + *

璇︽儏瑙: https://redkale.org + * @author zhangjx + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * @param Writer杈撳嚭鐨勫瓙绫诲瀷 + */ +public class PatternSimpledCoder extends SimpledCoder { + + public static final PatternSimpledCoder instance = new PatternSimpledCoder(); + + @Override + public void convertTo(W out, Pattern value) { + if (value == null) { + out.writeNull(); + } else { + out.writeString(value.flags() + "," + value.pattern()); + } + } + + @Override + public Pattern convertFrom(R in) { + String value = in.readString(); + if (value == null) return null; + int pos = value.indexOf(','); + return Pattern.compile(value.substring(pos + 1), Integer.parseInt(value.substring(0, pos))); + } + +} diff --git a/src/main/java/org/redkale/convert/ext/ShortArraySimpledCoder.java b/src/main/java/org/redkale/convert/ext/ShortArraySimpledCoder.java index eddb24ca2..9f2fda2b4 100644 --- a/src/main/java/org/redkale/convert/ext/ShortArraySimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/ShortArraySimpledCoder.java @@ -1,78 +1,78 @@ -/* - * 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.convert.ext; - -import org.redkale.convert.Reader; -import org.redkale.convert.SimpledCoder; -import org.redkale.convert.Writer; - -/** - * short[] 鐨凷impledCoder瀹炵幇 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Reader杈撳叆鐨勫瓙绫诲瀷 - * @param Writer杈撳嚭鐨勫瓙绫诲瀷 - */ -public final class ShortArraySimpledCoder extends SimpledCoder { - - public static final ShortArraySimpledCoder instance = new ShortArraySimpledCoder(); - - @Override - public void convertTo(W out, short[] values) { - if (values == null) { - out.writeNull(); - return; - } - if (out.writeArrayB(values.length, this, ShortSimpledCoder.instance, values) < 0) { - boolean flag = false; - for (short v : values) { - if (flag) out.writeArrayMark(); - out.writeShort(v); - flag = true; - } - } - out.writeArrayE(); - } - - @Override - public short[] convertFrom(R in) { - int len = in.readArrayB(null, null, ShortSimpledCoder.instance); - int contentLength = -1; - if (len == Reader.SIGN_NULL) return null; - if (len == Reader.SIGN_NOLENBUTBYTES) { - contentLength = in.readMemberContentLength(null, ShortSimpledCoder.instance); - len = Reader.SIGN_NOLENGTH; - } - if (len == Reader.SIGN_NOLENGTH) { - int size = 0; - short[] data = new short[8]; - int startPosition = in.position(); - while (in.hasNext(startPosition, contentLength)) { - if (size >= data.length) { - short[] newdata = new short[data.length + 4]; - System.arraycopy(data, 0, newdata, 0, size); - data = newdata; - } - data[size++] = in.readShort(); - } - in.readArrayE(); - short[] newdata = new short[size]; - System.arraycopy(data, 0, newdata, 0, size); - return newdata; - } else { - short[] values = new short[len]; - for (int i = 0; i < values.length; i++) { - values[i] = in.readShort(); - } - in.readArrayE(); - return values; - } - } - -} +/* + * 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.convert.ext; + +import org.redkale.convert.Reader; +import org.redkale.convert.SimpledCoder; +import org.redkale.convert.Writer; + +/** + * short[] 鐨凷impledCoder瀹炵幇 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * @param Writer杈撳嚭鐨勫瓙绫诲瀷 + */ +public final class ShortArraySimpledCoder extends SimpledCoder { + + public static final ShortArraySimpledCoder instance = new ShortArraySimpledCoder(); + + @Override + public void convertTo(W out, short[] values) { + if (values == null) { + out.writeNull(); + return; + } + if (out.writeArrayB(values.length, this, ShortSimpledCoder.instance, values) < 0) { + boolean flag = false; + for (short v : values) { + if (flag) out.writeArrayMark(); + out.writeShort(v); + flag = true; + } + } + out.writeArrayE(); + } + + @Override + public short[] convertFrom(R in) { + int len = in.readArrayB(null, null, ShortSimpledCoder.instance); + int contentLength = -1; + if (len == Reader.SIGN_NULL) return null; + if (len == Reader.SIGN_NOLENBUTBYTES) { + contentLength = in.readMemberContentLength(null, ShortSimpledCoder.instance); + len = Reader.SIGN_NOLENGTH; + } + if (len == Reader.SIGN_NOLENGTH) { + int size = 0; + short[] data = new short[8]; + int startPosition = in.position(); + while (in.hasNext(startPosition, contentLength)) { + if (size >= data.length) { + short[] newdata = new short[data.length + 4]; + System.arraycopy(data, 0, newdata, 0, size); + data = newdata; + } + data[size++] = in.readShort(); + } + in.readArrayE(); + short[] newdata = new short[size]; + System.arraycopy(data, 0, newdata, 0, size); + return newdata; + } else { + short[] values = new short[len]; + for (int i = 0; i < values.length; i++) { + values[i] = in.readShort(); + } + in.readArrayE(); + return values; + } + } + +} diff --git a/src/main/java/org/redkale/convert/ext/ShortSimpledCoder.java b/src/main/java/org/redkale/convert/ext/ShortSimpledCoder.java index 0b1487601..7df06aa64 100644 --- a/src/main/java/org/redkale/convert/ext/ShortSimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/ShortSimpledCoder.java @@ -1,34 +1,34 @@ -/* - * 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.convert.ext; - -import org.redkale.convert.Reader; -import org.redkale.convert.SimpledCoder; -import org.redkale.convert.Writer; - -/** - * short 鐨凷impledCoder瀹炵幇 - * - *

璇︽儏瑙: https://redkale.org - * @author zhangjx - * @param Reader杈撳叆鐨勫瓙绫诲瀷 - * @param Writer杈撳嚭鐨勫瓙绫诲瀷 - */ -public final class ShortSimpledCoder extends SimpledCoder { - - public static final ShortSimpledCoder instance = new ShortSimpledCoder(); - - @Override - public void convertTo(W out, Short value) { - out.writeShort(value); - } - - @Override - public Short convertFrom(R in) { - return in.readShort(); - } - -} +/* + * 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.convert.ext; + +import org.redkale.convert.Reader; +import org.redkale.convert.SimpledCoder; +import org.redkale.convert.Writer; + +/** + * short 鐨凷impledCoder瀹炵幇 + * + *

璇︽儏瑙: https://redkale.org + * @author zhangjx + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * @param Writer杈撳嚭鐨勫瓙绫诲瀷 + */ +public final class ShortSimpledCoder extends SimpledCoder { + + public static final ShortSimpledCoder instance = new ShortSimpledCoder(); + + @Override + public void convertTo(W out, Short value) { + out.writeShort(value); + } + + @Override + public Short convertFrom(R in) { + return in.readShort(); + } + +} diff --git a/src/main/java/org/redkale/convert/ext/StringArraySimpledCoder.java b/src/main/java/org/redkale/convert/ext/StringArraySimpledCoder.java index 04c55af05..23ba5382a 100644 --- a/src/main/java/org/redkale/convert/ext/StringArraySimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/StringArraySimpledCoder.java @@ -1,80 +1,80 @@ -/* - * 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.convert.ext; - -import org.redkale.convert.*; - -/** - * String[] 鐨凷impledCoder瀹炵幇 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Reader杈撳叆鐨勫瓙绫诲瀷 - * @param Writer杈撳嚭鐨勫瓙绫诲瀷 - */ -public final class StringArraySimpledCoder extends SimpledCoder { - - public static final StringArraySimpledCoder instance = new StringArraySimpledCoder(); - - @Override - public void convertTo(W out, String[] values) { - if (values == null) { - out.writeNull(); - return; - } - if (out.writeArrayB(values.length, this, StringSimpledCoder.instance, values) < 0) { - boolean flag = false; - for (String v : values) { - if (flag) out.writeArrayMark(); - out.writeString(v); - flag = true; - } - } - out.writeArrayE(); - } - - @Override - public String[] convertFrom(R in) { - return convertFrom(in, null); - } - - public String[] convertFrom(R in, DeMember member) { - int len = in.readArrayB(member, null, StringSimpledCoder.instance); - int contentLength = -1; - if (len == Reader.SIGN_NULL) return null; - if (len == Reader.SIGN_NOLENBUTBYTES) { - contentLength = in.readMemberContentLength(null, StringSimpledCoder.instance); - len = Reader.SIGN_NOLENGTH; - } - if (len == Reader.SIGN_NOLENGTH) { - int size = 0; - String[] data = new String[8]; - int startPosition = in.position(); - while (in.hasNext(startPosition, contentLength)) { - if (size >= data.length) { - String[] newdata = new String[data.length + 4]; - System.arraycopy(data, 0, newdata, 0, size); - data = newdata; - } - data[size++] = in.readString(); - } - in.readArrayE(); - String[] newdata = new String[size]; - System.arraycopy(data, 0, newdata, 0, size); - return newdata; - } else { - String[] values = new String[len]; - for (int i = 0; i < values.length; i++) { - values[i] = in.readString(); - } - in.readArrayE(); - return values; - } - } - -} +/* + * 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.convert.ext; + +import org.redkale.convert.*; + +/** + * String[] 鐨凷impledCoder瀹炵幇 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * @param Writer杈撳嚭鐨勫瓙绫诲瀷 + */ +public final class StringArraySimpledCoder extends SimpledCoder { + + public static final StringArraySimpledCoder instance = new StringArraySimpledCoder(); + + @Override + public void convertTo(W out, String[] values) { + if (values == null) { + out.writeNull(); + return; + } + if (out.writeArrayB(values.length, this, StringSimpledCoder.instance, values) < 0) { + boolean flag = false; + for (String v : values) { + if (flag) out.writeArrayMark(); + out.writeString(v); + flag = true; + } + } + out.writeArrayE(); + } + + @Override + public String[] convertFrom(R in) { + return convertFrom(in, null); + } + + public String[] convertFrom(R in, DeMember member) { + int len = in.readArrayB(member, null, StringSimpledCoder.instance); + int contentLength = -1; + if (len == Reader.SIGN_NULL) return null; + if (len == Reader.SIGN_NOLENBUTBYTES) { + contentLength = in.readMemberContentLength(null, StringSimpledCoder.instance); + len = Reader.SIGN_NOLENGTH; + } + if (len == Reader.SIGN_NOLENGTH) { + int size = 0; + String[] data = new String[8]; + int startPosition = in.position(); + while (in.hasNext(startPosition, contentLength)) { + if (size >= data.length) { + String[] newdata = new String[data.length + 4]; + System.arraycopy(data, 0, newdata, 0, size); + data = newdata; + } + data[size++] = in.readString(); + } + in.readArrayE(); + String[] newdata = new String[size]; + System.arraycopy(data, 0, newdata, 0, size); + return newdata; + } else { + String[] values = new String[len]; + for (int i = 0; i < values.length; i++) { + values[i] = in.readString(); + } + in.readArrayE(); + return values; + } + } + +} diff --git a/src/main/java/org/redkale/convert/ext/StringSimpledCoder.java b/src/main/java/org/redkale/convert/ext/StringSimpledCoder.java index 0e89478f5..2932d10c1 100644 --- a/src/main/java/org/redkale/convert/ext/StringSimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/StringSimpledCoder.java @@ -1,51 +1,51 @@ -/* - * 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.convert.ext; - -import org.redkale.convert.Reader; -import org.redkale.convert.SimpledCoder; -import org.redkale.convert.Writer; - -/** - * String 鐨凷impledCoder瀹炵幇 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Reader杈撳叆鐨勫瓙绫诲瀷 - * @param Writer杈撳嚭鐨勫瓙绫诲瀷 - */ -public final class StringSimpledCoder extends SimpledCoder { - - public static final StringSimpledCoder instance = new StringSimpledCoder(); - - @Override - public void convertTo(W out, String value) { - out.writeString(value); - } - - @Override - public String convertFrom(R in) { - return in.readString(); - } - - public final static class SmallStringSimpledCoder extends SimpledCoder { - - public static final SmallStringSimpledCoder instance = new SmallStringSimpledCoder(); - - @Override - public void convertTo(W out, String value) { - out.writeSmallString(value); - } - - @Override - public String convertFrom(R in) { - return in.readSmallString(); - } - - } -} +/* + * 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.convert.ext; + +import org.redkale.convert.Reader; +import org.redkale.convert.SimpledCoder; +import org.redkale.convert.Writer; + +/** + * String 鐨凷impledCoder瀹炵幇 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * @param Writer杈撳嚭鐨勫瓙绫诲瀷 + */ +public final class StringSimpledCoder extends SimpledCoder { + + public static final StringSimpledCoder instance = new StringSimpledCoder(); + + @Override + public void convertTo(W out, String value) { + out.writeString(value); + } + + @Override + public String convertFrom(R in) { + return in.readString(); + } + + public final static class SmallStringSimpledCoder extends SimpledCoder { + + public static final SmallStringSimpledCoder instance = new SmallStringSimpledCoder(); + + @Override + public void convertTo(W out, String value) { + out.writeSmallString(value); + } + + @Override + public String convertFrom(R in) { + return in.readSmallString(); + } + + } +} diff --git a/src/main/java/org/redkale/convert/ext/StringWrapperSimpledCoder.java b/src/main/java/org/redkale/convert/ext/StringWrapperSimpledCoder.java index 7d1a13522..ffe447786 100644 --- a/src/main/java/org/redkale/convert/ext/StringWrapperSimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/StringWrapperSimpledCoder.java @@ -1,35 +1,35 @@ -/* - * 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.convert.ext; - -import org.redkale.convert.*; -import org.redkale.util.StringWrapper; - -/** - * String 鐨凷impledCoder瀹炵幇 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Reader杈撳叆鐨勫瓙绫诲瀷 - * @param Writer杈撳嚭鐨勫瓙绫诲瀷 - */ -public final class StringWrapperSimpledCoder extends SimpledCoder { - - public static final StringWrapperSimpledCoder instance = new StringWrapperSimpledCoder(); - - @Override - public void convertTo(W out, StringWrapper value) { - out.writeWrapper(value); - } - - @Override - public StringWrapper convertFrom(R in) { - return new StringWrapper(in.readString()); - } - -} +/* + * 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.convert.ext; + +import org.redkale.convert.*; +import org.redkale.util.StringWrapper; + +/** + * String 鐨凷impledCoder瀹炵幇 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * @param Writer杈撳嚭鐨勫瓙绫诲瀷 + */ +public final class StringWrapperSimpledCoder extends SimpledCoder { + + public static final StringWrapperSimpledCoder instance = new StringWrapperSimpledCoder(); + + @Override + public void convertTo(W out, StringWrapper value) { + out.writeWrapper(value); + } + + @Override + public StringWrapper convertFrom(R in) { + return new StringWrapper(in.readString()); + } + +} diff --git a/src/main/java/org/redkale/convert/ext/ThrowableSimpledCoder.java b/src/main/java/org/redkale/convert/ext/ThrowableSimpledCoder.java index 66f98b4d2..1c872bcfb 100644 --- a/src/main/java/org/redkale/convert/ext/ThrowableSimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/ThrowableSimpledCoder.java @@ -1,40 +1,40 @@ -/* - * 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.convert.ext; - -import org.redkale.convert.*; - -/** - * 鏂囦欢 鐨凷impledCoder瀹炵幇 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Reader杈撳叆鐨勫瓙绫诲瀷 - * @param Writer杈撳嚭鐨勫瓙绫诲瀷 - */ -public class ThrowableSimpledCoder extends SimpledCoder { - - public static final ThrowableSimpledCoder instance = new ThrowableSimpledCoder(); - - @Override - public void convertTo(W out, Throwable value) { - if (value == null) { - out.writeNull(); - } else { - out.writeString(value.toString()); - } - } - - @Override - public Throwable convertFrom(R in) { - String value = in.readString(); - if (value == null) return null; - return new Exception(value); - } - -} +/* + * 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.convert.ext; + +import org.redkale.convert.*; + +/** + * 鏂囦欢 鐨凷impledCoder瀹炵幇 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * @param Writer杈撳嚭鐨勫瓙绫诲瀷 + */ +public class ThrowableSimpledCoder extends SimpledCoder { + + public static final ThrowableSimpledCoder instance = new ThrowableSimpledCoder(); + + @Override + public void convertTo(W out, Throwable value) { + if (value == null) { + out.writeNull(); + } else { + out.writeString(value.toString()); + } + } + + @Override + public Throwable convertFrom(R in) { + String value = in.readString(); + if (value == null) return null; + return new Exception(value); + } + +} diff --git a/src/main/java/org/redkale/convert/ext/TypeSimpledCoder.java b/src/main/java/org/redkale/convert/ext/TypeSimpledCoder.java index 530b0299a..70257d4ac 100644 --- a/src/main/java/org/redkale/convert/ext/TypeSimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/TypeSimpledCoder.java @@ -1,46 +1,46 @@ -/* - * 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.convert.ext; - -import org.redkale.convert.Reader; -import org.redkale.convert.Writer; -import org.redkale.convert.SimpledCoder; - -/** - * Type 鐨凷impledCoder瀹炵幇 鍙敮鎸乀ype鐨勫瓙绫籆lass - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Reader杈撳叆鐨勫瓙绫诲瀷 - * @param Writer杈撳嚭鐨勫瓙绫诲瀷 - */ -public class TypeSimpledCoder extends SimpledCoder { - - public static final TypeSimpledCoder instance = new TypeSimpledCoder(); - - @Override - public void convertTo(final W out, final Class value) { - if (value == null) { - out.writeNull(); - } else { - out.writeSmallString(value.getName()); - } - } - - @Override - public Class convertFrom(R in) { - String str = in.readSmallString(); - if (str == null) return null; - try { - return Thread.currentThread().getContextClassLoader().loadClass(str); - } catch (Throwable e) { - return null; - } - } - -} +/* + * 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.convert.ext; + +import org.redkale.convert.Reader; +import org.redkale.convert.Writer; +import org.redkale.convert.SimpledCoder; + +/** + * Type 鐨凷impledCoder瀹炵幇 鍙敮鎸乀ype鐨勫瓙绫籆lass + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * @param Writer杈撳嚭鐨勫瓙绫诲瀷 + */ +public class TypeSimpledCoder extends SimpledCoder { + + public static final TypeSimpledCoder instance = new TypeSimpledCoder(); + + @Override + public void convertTo(final W out, final Class value) { + if (value == null) { + out.writeNull(); + } else { + out.writeSmallString(value.getName()); + } + } + + @Override + public Class convertFrom(R in) { + String str = in.readSmallString(); + if (str == null) return null; + try { + return Thread.currentThread().getContextClassLoader().loadClass(str); + } catch (Throwable e) { + return null; + } + } + +} diff --git a/src/main/java/org/redkale/convert/ext/URISimpledCoder.java b/src/main/java/org/redkale/convert/ext/URISimpledCoder.java index 38a4a06cf..1376d2b5c 100644 --- a/src/main/java/org/redkale/convert/ext/URISimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/URISimpledCoder.java @@ -1,44 +1,44 @@ -/* - * 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.convert.ext; - -import java.net.*; -import org.redkale.convert.*; - -/** - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Reader杈撳叆鐨勫瓙绫诲瀷 - * @param Writer杈撳嚭鐨勫瓙绫诲瀷 - */ -public class URISimpledCoder extends SimpledCoder { - - public static final URLSimpledCoder instance = new URLSimpledCoder(); - - @Override - public void convertTo(final Writer out, final URI value) { - if (value == null) { - out.writeNull(); - } else { - out.writeString(value.toString()); - } - } - - @Override - public URI convertFrom(Reader in) { - final String str = in.readString(); - if (str == null) return null; - try { - return new URI(str); - } catch (Exception e) { - e.printStackTrace(); - return null; - } - } -} +/* + * 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.convert.ext; + +import java.net.*; +import org.redkale.convert.*; + +/** + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * @param Writer杈撳嚭鐨勫瓙绫诲瀷 + */ +public class URISimpledCoder extends SimpledCoder { + + public static final URLSimpledCoder instance = new URLSimpledCoder(); + + @Override + public void convertTo(final Writer out, final URI value) { + if (value == null) { + out.writeNull(); + } else { + out.writeString(value.toString()); + } + } + + @Override + public URI convertFrom(Reader in) { + final String str = in.readString(); + if (str == null) return null; + try { + return new URI(str); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } +} diff --git a/src/main/java/org/redkale/convert/ext/URLSimpledCoder.java b/src/main/java/org/redkale/convert/ext/URLSimpledCoder.java index 1408026fa..172f2733c 100644 --- a/src/main/java/org/redkale/convert/ext/URLSimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/URLSimpledCoder.java @@ -1,44 +1,44 @@ -/* - * 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.convert.ext; - -import java.net.*; -import org.redkale.convert.*; - -/** - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Reader杈撳叆鐨勫瓙绫诲瀷 - * @param Writer杈撳嚭鐨勫瓙绫诲瀷 - */ -public class URLSimpledCoder extends SimpledCoder { - - public static final URLSimpledCoder instance = new URLSimpledCoder(); - - @Override - public void convertTo(final Writer out, final URL value) { - if (value == null) { - out.writeNull(); - } else { - out.writeString(value.toString()); - } - } - - @Override - public URL convertFrom(Reader in) { - final String str = in.readString(); - if (str == null) return null; - try { - return new URL(str); - } catch (Exception e) { - e.printStackTrace(); - return null; - } - } -} +/* + * 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.convert.ext; + +import java.net.*; +import org.redkale.convert.*; + +/** + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * @param Writer杈撳嚭鐨勫瓙绫诲瀷 + */ +public class URLSimpledCoder extends SimpledCoder { + + public static final URLSimpledCoder instance = new URLSimpledCoder(); + + @Override + public void convertTo(final Writer out, final URL value) { + if (value == null) { + out.writeNull(); + } else { + out.writeString(value.toString()); + } + } + + @Override + public URL convertFrom(Reader in) { + final String str = in.readString(); + if (str == null) return null; + try { + return new URL(str); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } +} diff --git a/src/main/java/org/redkale/convert/ext/package-info.java b/src/main/java/org/redkale/convert/ext/package-info.java index 19c497bd6..3d10de53b 100644 --- a/src/main/java/org/redkale/convert/ext/package-info.java +++ b/src/main/java/org/redkale/convert/ext/package-info.java @@ -1,4 +1,4 @@ -/** - * Convert鐨勫熀鏈暟鎹殑Coder瀹炵幇 - */ -package org.redkale.convert.ext; +/** + * Convert鐨勫熀鏈暟鎹殑Coder瀹炵幇 + */ +package org.redkale.convert.ext; diff --git a/src/main/java/org/redkale/convert/json/JsonByteBufferReader.java b/src/main/java/org/redkale/convert/json/JsonByteBufferReader.java index 35f7ed015..698e786f9 100644 --- a/src/main/java/org/redkale/convert/json/JsonByteBufferReader.java +++ b/src/main/java/org/redkale/convert/json/JsonByteBufferReader.java @@ -1,387 +1,387 @@ -/* - * 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.convert.json; - -import java.nio.*; -import java.nio.charset.*; -import org.redkale.convert.*; -import static org.redkale.convert.Reader.*; - -/** - * 浠yteBuffer涓烘暟鎹浇浣撶殑JsonReader
- * - * 鍙敮鎸乁TF-8鏍煎紡 - * - * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public class JsonByteBufferReader extends JsonReader { - - private char currentChar; - - private ByteBuffer[] buffers; - - private int currentIndex = 0; - - private ByteBuffer currentBuffer; - - protected ConvertMask mask; - - protected JsonByteBufferReader(ConvertMask mask, ByteBuffer... buffers) { - this.mask = mask; - this.buffers = buffers; - if (buffers != null && buffers.length > 0) this.currentBuffer = buffers[currentIndex]; - } - - @Override - protected boolean recycle() { - super.recycle(); // this.position 鍒濆鍖栧间负-1 - this.currentIndex = 0; - this.currentChar = 0; - this.currentBuffer = null; - this.buffers = null; - this.mask = null; - return false; - } - - protected byte nextByte() { - if (this.currentBuffer.hasRemaining()) { - this.position++; - return mask == null ? this.currentBuffer.get() : mask.unmask(this.currentBuffer.get()); - } - for (;;) { - this.currentBuffer = this.buffers[++this.currentIndex]; - if (this.currentBuffer.hasRemaining()) { - this.position++; - return mask == null ? this.currentBuffer.get() : mask.unmask(this.currentBuffer.get()); - } - } - } - - /** - * 璇诲彇涓嬩竴涓瓧绗︼紝 涓嶈烦杩囩┖鐧藉瓧绗 - * - * @return 鏈夋晥瀛楃鎴栫┖鐧藉瓧绗 - */ - @Override - protected final char nextChar() { - return nextChar(null); - } - - protected final char nextChar(StringBuilder sb) { - if (currentChar != 0) { - char ch = currentChar; - this.currentChar = 0; - return ch; - } - if (this.currentBuffer != null) { - int remain = this.currentBuffer.remaining(); - if (remain == 0 && this.currentIndex + 1 >= this.buffers.length) return 0; - } - byte b = nextByte(); - if (b >= 0) {// 1 byte, 7 bits: 0xxxxxxx - return (char) b; - } else if ((b >> 5) == -2 && (b & 0x1e) != 0) { // 2 bytes, 11 bits: 110xxxxx 10xxxxxx - return (char) (((b << 6) ^ nextByte()) ^ (((byte) 0xC0 << 6) ^ ((byte) 0x80))); - } else if ((b >> 4) == -2) { // 3 bytes, 16 bits: 1110xxxx 10xxxxxx 10xxxxxx - return (char) ((b << 12) ^ (nextByte() << 6) ^ (nextByte() ^ (((byte) 0xE0 << 12) ^ ((byte) 0x80 << 6) ^ ((byte) 0x80)))); - } else if ((b >> 3) == -2) {// 4 bytes, 21 bits: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - int uc = ((b << 18) ^ (nextByte() << 12) ^ (nextByte() << 6) ^ (nextByte() ^ (((byte) 0xF0 << 18) ^ ((byte) 0x80 << 12) ^ ((byte) 0x80 << 6) ^ ((byte) 0x80)))); - if (sb != null) sb.append(Character.highSurrogate(uc)); - return Character.lowSurrogate(uc); - } else { - throw new RuntimeException(new UnmappableCharacterException(4)); - } - } - - /** - * 璇诲彇涓嬩竴涓湁鏁堝瓧绗 - * - * @return 鏈夋晥瀛楃 - */ - @Override - protected final char nextGoodChar() { - char c = nextChar(); - if (c > ' ' || c == 0) return c; // 0 琛ㄧずbuffer缁撳熬浜 - for (;;) { - c = nextChar(); - if (c > ' ' || c == 0) return c; - } - } - - /** - * 鍥為鏈鍚庤鍙栫殑瀛楃 - * - * @param ch 鍥為鐨勫瓧绗 - */ - @Override - protected final void backChar(char ch) { - this.currentChar = ch; - } - - /** - * 鍒ゆ柇涓嬩竴涓潪绌虹櫧瀛楃鏄惁涓簕 - * - * @return SIGN_NOLENGTH 鎴 SIGN_NULL - */ - @Override - public final String readObjectB(final Class clazz) { - char ch = nextGoodChar(); - if (ch == '{') return ""; - if (ch == 'n' && nextChar() == 'u' && nextChar() == 'l' && nextChar() == 'l') return null; - if (ch == 'N' && nextChar() == 'U' && nextChar() == 'L' && nextChar() == 'L') return null; - StringBuilder sb = new StringBuilder(); - sb.append(ch); - char one; - try { - while ((one = nextChar()) != 0) sb.append(one); - } catch (Exception e) { - } - throw new ConvertException("a json object text must begin with '{' (position = " + position + ") but '" + ch + "' in (" + sb + ")"); - } - - /** - * 鍒ゆ柇涓嬩竴涓潪绌虹櫧瀛楃鏄惁涓篬 - * - * @param member DeMember - * @param typevals byte[] - * @param decoder Decodeable - * - * @return SIGN_NOLENGTH 鎴 SIGN_NULL - */ - @Override - public final int readArrayB(DeMember member, byte[] typevals, Decodeable decoder) { - char ch = nextGoodChar(); - if (ch == '[' || ch == '{') return SIGN_NOLENGTH; - if (ch == 'n' && nextChar() == 'u' && nextChar() == 'l' && nextChar() == 'l') return SIGN_NULL; - if (ch == 'N' && nextChar() == 'U' && nextChar() == 'L' && nextChar() == 'L') return SIGN_NULL; - StringBuilder sb = new StringBuilder(); - sb.append(ch); - char one; - try { - while ((one = nextChar()) != 0) sb.append(one); - } catch (Exception e) { - } - throw new ConvertException("a json array text must begin with '[' (position = " + position + ") but '" + ch + "' in (" + sb + ")"); - } - - /** - * 鍒ゆ柇涓嬩竴涓潪绌虹櫧瀛楃鏄惁: - */ - @Override - public final void readBlank() { - char ch = nextGoodChar(); - if (ch == ':') return; - StringBuilder sb = new StringBuilder(); - sb.append(ch); - char one; - try { - while ((one = nextChar()) != 0) sb.append(one); - } catch (Exception e) { - } - throw new ConvertException("expected a ':' but '" + ch + "'(position = " + position + ") in (" + sb + ")"); - } - - /** - * 鍒ゆ柇瀵硅薄鏄惁瀛樺湪涓嬩竴涓睘鎬ф垨鑰呮暟缁勬槸鍚﹀瓨鍦ㄤ笅涓涓厓绱 - * - * @param startPosition 璧峰浣嶇疆 - * @param contentLength 鍐呭澶у皬锛 涓嶇‘瀹氱殑浼-1 - * - * @return 鏄惁瀛樺湪 - */ - @Override - public boolean hasNext(int startPosition, int contentLength) { - char ch = nextGoodChar(); - if (ch == ',') return true; - if (ch == '}' || ch == ']' || ch == 0) return false; - backChar(ch); // { [ 浜ょ敱 readObjectB 鎴 readMapB 鎴 readArrayB 璇诲彇 - return true; - } - - /** - * 璇诲彇灏忓瓧绗︿覆 - * - * @return String鍊 - */ - @Override - public final String readSmallString() { - char ch = nextGoodChar(); - if (ch == 0) return null; - final StringBuilder sb = new StringBuilder(); - if (ch == '"' || ch == '\'') { - final char quote = ch; - for (;;) { - ch = nextChar(sb); - if (ch == '\\') { - char c = nextChar(sb); - switch (c) { - case '"': - case '\'': - case '\\': - case '/': - sb.append(c); - break; - case 'n': - sb.append('\n'); - break; - case 'r': - sb.append('\r'); - break; - case 'u': - sb.append((char) Integer.parseInt(new String(new char[]{nextChar(), nextChar(), nextChar(), nextChar()}), 16)); - break; - case 't': - sb.append('\t'); - break; - case 'b': - sb.append('\b'); - break; - case 'f': - sb.append('\f'); - break; - default: - throw new ConvertException("illegal escape(" + c + ") (position = " + this.position + ")"); - } - } else if (ch == quote || ch == 0) { - break; - } else { - sb.append(ch); - } - } - return sb.toString(); - } else { - sb.append(ch); - for (;;) { - ch = nextChar(sb); - if (ch == '\\') { - char c = nextChar(sb); - switch (c) { - case '"': - case '\'': - case '\\': - case '/': - sb.append(c); - break; - case 'n': - sb.append('\n'); - break; - case 'r': - sb.append('\r'); - break; - case 'u': - sb.append((char) Integer.parseInt(new String(new char[]{nextChar(), nextChar(), nextChar(), nextChar()}), 16)); - break; - case 't': - sb.append('\t'); - break; - case 'b': - sb.append('\b'); - break; - case 'f': - sb.append('\f'); - break; - default: - throw new ConvertException("illegal escape(" + c + ") (position = " + this.position + ")"); - } - } else if (ch == ',' || ch == ']' || ch == '}' || ch <= ' ' || ch == ':') { // ch <= ' ' 鍖呭惈 0 - backChar(ch); - break; - } else { - sb.append(ch); - } - } - String rs = sb.toString(); - return "null".equalsIgnoreCase(rs) ? null : rs; - } - } - - /** - * 璇诲彇涓涓猧nt鍊 - * - * @return int鍊 - */ - @Override - public final int readInt() { - char firstchar = nextGoodChar(); - boolean quote = false; - if (firstchar == '"' || firstchar == '\'') { - quote = true; - firstchar = nextGoodChar(); - if (firstchar == '"' || firstchar == '\'') return 0; - } - int value = 0; - final boolean negative = firstchar == '-'; - if (!negative) { - if (firstchar < '0' || firstchar > '9') throw new ConvertException("illegal escape(" + firstchar + ") (position = " + position + ")"); - value = firstchar - '0'; - } - for (;;) { - char ch = nextChar(); - if (ch == 0) break; - if (ch >= '0' && ch <= '9') { - value = (value << 3) + (value << 1) + (ch - '0'); - } else if (ch == '"' || ch == '\'') { - } else if (quote && ch <= ' ') { - } else if (ch == ',' || ch == '}' || ch == ']' || ch <= ' ' || ch == ':') { - backChar(ch); - break; - } else { - throw new ConvertException("illegal escape(" + ch + ") (position = " + position + ")"); - } - } - return negative ? -value : value; - } - - /** - * 璇诲彇涓涓猯ong鍊 - * - * @return long鍊 - */ - @Override - public final long readLong() { - char firstchar = nextGoodChar(); - boolean quote = false; - if (firstchar == '"' || firstchar == '\'') { - quote = true; - firstchar = nextGoodChar(); - if (firstchar == '"' || firstchar == '\'') return 0L; - } - long value = 0; - final boolean negative = firstchar == '-'; - if (!negative) { - if (firstchar < '0' || firstchar > '9') throw new ConvertException("illegal escape(" + firstchar + ") (position = " + position + ")"); - value = firstchar - '0'; - } - for (;;) { - char ch = nextChar(); - if (ch == 0) break; - if (ch >= '0' && ch <= '9') { - value = (value << 3) + (value << 1) + (ch - '0'); - } else if (ch == '"' || ch == '\'') { - } else if (quote && ch <= ' ') { - } else if (ch == ',' || ch == '}' || ch == ']' || ch <= ' ' || ch == ':') { - backChar(ch); - break; - } else { - throw new ConvertException("illegal escape(" + ch + ") (position = " + position + ")"); - } - } - return negative ? -value : value; - } - - /** - * 璇诲彇瀛楃涓诧紝 蹇呴』鏄"鎴栬'鍖呭洿鐨勫瓧绗︿覆鍊 - * - * @return String鍊 - */ - @Override - public final String readString() { - return readSmallString(); - } - -} +/* + * 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.convert.json; + +import java.nio.*; +import java.nio.charset.*; +import org.redkale.convert.*; +import static org.redkale.convert.Reader.*; + +/** + * 浠yteBuffer涓烘暟鎹浇浣撶殑JsonReader
+ * + * 鍙敮鎸乁TF-8鏍煎紡 + * + * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public class JsonByteBufferReader extends JsonReader { + + private char currentChar; + + private ByteBuffer[] buffers; + + private int currentIndex = 0; + + private ByteBuffer currentBuffer; + + protected ConvertMask mask; + + protected JsonByteBufferReader(ConvertMask mask, ByteBuffer... buffers) { + this.mask = mask; + this.buffers = buffers; + if (buffers != null && buffers.length > 0) this.currentBuffer = buffers[currentIndex]; + } + + @Override + protected boolean recycle() { + super.recycle(); // this.position 鍒濆鍖栧间负-1 + this.currentIndex = 0; + this.currentChar = 0; + this.currentBuffer = null; + this.buffers = null; + this.mask = null; + return false; + } + + protected byte nextByte() { + if (this.currentBuffer.hasRemaining()) { + this.position++; + return mask == null ? this.currentBuffer.get() : mask.unmask(this.currentBuffer.get()); + } + for (;;) { + this.currentBuffer = this.buffers[++this.currentIndex]; + if (this.currentBuffer.hasRemaining()) { + this.position++; + return mask == null ? this.currentBuffer.get() : mask.unmask(this.currentBuffer.get()); + } + } + } + + /** + * 璇诲彇涓嬩竴涓瓧绗︼紝 涓嶈烦杩囩┖鐧藉瓧绗 + * + * @return 鏈夋晥瀛楃鎴栫┖鐧藉瓧绗 + */ + @Override + protected final char nextChar() { + return nextChar(null); + } + + protected final char nextChar(StringBuilder sb) { + if (currentChar != 0) { + char ch = currentChar; + this.currentChar = 0; + return ch; + } + if (this.currentBuffer != null) { + int remain = this.currentBuffer.remaining(); + if (remain == 0 && this.currentIndex + 1 >= this.buffers.length) return 0; + } + byte b = nextByte(); + if (b >= 0) {// 1 byte, 7 bits: 0xxxxxxx + return (char) b; + } else if ((b >> 5) == -2 && (b & 0x1e) != 0) { // 2 bytes, 11 bits: 110xxxxx 10xxxxxx + return (char) (((b << 6) ^ nextByte()) ^ (((byte) 0xC0 << 6) ^ ((byte) 0x80))); + } else if ((b >> 4) == -2) { // 3 bytes, 16 bits: 1110xxxx 10xxxxxx 10xxxxxx + return (char) ((b << 12) ^ (nextByte() << 6) ^ (nextByte() ^ (((byte) 0xE0 << 12) ^ ((byte) 0x80 << 6) ^ ((byte) 0x80)))); + } else if ((b >> 3) == -2) {// 4 bytes, 21 bits: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + int uc = ((b << 18) ^ (nextByte() << 12) ^ (nextByte() << 6) ^ (nextByte() ^ (((byte) 0xF0 << 18) ^ ((byte) 0x80 << 12) ^ ((byte) 0x80 << 6) ^ ((byte) 0x80)))); + if (sb != null) sb.append(Character.highSurrogate(uc)); + return Character.lowSurrogate(uc); + } else { + throw new RuntimeException(new UnmappableCharacterException(4)); + } + } + + /** + * 璇诲彇涓嬩竴涓湁鏁堝瓧绗 + * + * @return 鏈夋晥瀛楃 + */ + @Override + protected final char nextGoodChar() { + char c = nextChar(); + if (c > ' ' || c == 0) return c; // 0 琛ㄧずbuffer缁撳熬浜 + for (;;) { + c = nextChar(); + if (c > ' ' || c == 0) return c; + } + } + + /** + * 鍥為鏈鍚庤鍙栫殑瀛楃 + * + * @param ch 鍥為鐨勫瓧绗 + */ + @Override + protected final void backChar(char ch) { + this.currentChar = ch; + } + + /** + * 鍒ゆ柇涓嬩竴涓潪绌虹櫧瀛楃鏄惁涓簕 + * + * @return SIGN_NOLENGTH 鎴 SIGN_NULL + */ + @Override + public final String readObjectB(final Class clazz) { + char ch = nextGoodChar(); + if (ch == '{') return ""; + if (ch == 'n' && nextChar() == 'u' && nextChar() == 'l' && nextChar() == 'l') return null; + if (ch == 'N' && nextChar() == 'U' && nextChar() == 'L' && nextChar() == 'L') return null; + StringBuilder sb = new StringBuilder(); + sb.append(ch); + char one; + try { + while ((one = nextChar()) != 0) sb.append(one); + } catch (Exception e) { + } + throw new ConvertException("a json object text must begin with '{' (position = " + position + ") but '" + ch + "' in (" + sb + ")"); + } + + /** + * 鍒ゆ柇涓嬩竴涓潪绌虹櫧瀛楃鏄惁涓篬 + * + * @param member DeMember + * @param typevals byte[] + * @param decoder Decodeable + * + * @return SIGN_NOLENGTH 鎴 SIGN_NULL + */ + @Override + public final int readArrayB(DeMember member, byte[] typevals, Decodeable decoder) { + char ch = nextGoodChar(); + if (ch == '[' || ch == '{') return SIGN_NOLENGTH; + if (ch == 'n' && nextChar() == 'u' && nextChar() == 'l' && nextChar() == 'l') return SIGN_NULL; + if (ch == 'N' && nextChar() == 'U' && nextChar() == 'L' && nextChar() == 'L') return SIGN_NULL; + StringBuilder sb = new StringBuilder(); + sb.append(ch); + char one; + try { + while ((one = nextChar()) != 0) sb.append(one); + } catch (Exception e) { + } + throw new ConvertException("a json array text must begin with '[' (position = " + position + ") but '" + ch + "' in (" + sb + ")"); + } + + /** + * 鍒ゆ柇涓嬩竴涓潪绌虹櫧瀛楃鏄惁: + */ + @Override + public final void readBlank() { + char ch = nextGoodChar(); + if (ch == ':') return; + StringBuilder sb = new StringBuilder(); + sb.append(ch); + char one; + try { + while ((one = nextChar()) != 0) sb.append(one); + } catch (Exception e) { + } + throw new ConvertException("expected a ':' but '" + ch + "'(position = " + position + ") in (" + sb + ")"); + } + + /** + * 鍒ゆ柇瀵硅薄鏄惁瀛樺湪涓嬩竴涓睘鎬ф垨鑰呮暟缁勬槸鍚﹀瓨鍦ㄤ笅涓涓厓绱 + * + * @param startPosition 璧峰浣嶇疆 + * @param contentLength 鍐呭澶у皬锛 涓嶇‘瀹氱殑浼-1 + * + * @return 鏄惁瀛樺湪 + */ + @Override + public boolean hasNext(int startPosition, int contentLength) { + char ch = nextGoodChar(); + if (ch == ',') return true; + if (ch == '}' || ch == ']' || ch == 0) return false; + backChar(ch); // { [ 浜ょ敱 readObjectB 鎴 readMapB 鎴 readArrayB 璇诲彇 + return true; + } + + /** + * 璇诲彇灏忓瓧绗︿覆 + * + * @return String鍊 + */ + @Override + public final String readSmallString() { + char ch = nextGoodChar(); + if (ch == 0) return null; + final StringBuilder sb = new StringBuilder(); + if (ch == '"' || ch == '\'') { + final char quote = ch; + for (;;) { + ch = nextChar(sb); + if (ch == '\\') { + char c = nextChar(sb); + switch (c) { + case '"': + case '\'': + case '\\': + case '/': + sb.append(c); + break; + case 'n': + sb.append('\n'); + break; + case 'r': + sb.append('\r'); + break; + case 'u': + sb.append((char) Integer.parseInt(new String(new char[]{nextChar(), nextChar(), nextChar(), nextChar()}), 16)); + break; + case 't': + sb.append('\t'); + break; + case 'b': + sb.append('\b'); + break; + case 'f': + sb.append('\f'); + break; + default: + throw new ConvertException("illegal escape(" + c + ") (position = " + this.position + ")"); + } + } else if (ch == quote || ch == 0) { + break; + } else { + sb.append(ch); + } + } + return sb.toString(); + } else { + sb.append(ch); + for (;;) { + ch = nextChar(sb); + if (ch == '\\') { + char c = nextChar(sb); + switch (c) { + case '"': + case '\'': + case '\\': + case '/': + sb.append(c); + break; + case 'n': + sb.append('\n'); + break; + case 'r': + sb.append('\r'); + break; + case 'u': + sb.append((char) Integer.parseInt(new String(new char[]{nextChar(), nextChar(), nextChar(), nextChar()}), 16)); + break; + case 't': + sb.append('\t'); + break; + case 'b': + sb.append('\b'); + break; + case 'f': + sb.append('\f'); + break; + default: + throw new ConvertException("illegal escape(" + c + ") (position = " + this.position + ")"); + } + } else if (ch == ',' || ch == ']' || ch == '}' || ch <= ' ' || ch == ':') { // ch <= ' ' 鍖呭惈 0 + backChar(ch); + break; + } else { + sb.append(ch); + } + } + String rs = sb.toString(); + return "null".equalsIgnoreCase(rs) ? null : rs; + } + } + + /** + * 璇诲彇涓涓猧nt鍊 + * + * @return int鍊 + */ + @Override + public final int readInt() { + char firstchar = nextGoodChar(); + boolean quote = false; + if (firstchar == '"' || firstchar == '\'') { + quote = true; + firstchar = nextGoodChar(); + if (firstchar == '"' || firstchar == '\'') return 0; + } + int value = 0; + final boolean negative = firstchar == '-'; + if (!negative) { + if (firstchar < '0' || firstchar > '9') throw new ConvertException("illegal escape(" + firstchar + ") (position = " + position + ")"); + value = firstchar - '0'; + } + for (;;) { + char ch = nextChar(); + if (ch == 0) break; + if (ch >= '0' && ch <= '9') { + value = (value << 3) + (value << 1) + (ch - '0'); + } else if (ch == '"' || ch == '\'') { + } else if (quote && ch <= ' ') { + } else if (ch == ',' || ch == '}' || ch == ']' || ch <= ' ' || ch == ':') { + backChar(ch); + break; + } else { + throw new ConvertException("illegal escape(" + ch + ") (position = " + position + ")"); + } + } + return negative ? -value : value; + } + + /** + * 璇诲彇涓涓猯ong鍊 + * + * @return long鍊 + */ + @Override + public final long readLong() { + char firstchar = nextGoodChar(); + boolean quote = false; + if (firstchar == '"' || firstchar == '\'') { + quote = true; + firstchar = nextGoodChar(); + if (firstchar == '"' || firstchar == '\'') return 0L; + } + long value = 0; + final boolean negative = firstchar == '-'; + if (!negative) { + if (firstchar < '0' || firstchar > '9') throw new ConvertException("illegal escape(" + firstchar + ") (position = " + position + ")"); + value = firstchar - '0'; + } + for (;;) { + char ch = nextChar(); + if (ch == 0) break; + if (ch >= '0' && ch <= '9') { + value = (value << 3) + (value << 1) + (ch - '0'); + } else if (ch == '"' || ch == '\'') { + } else if (quote && ch <= ' ') { + } else if (ch == ',' || ch == '}' || ch == ']' || ch <= ' ' || ch == ':') { + backChar(ch); + break; + } else { + throw new ConvertException("illegal escape(" + ch + ") (position = " + position + ")"); + } + } + return negative ? -value : value; + } + + /** + * 璇诲彇瀛楃涓诧紝 蹇呴』鏄"鎴栬'鍖呭洿鐨勫瓧绗︿覆鍊 + * + * @return String鍊 + */ + @Override + public final String readString() { + return readSmallString(); + } + +} diff --git a/src/main/java/org/redkale/convert/json/JsonByteBufferWriter.java b/src/main/java/org/redkale/convert/json/JsonByteBufferWriter.java index 3a3bcfc57..ebc0fd06a 100644 --- a/src/main/java/org/redkale/convert/json/JsonByteBufferWriter.java +++ b/src/main/java/org/redkale/convert/json/JsonByteBufferWriter.java @@ -1,721 +1,721 @@ -/* - * 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.convert.json; - -import java.nio.*; -import java.nio.charset.*; -import java.util.*; -import java.util.function.*; -import org.redkale.convert.*; -import org.redkale.util.*; - -/** - * 浠yteBuffer涓烘暟鎹浇浣撶殑JsonWriter - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public class JsonByteBufferWriter extends JsonWriter { - - private static final char[] CHARS_TUREVALUE = "true".toCharArray(); - - private static final char[] CHARS_FALSEVALUE = "false".toCharArray(); - - protected Charset charset; - - private final Supplier supplier; - - private ByteBuffer[] buffers; - - private int index; - - public JsonByteBufferWriter(boolean tiny, Supplier supplier) { - this(tiny, null, supplier); - } - - public JsonByteBufferWriter(boolean tiny, Charset charset, Supplier supplier) { - this.tiny = tiny; - this.charset = charset; - this.supplier = supplier; - } - - @Override - public JsonByteBufferWriter tiny(boolean tiny) { - this.tiny = tiny; - return this; - } - - @Override - protected boolean recycle() { - super.recycle(); - this.index = 0; - this.specify = null; - this.charset = null; - this.buffers = null; - return false; - } - - public ByteBuffer[] toBuffers() { - if (buffers == null) return new ByteBuffer[0]; - for (int i = index; i < this.buffers.length; i++) { - ByteBuffer buf = this.buffers[i]; - if (buf.position() != 0) buf.flip(); - } - return this.buffers; - } - - public int count() { - if (this.buffers == null) return 0; - int len = 0; - for (ByteBuffer buffer : buffers) { - len += buffer.remaining(); - } - return len; - } - - private int expand(final int byteLength) { - if (this.buffers == null) { - this.index = 0; - this.buffers = new ByteBuffer[]{supplier.get()}; - } - ByteBuffer buffer = this.buffers[index]; - if (!buffer.hasRemaining()) { - buffer.flip(); - buffer = supplier.get(); - this.buffers = Utility.append(this.buffers, buffer); - this.index++; - } - int len = buffer.remaining(); - int size = 0; - while (len < byteLength) { - buffer = supplier.get(); - this.buffers = Utility.append(this.buffers, buffer); - len += buffer.remaining(); - size++; - } - return size; - } - - @Override - public void writeTo(final char ch) { - if (ch > Byte.MAX_VALUE) throw new ConvertException("writeTo char(int.value = " + (int) ch + ") must be less 127"); - expand(1); - this.buffers[index].put((byte) ch); - } - - @Override - public void writeTo(final char[] chs, final int start, final int len) { - writeTo(-1, false, chs, start, len); - } - - @Override - public void writeTo(final byte ch) { //鍙兘鏄 0 - 127 鐨勫瓧绗 - expand(1); - this.buffers[index].put(ch); - } - - @Override - public void writeTo(final byte[] chs, final int start, final int len) { //鍙兘鏄 0 - 127 鐨勫瓧绗 - int expandsize = expand(len); - if (expandsize == 0) { // 鍙渶瑕佷竴涓猙uffer - this.buffers[index].put(chs, start, len); - } else { - ByteBuffer buffer = this.buffers[index]; - int remain = len; - int offset = start; - while (remain > 0) { - int bsize = Math.min(buffer.remaining(), remain); - buffer.put(chs, offset, bsize); - offset += bsize; - remain -= bsize; - if (remain < 1) break; - buffer = nextByteBuffer(); - } - } - } - - private void writeTo(int expandsize, final boolean quote, final char[] chs, final int start, final int len) { - int byteLength = quote ? 2 : 0; - ByteBuffer bb = null; - if (charset == null) { - byteLength += Utility.encodeUTF8Length(chs, start, len); - } else { - bb = charset.encode(CharBuffer.wrap(chs, start, len)); - byteLength += bb.remaining(); - } - if (expandsize < 0) expandsize = expand(byteLength); - if (expandsize == 0) { // 鍙渶瑕佷竴涓猙uffer - final ByteBuffer buffer = this.buffers[index]; - if (quote) buffer.put((byte) '"'); - - if (charset == null) { //UTF-8 - final int limit = start + len; - for (int i = start; i < limit; i++) { - char c = chs[i]; - if (c < 0x80) { - buffer.put((byte) c); - } else if (c < 0x800) { - buffer.put((byte) (0xc0 | (c >> 6))); - buffer.put((byte) (0x80 | (c & 0x3f))); - } else if (Character.isSurrogate(c)) { //杩炲彇涓や釜 - int uc = Character.toCodePoint(c, chs[i + 1]); - buffer.put((byte) (0xf0 | ((uc >> 18)))); - buffer.put((byte) (0x80 | ((uc >> 12) & 0x3f))); - buffer.put((byte) (0x80 | ((uc >> 6) & 0x3f))); - buffer.put((byte) (0x80 | (uc & 0x3f))); - i++; - } else { - buffer.put((byte) (0xe0 | ((c >> 12)))); - buffer.put((byte) (0x80 | ((c >> 6) & 0x3f))); - buffer.put((byte) (0x80 | (c & 0x3f))); - } - } - } else { - buffer.put(bb); - } - - if (quote) buffer.put((byte) '"'); - return; - } - ByteBuffer buffer = this.buffers[index]; - if (quote) { - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put((byte) '"'); - } - if (charset == null) { //UTF-8 - final int limit = start + len; - for (int i = start; i < limit; i++) { - char c = chs[i]; - if (c < 0x80) { - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put((byte) c); - } else if (c < 0x800) { - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put((byte) (0xc0 | (c >> 6))); - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put((byte) (0x80 | (c & 0x3f))); - } else if (Character.isSurrogate(c)) { //杩炲彇涓や釜 - int uc = Character.toCodePoint(c, chs[i + 1]); - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put((byte) (0xf0 | ((uc >> 18)))); - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put((byte) (0x80 | ((uc >> 12) & 0x3f))); - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put((byte) (0x80 | ((uc >> 6) & 0x3f))); - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put((byte) (0x80 | (uc & 0x3f))); - i++; - } else { - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put((byte) (0xe0 | ((c >> 12)))); - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put((byte) (0x80 | ((c >> 6) & 0x3f))); - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put((byte) (0x80 | (c & 0x3f))); - } - } - } else { - while (bb.hasRemaining()) { - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put(bb.get()); - } - } - if (quote) { - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put((byte) '"'); - } - } - - private ByteBuffer nextByteBuffer() { - this.buffers[this.index].flip(); - return this.buffers[++this.index]; - } - - protected static int encodeEscapeUTF8Length(final char[] text, final int start, final int len) { - char c; - int size = 0; - final char[] chs = text; - final int limit = start + len; - for (int i = start; i < limit; i++) { - c = chs[i]; - switch (c) { - case '\n': size += 2; - break; - case '\r': size += 2; - break; - case '\t': size += 2; - break; - case '\\': size += 2; - break; - case '"': size += 2; - break; - default: - size += (c < 0x80 ? 1 : (c < 0x800 || Character.isSurrogate(c) ? 2 : 3)); - break; - } - } - return size; - } - - /** - * 娉ㄦ剰锛 璇tring鍊间笉鑳戒负null涓斾笉浼氳繘琛岃浆涔夛紝 鍙敤浜庝笉鍚渶瑕佽浆涔夊瓧绗︾殑瀛楃涓诧紝渚嬪enum銆乨ouble銆丅igInteger杞崲鐨凷tring - * - * @param quote 鏄惁鍐欏叆鍙屽紩鍙 - * @param value String鍊 - */ - @Override - public void writeLatin1To(final boolean quote, final String value) { - byte[] bs = Utility.latin1ByteArray(value); - int expandsize = expand(bs.length + (quote ? 2 : 0)); - if (expandsize == 0) {// 鍙渶瑕佷竴涓猙uffer - final ByteBuffer buffer = this.buffers[index]; - if (quote) buffer.put((byte) '"'); - buffer.put(bs); - if (quote) buffer.put((byte) '"'); - } else { - ByteBuffer buffer = this.buffers[index]; - if (quote) { - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put((byte) '"'); - } - for (byte b : bs) { - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put(b); - } - if (quote) { - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put((byte) '"'); - } - } - } - - @Override - public void writeFieldShortValue(final byte[] fieldBytes, final short value) { - byte[] bs1 = fieldBytes; - byte[] bs2 = Utility.latin1ByteArray(String.valueOf(value)); - int expandsize = expand(bs1.length + bs2.length); - if (expandsize == 0) {// 鍙渶瑕佷竴涓猙uffer - final ByteBuffer buffer = this.buffers[index]; - buffer.put(bs1); - buffer.put(bs2); - } else { - ByteBuffer buffer = this.buffers[index]; - for (byte b : bs1) { - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put(b); - } - for (byte b : bs2) { - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put(b); - } - } - } - - @Override - public void writeFieldIntValue(final byte[] fieldBytes, final int value) { - byte[] bs1 = fieldBytes; - byte[] bs2 = Utility.latin1ByteArray(String.valueOf(value)); - int expandsize = expand(bs1.length + bs2.length); - if (expandsize == 0) {// 鍙渶瑕佷竴涓猙uffer - final ByteBuffer buffer = this.buffers[index]; - buffer.put(bs1); - buffer.put(bs2); - } else { - ByteBuffer buffer = this.buffers[index]; - for (byte b : bs1) { - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put(b); - } - for (byte b : bs2) { - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put(b); - } - } - } - - @Override - public void writeFieldLongValue(final byte[] fieldBytes, final long value) { - byte[] bs1 = fieldBytes; - byte[] bs2 = Utility.latin1ByteArray(String.valueOf(value)); - int expandsize = expand(bs1.length + bs2.length); - if (expandsize == 0) {// 鍙渶瑕佷竴涓猙uffer - final ByteBuffer buffer = this.buffers[index]; - buffer.put(bs1); - buffer.put(bs2); - } else { - ByteBuffer buffer = this.buffers[index]; - for (byte b : bs1) { - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put(b); - } - for (byte b : bs2) { - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put(b); - } - } - } - - @Override - public void writeFieldLatin1Value(final byte[] fieldBytes, final String value) { - byte[] bs1 = fieldBytes; - byte[] bs2 = Utility.latin1ByteArray(value); - int expandsize = expand(bs1.length + bs2.length + 2); - if (expandsize == 0) {// 鍙渶瑕佷竴涓猙uffer - final ByteBuffer buffer = this.buffers[index]; - buffer.put(bs1); - buffer.put((byte) '"'); - buffer.put(bs2); - buffer.put((byte) '"'); - } else { - ByteBuffer buffer = this.buffers[index]; - for (byte b : bs1) { - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put(b); - } - { - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put((byte) '"'); - } - for (byte b : bs2) { - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put(b); - } - { - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put((byte) '"'); - } - } - } - - @Override - public void writeLastFieldShortValue(final byte[] fieldBytes, final short value) { - byte[] bs1 = fieldBytes; - byte[] bs2 = Utility.latin1ByteArray(String.valueOf(value)); - int expandsize = expand(bs1.length + bs2.length + 1); - if (expandsize == 0) {// 鍙渶瑕佷竴涓猙uffer - final ByteBuffer buffer = this.buffers[index]; - buffer.put(bs1); - buffer.put(bs2); - buffer.put((byte) '}'); - } else { - ByteBuffer buffer = this.buffers[index]; - for (byte b : bs1) { - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put(b); - } - for (byte b : bs2) { - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put(b); - } - { - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put((byte) '}'); - } - } - } - - @Override - public void writeLastFieldIntValue(final byte[] fieldBytes, final int value) { - byte[] bs1 = fieldBytes; - byte[] bs2 = Utility.latin1ByteArray(String.valueOf(value)); - int expandsize = expand(bs1.length + bs2.length + 1); - if (expandsize == 0) {// 鍙渶瑕佷竴涓猙uffer - final ByteBuffer buffer = this.buffers[index]; - buffer.put(bs1); - buffer.put(bs2); - buffer.put((byte) '}'); - } else { - ByteBuffer buffer = this.buffers[index]; - for (byte b : bs1) { - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put(b); - } - for (byte b : bs2) { - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put(b); - } - { - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put((byte) '}'); - } - } - } - - @Override - public void writeLastFieldLongValue(final byte[] fieldBytes, final long value) { - byte[] bs1 = fieldBytes; - byte[] bs2 = Utility.latin1ByteArray(String.valueOf(value)); - int expandsize = expand(bs1.length + bs2.length + 1); - if (expandsize == 0) {// 鍙渶瑕佷竴涓猙uffer - final ByteBuffer buffer = this.buffers[index]; - buffer.put(bs1); - buffer.put(bs2); - buffer.put((byte) '}'); - } else { - ByteBuffer buffer = this.buffers[index]; - for (byte b : bs1) { - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put(b); - } - for (byte b : bs2) { - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put(b); - } - { - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put((byte) '}'); - } - } - } - - @Override - public void writeLastFieldLatin1Value(final byte[] fieldBytes, final String value) { - if (value == null || (tiny && value.isEmpty())) { - expand(1); - this.buffers[index].put((byte) '}'); - } else { - byte[] bs1 = fieldBytes; - byte[] bs2 = Utility.latin1ByteArray(value); - int expandsize = expand(bs1.length + bs2.length + 3); - if (expandsize == 0) {// 鍙渶瑕佷竴涓猙uffer - final ByteBuffer buffer = this.buffers[index]; - buffer.put(bs1); - buffer.put((byte) '"'); - buffer.put(bs2); - buffer.put((byte) '"'); - buffer.put((byte) '}'); - } else { - ByteBuffer buffer = this.buffers[index]; - for (byte b : bs1) { - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put(b); - } - { - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put((byte) '"'); - } - for (byte b : bs2) { - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put(b); - } - { - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put((byte) '"'); - } - { - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put((byte) '}'); - } - } - } - } - - @Override //firstFieldBytes 蹇呴』甯寮澶 - public void writeObjectByOnlyOneLatin1FieldValue(final byte[] firstFieldBytes, final String value) { - if (value == null || (tiny && value.isEmpty())) { - int expandsize = expand(2); - if (expandsize == 0) { // 鍙渶瑕佷竴涓猙uffer - ByteBuffer bb = this.buffers[index]; - bb.put((byte) '{'); - bb.put((byte) '}'); - } else { - ByteBuffer bb = this.buffers[index]; - bb.put((byte) '{'); - bb = nextByteBuffer(); - bb.put((byte) '}'); - } - } else { - byte[] bs1 = firstFieldBytes; - byte[] bs2 = Utility.latin1ByteArray(value); - int expandsize = expand(bs1.length + bs2.length + 3); - if (expandsize == 0) {// 鍙渶瑕佷竴涓猙uffer - final ByteBuffer buffer = this.buffers[index]; - buffer.put(bs1); - buffer.put((byte) '"'); - buffer.put(bs2); - buffer.put((byte) '"'); - buffer.put((byte) '}'); - } else { - ByteBuffer buffer = this.buffers[index]; - for (byte b : bs1) { - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put(b); - } - { - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put((byte) '"'); - } - for (byte b : bs2) { - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put(b); - } - { - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put((byte) '"'); - } - { - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put((byte) '}'); - } - } - } - } - - @Override //firstFieldBytes 蹇呴』甯寮澶, lastFieldBytes蹇呴』,寮澶 - public void writeObjectByOnlyTwoIntFieldValue(final byte[] firstFieldBytes, final int value1, final byte[] lastFieldBytes, final int value2) { - byte[] bs1 = firstFieldBytes; - byte[] bs2 = Utility.latin1ByteArray(String.valueOf(value1)); - byte[] bs3 = lastFieldBytes; - byte[] bs4 = Utility.latin1ByteArray(String.valueOf(value2)); - int expandsize = expand(bs1.length + bs2.length + bs3.length + bs4.length + 1); - if (expandsize == 0) {// 鍙渶瑕佷竴涓猙uffer - final ByteBuffer buffer = this.buffers[index]; - buffer.put(bs1); - buffer.put(bs2); - buffer.put(bs3); - buffer.put(bs4); - buffer.put((byte) '}'); - } else { - ByteBuffer buffer = this.buffers[index]; - for (byte b : bs1) { - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put(b); - } - for (byte b : bs2) { - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put(b); - } - for (byte b : bs3) { - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put(b); - } - for (byte b : bs4) { - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put(b); - } - { - if (!buffer.hasRemaining()) buffer = nextByteBuffer(); - buffer.put((byte) '}'); - } - } - } - - @Override - public void writeBoolean(boolean value) { - writeTo(value ? CHARS_TUREVALUE : CHARS_FALSEVALUE); - } - - @Override - public void writeInt(int value) { - writeLatin1To(false, String.valueOf(value)); - } - - @Override - public void writeLong(long value) { - writeLatin1To(false, String.valueOf(value)); - } - - @Override - public void writeString(String value) { - if (value == null) { - writeNull(); - return; - } - final char[] chs = Utility.charArray(value); - int len = 0; - for (char ch : chs) { - switch (ch) { - case '\n': len += 2; - break; - case '\r': len += 2; - break; - case '\t': len += 2; - break; - case '\\': len += 2; - break; - case '"': len += 2; - break; - default: len++; - break; - } - } - if (len == chs.length) { - writeTo(-1, true, chs, 0, len); - return; - } - int expandsize = -1; - if (this.charset == null) { //UTF-8 - final int byteLength = 2 + encodeEscapeUTF8Length(chs, 0, chs.length); - expandsize = expand(byteLength); - if (expandsize == 0) { // 鍙渶瑕佷竴涓猙uffer - final ByteBuffer buffer = this.buffers[index]; - buffer.put((byte) '"'); - for (int i = 0; i < chs.length; i++) { - char c = chs[i]; - switch (c) { - case '\n': buffer.put((byte) '\\').put((byte) 'n'); - break; - case '\r': buffer.put((byte) '\\').put((byte) 'r'); - break; - case '\t': buffer.put((byte) '\\').put((byte) 't'); - break; - case '\\': buffer.put((byte) '\\').put((byte) '\\'); - break; - case '"': buffer.put((byte) '\\').put((byte) '"'); - break; - default: - if (c < 0x80) { - buffer.put((byte) c); - } else if (c < 0x800) { - buffer.put((byte) (0xc0 | (c >> 6))); - buffer.put((byte) (0x80 | (c & 0x3f))); - } else if (Character.isSurrogate(c)) { //杩炲彇涓や釜 - int uc = Character.toCodePoint(c, chs[i + 1]); - buffer.put((byte) (0xf0 | ((uc >> 18)))); - buffer.put((byte) (0x80 | ((uc >> 12) & 0x3f))); - buffer.put((byte) (0x80 | ((uc >> 6) & 0x3f))); - buffer.put((byte) (0x80 | (uc & 0x3f))); - i++; - } else { - buffer.put((byte) (0xe0 | ((c >> 12)))); - buffer.put((byte) (0x80 | ((c >> 6) & 0x3f))); - buffer.put((byte) (0x80 | (c & 0x3f))); - } - break; - } - } - buffer.put((byte) '"'); - return; - } - } - StringBuilder sb = new StringBuilder(len); - for (char ch : chs) { - switch (ch) { - case '\n': sb.append("\\n"); - break; - case '\r': sb.append("\\r"); - break; - case '\t': sb.append("\\t"); - break; - case '\\': sb.append("\\\\"); - break; - case '"': sb.append("\\\""); - break; - default: sb.append(ch); - break; - } - } - char[] cs = Utility.charArray(sb); - writeTo(expandsize, true, cs, 0, sb.length()); - } - - @Override - public String toString() { - return Objects.toString(this); - } -} +/* + * 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.convert.json; + +import java.nio.*; +import java.nio.charset.*; +import java.util.*; +import java.util.function.*; +import org.redkale.convert.*; +import org.redkale.util.*; + +/** + * 浠yteBuffer涓烘暟鎹浇浣撶殑JsonWriter + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public class JsonByteBufferWriter extends JsonWriter { + + private static final char[] CHARS_TUREVALUE = "true".toCharArray(); + + private static final char[] CHARS_FALSEVALUE = "false".toCharArray(); + + protected Charset charset; + + private final Supplier supplier; + + private ByteBuffer[] buffers; + + private int index; + + public JsonByteBufferWriter(boolean tiny, Supplier supplier) { + this(tiny, null, supplier); + } + + public JsonByteBufferWriter(boolean tiny, Charset charset, Supplier supplier) { + this.tiny = tiny; + this.charset = charset; + this.supplier = supplier; + } + + @Override + public JsonByteBufferWriter tiny(boolean tiny) { + this.tiny = tiny; + return this; + } + + @Override + protected boolean recycle() { + super.recycle(); + this.index = 0; + this.specify = null; + this.charset = null; + this.buffers = null; + return false; + } + + public ByteBuffer[] toBuffers() { + if (buffers == null) return new ByteBuffer[0]; + for (int i = index; i < this.buffers.length; i++) { + ByteBuffer buf = this.buffers[i]; + if (buf.position() != 0) buf.flip(); + } + return this.buffers; + } + + public int count() { + if (this.buffers == null) return 0; + int len = 0; + for (ByteBuffer buffer : buffers) { + len += buffer.remaining(); + } + return len; + } + + private int expand(final int byteLength) { + if (this.buffers == null) { + this.index = 0; + this.buffers = new ByteBuffer[]{supplier.get()}; + } + ByteBuffer buffer = this.buffers[index]; + if (!buffer.hasRemaining()) { + buffer.flip(); + buffer = supplier.get(); + this.buffers = Utility.append(this.buffers, buffer); + this.index++; + } + int len = buffer.remaining(); + int size = 0; + while (len < byteLength) { + buffer = supplier.get(); + this.buffers = Utility.append(this.buffers, buffer); + len += buffer.remaining(); + size++; + } + return size; + } + + @Override + public void writeTo(final char ch) { + if (ch > Byte.MAX_VALUE) throw new ConvertException("writeTo char(int.value = " + (int) ch + ") must be less 127"); + expand(1); + this.buffers[index].put((byte) ch); + } + + @Override + public void writeTo(final char[] chs, final int start, final int len) { + writeTo(-1, false, chs, start, len); + } + + @Override + public void writeTo(final byte ch) { //鍙兘鏄 0 - 127 鐨勫瓧绗 + expand(1); + this.buffers[index].put(ch); + } + + @Override + public void writeTo(final byte[] chs, final int start, final int len) { //鍙兘鏄 0 - 127 鐨勫瓧绗 + int expandsize = expand(len); + if (expandsize == 0) { // 鍙渶瑕佷竴涓猙uffer + this.buffers[index].put(chs, start, len); + } else { + ByteBuffer buffer = this.buffers[index]; + int remain = len; + int offset = start; + while (remain > 0) { + int bsize = Math.min(buffer.remaining(), remain); + buffer.put(chs, offset, bsize); + offset += bsize; + remain -= bsize; + if (remain < 1) break; + buffer = nextByteBuffer(); + } + } + } + + private void writeTo(int expandsize, final boolean quote, final char[] chs, final int start, final int len) { + int byteLength = quote ? 2 : 0; + ByteBuffer bb = null; + if (charset == null) { + byteLength += Utility.encodeUTF8Length(chs, start, len); + } else { + bb = charset.encode(CharBuffer.wrap(chs, start, len)); + byteLength += bb.remaining(); + } + if (expandsize < 0) expandsize = expand(byteLength); + if (expandsize == 0) { // 鍙渶瑕佷竴涓猙uffer + final ByteBuffer buffer = this.buffers[index]; + if (quote) buffer.put((byte) '"'); + + if (charset == null) { //UTF-8 + final int limit = start + len; + for (int i = start; i < limit; i++) { + char c = chs[i]; + if (c < 0x80) { + buffer.put((byte) c); + } else if (c < 0x800) { + buffer.put((byte) (0xc0 | (c >> 6))); + buffer.put((byte) (0x80 | (c & 0x3f))); + } else if (Character.isSurrogate(c)) { //杩炲彇涓や釜 + int uc = Character.toCodePoint(c, chs[i + 1]); + buffer.put((byte) (0xf0 | ((uc >> 18)))); + buffer.put((byte) (0x80 | ((uc >> 12) & 0x3f))); + buffer.put((byte) (0x80 | ((uc >> 6) & 0x3f))); + buffer.put((byte) (0x80 | (uc & 0x3f))); + i++; + } else { + buffer.put((byte) (0xe0 | ((c >> 12)))); + buffer.put((byte) (0x80 | ((c >> 6) & 0x3f))); + buffer.put((byte) (0x80 | (c & 0x3f))); + } + } + } else { + buffer.put(bb); + } + + if (quote) buffer.put((byte) '"'); + return; + } + ByteBuffer buffer = this.buffers[index]; + if (quote) { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put((byte) '"'); + } + if (charset == null) { //UTF-8 + final int limit = start + len; + for (int i = start; i < limit; i++) { + char c = chs[i]; + if (c < 0x80) { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put((byte) c); + } else if (c < 0x800) { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put((byte) (0xc0 | (c >> 6))); + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put((byte) (0x80 | (c & 0x3f))); + } else if (Character.isSurrogate(c)) { //杩炲彇涓や釜 + int uc = Character.toCodePoint(c, chs[i + 1]); + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put((byte) (0xf0 | ((uc >> 18)))); + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put((byte) (0x80 | ((uc >> 12) & 0x3f))); + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put((byte) (0x80 | ((uc >> 6) & 0x3f))); + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put((byte) (0x80 | (uc & 0x3f))); + i++; + } else { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put((byte) (0xe0 | ((c >> 12)))); + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put((byte) (0x80 | ((c >> 6) & 0x3f))); + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put((byte) (0x80 | (c & 0x3f))); + } + } + } else { + while (bb.hasRemaining()) { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put(bb.get()); + } + } + if (quote) { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put((byte) '"'); + } + } + + private ByteBuffer nextByteBuffer() { + this.buffers[this.index].flip(); + return this.buffers[++this.index]; + } + + protected static int encodeEscapeUTF8Length(final char[] text, final int start, final int len) { + char c; + int size = 0; + final char[] chs = text; + final int limit = start + len; + for (int i = start; i < limit; i++) { + c = chs[i]; + switch (c) { + case '\n': size += 2; + break; + case '\r': size += 2; + break; + case '\t': size += 2; + break; + case '\\': size += 2; + break; + case '"': size += 2; + break; + default: + size += (c < 0x80 ? 1 : (c < 0x800 || Character.isSurrogate(c) ? 2 : 3)); + break; + } + } + return size; + } + + /** + * 娉ㄦ剰锛 璇tring鍊间笉鑳戒负null涓斾笉浼氳繘琛岃浆涔夛紝 鍙敤浜庝笉鍚渶瑕佽浆涔夊瓧绗︾殑瀛楃涓诧紝渚嬪enum銆乨ouble銆丅igInteger杞崲鐨凷tring + * + * @param quote 鏄惁鍐欏叆鍙屽紩鍙 + * @param value String鍊 + */ + @Override + public void writeLatin1To(final boolean quote, final String value) { + byte[] bs = Utility.latin1ByteArray(value); + int expandsize = expand(bs.length + (quote ? 2 : 0)); + if (expandsize == 0) {// 鍙渶瑕佷竴涓猙uffer + final ByteBuffer buffer = this.buffers[index]; + if (quote) buffer.put((byte) '"'); + buffer.put(bs); + if (quote) buffer.put((byte) '"'); + } else { + ByteBuffer buffer = this.buffers[index]; + if (quote) { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put((byte) '"'); + } + for (byte b : bs) { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put(b); + } + if (quote) { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put((byte) '"'); + } + } + } + + @Override + public void writeFieldShortValue(final byte[] fieldBytes, final short value) { + byte[] bs1 = fieldBytes; + byte[] bs2 = Utility.latin1ByteArray(String.valueOf(value)); + int expandsize = expand(bs1.length + bs2.length); + if (expandsize == 0) {// 鍙渶瑕佷竴涓猙uffer + final ByteBuffer buffer = this.buffers[index]; + buffer.put(bs1); + buffer.put(bs2); + } else { + ByteBuffer buffer = this.buffers[index]; + for (byte b : bs1) { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put(b); + } + for (byte b : bs2) { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put(b); + } + } + } + + @Override + public void writeFieldIntValue(final byte[] fieldBytes, final int value) { + byte[] bs1 = fieldBytes; + byte[] bs2 = Utility.latin1ByteArray(String.valueOf(value)); + int expandsize = expand(bs1.length + bs2.length); + if (expandsize == 0) {// 鍙渶瑕佷竴涓猙uffer + final ByteBuffer buffer = this.buffers[index]; + buffer.put(bs1); + buffer.put(bs2); + } else { + ByteBuffer buffer = this.buffers[index]; + for (byte b : bs1) { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put(b); + } + for (byte b : bs2) { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put(b); + } + } + } + + @Override + public void writeFieldLongValue(final byte[] fieldBytes, final long value) { + byte[] bs1 = fieldBytes; + byte[] bs2 = Utility.latin1ByteArray(String.valueOf(value)); + int expandsize = expand(bs1.length + bs2.length); + if (expandsize == 0) {// 鍙渶瑕佷竴涓猙uffer + final ByteBuffer buffer = this.buffers[index]; + buffer.put(bs1); + buffer.put(bs2); + } else { + ByteBuffer buffer = this.buffers[index]; + for (byte b : bs1) { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put(b); + } + for (byte b : bs2) { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put(b); + } + } + } + + @Override + public void writeFieldLatin1Value(final byte[] fieldBytes, final String value) { + byte[] bs1 = fieldBytes; + byte[] bs2 = Utility.latin1ByteArray(value); + int expandsize = expand(bs1.length + bs2.length + 2); + if (expandsize == 0) {// 鍙渶瑕佷竴涓猙uffer + final ByteBuffer buffer = this.buffers[index]; + buffer.put(bs1); + buffer.put((byte) '"'); + buffer.put(bs2); + buffer.put((byte) '"'); + } else { + ByteBuffer buffer = this.buffers[index]; + for (byte b : bs1) { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put(b); + } + { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put((byte) '"'); + } + for (byte b : bs2) { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put(b); + } + { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put((byte) '"'); + } + } + } + + @Override + public void writeLastFieldShortValue(final byte[] fieldBytes, final short value) { + byte[] bs1 = fieldBytes; + byte[] bs2 = Utility.latin1ByteArray(String.valueOf(value)); + int expandsize = expand(bs1.length + bs2.length + 1); + if (expandsize == 0) {// 鍙渶瑕佷竴涓猙uffer + final ByteBuffer buffer = this.buffers[index]; + buffer.put(bs1); + buffer.put(bs2); + buffer.put((byte) '}'); + } else { + ByteBuffer buffer = this.buffers[index]; + for (byte b : bs1) { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put(b); + } + for (byte b : bs2) { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put(b); + } + { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put((byte) '}'); + } + } + } + + @Override + public void writeLastFieldIntValue(final byte[] fieldBytes, final int value) { + byte[] bs1 = fieldBytes; + byte[] bs2 = Utility.latin1ByteArray(String.valueOf(value)); + int expandsize = expand(bs1.length + bs2.length + 1); + if (expandsize == 0) {// 鍙渶瑕佷竴涓猙uffer + final ByteBuffer buffer = this.buffers[index]; + buffer.put(bs1); + buffer.put(bs2); + buffer.put((byte) '}'); + } else { + ByteBuffer buffer = this.buffers[index]; + for (byte b : bs1) { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put(b); + } + for (byte b : bs2) { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put(b); + } + { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put((byte) '}'); + } + } + } + + @Override + public void writeLastFieldLongValue(final byte[] fieldBytes, final long value) { + byte[] bs1 = fieldBytes; + byte[] bs2 = Utility.latin1ByteArray(String.valueOf(value)); + int expandsize = expand(bs1.length + bs2.length + 1); + if (expandsize == 0) {// 鍙渶瑕佷竴涓猙uffer + final ByteBuffer buffer = this.buffers[index]; + buffer.put(bs1); + buffer.put(bs2); + buffer.put((byte) '}'); + } else { + ByteBuffer buffer = this.buffers[index]; + for (byte b : bs1) { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put(b); + } + for (byte b : bs2) { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put(b); + } + { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put((byte) '}'); + } + } + } + + @Override + public void writeLastFieldLatin1Value(final byte[] fieldBytes, final String value) { + if (value == null || (tiny && value.isEmpty())) { + expand(1); + this.buffers[index].put((byte) '}'); + } else { + byte[] bs1 = fieldBytes; + byte[] bs2 = Utility.latin1ByteArray(value); + int expandsize = expand(bs1.length + bs2.length + 3); + if (expandsize == 0) {// 鍙渶瑕佷竴涓猙uffer + final ByteBuffer buffer = this.buffers[index]; + buffer.put(bs1); + buffer.put((byte) '"'); + buffer.put(bs2); + buffer.put((byte) '"'); + buffer.put((byte) '}'); + } else { + ByteBuffer buffer = this.buffers[index]; + for (byte b : bs1) { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put(b); + } + { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put((byte) '"'); + } + for (byte b : bs2) { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put(b); + } + { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put((byte) '"'); + } + { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put((byte) '}'); + } + } + } + } + + @Override //firstFieldBytes 蹇呴』甯寮澶 + public void writeObjectByOnlyOneLatin1FieldValue(final byte[] firstFieldBytes, final String value) { + if (value == null || (tiny && value.isEmpty())) { + int expandsize = expand(2); + if (expandsize == 0) { // 鍙渶瑕佷竴涓猙uffer + ByteBuffer bb = this.buffers[index]; + bb.put((byte) '{'); + bb.put((byte) '}'); + } else { + ByteBuffer bb = this.buffers[index]; + bb.put((byte) '{'); + bb = nextByteBuffer(); + bb.put((byte) '}'); + } + } else { + byte[] bs1 = firstFieldBytes; + byte[] bs2 = Utility.latin1ByteArray(value); + int expandsize = expand(bs1.length + bs2.length + 3); + if (expandsize == 0) {// 鍙渶瑕佷竴涓猙uffer + final ByteBuffer buffer = this.buffers[index]; + buffer.put(bs1); + buffer.put((byte) '"'); + buffer.put(bs2); + buffer.put((byte) '"'); + buffer.put((byte) '}'); + } else { + ByteBuffer buffer = this.buffers[index]; + for (byte b : bs1) { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put(b); + } + { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put((byte) '"'); + } + for (byte b : bs2) { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put(b); + } + { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put((byte) '"'); + } + { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put((byte) '}'); + } + } + } + } + + @Override //firstFieldBytes 蹇呴』甯寮澶, lastFieldBytes蹇呴』,寮澶 + public void writeObjectByOnlyTwoIntFieldValue(final byte[] firstFieldBytes, final int value1, final byte[] lastFieldBytes, final int value2) { + byte[] bs1 = firstFieldBytes; + byte[] bs2 = Utility.latin1ByteArray(String.valueOf(value1)); + byte[] bs3 = lastFieldBytes; + byte[] bs4 = Utility.latin1ByteArray(String.valueOf(value2)); + int expandsize = expand(bs1.length + bs2.length + bs3.length + bs4.length + 1); + if (expandsize == 0) {// 鍙渶瑕佷竴涓猙uffer + final ByteBuffer buffer = this.buffers[index]; + buffer.put(bs1); + buffer.put(bs2); + buffer.put(bs3); + buffer.put(bs4); + buffer.put((byte) '}'); + } else { + ByteBuffer buffer = this.buffers[index]; + for (byte b : bs1) { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put(b); + } + for (byte b : bs2) { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put(b); + } + for (byte b : bs3) { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put(b); + } + for (byte b : bs4) { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put(b); + } + { + if (!buffer.hasRemaining()) buffer = nextByteBuffer(); + buffer.put((byte) '}'); + } + } + } + + @Override + public void writeBoolean(boolean value) { + writeTo(value ? CHARS_TUREVALUE : CHARS_FALSEVALUE); + } + + @Override + public void writeInt(int value) { + writeLatin1To(false, String.valueOf(value)); + } + + @Override + public void writeLong(long value) { + writeLatin1To(false, String.valueOf(value)); + } + + @Override + public void writeString(String value) { + if (value == null) { + writeNull(); + return; + } + final char[] chs = Utility.charArray(value); + int len = 0; + for (char ch : chs) { + switch (ch) { + case '\n': len += 2; + break; + case '\r': len += 2; + break; + case '\t': len += 2; + break; + case '\\': len += 2; + break; + case '"': len += 2; + break; + default: len++; + break; + } + } + if (len == chs.length) { + writeTo(-1, true, chs, 0, len); + return; + } + int expandsize = -1; + if (this.charset == null) { //UTF-8 + final int byteLength = 2 + encodeEscapeUTF8Length(chs, 0, chs.length); + expandsize = expand(byteLength); + if (expandsize == 0) { // 鍙渶瑕佷竴涓猙uffer + final ByteBuffer buffer = this.buffers[index]; + buffer.put((byte) '"'); + for (int i = 0; i < chs.length; i++) { + char c = chs[i]; + switch (c) { + case '\n': buffer.put((byte) '\\').put((byte) 'n'); + break; + case '\r': buffer.put((byte) '\\').put((byte) 'r'); + break; + case '\t': buffer.put((byte) '\\').put((byte) 't'); + break; + case '\\': buffer.put((byte) '\\').put((byte) '\\'); + break; + case '"': buffer.put((byte) '\\').put((byte) '"'); + break; + default: + if (c < 0x80) { + buffer.put((byte) c); + } else if (c < 0x800) { + buffer.put((byte) (0xc0 | (c >> 6))); + buffer.put((byte) (0x80 | (c & 0x3f))); + } else if (Character.isSurrogate(c)) { //杩炲彇涓や釜 + int uc = Character.toCodePoint(c, chs[i + 1]); + buffer.put((byte) (0xf0 | ((uc >> 18)))); + buffer.put((byte) (0x80 | ((uc >> 12) & 0x3f))); + buffer.put((byte) (0x80 | ((uc >> 6) & 0x3f))); + buffer.put((byte) (0x80 | (uc & 0x3f))); + i++; + } else { + buffer.put((byte) (0xe0 | ((c >> 12)))); + buffer.put((byte) (0x80 | ((c >> 6) & 0x3f))); + buffer.put((byte) (0x80 | (c & 0x3f))); + } + break; + } + } + buffer.put((byte) '"'); + return; + } + } + StringBuilder sb = new StringBuilder(len); + for (char ch : chs) { + switch (ch) { + case '\n': sb.append("\\n"); + break; + case '\r': sb.append("\\r"); + break; + case '\t': sb.append("\\t"); + break; + case '\\': sb.append("\\\\"); + break; + case '"': sb.append("\\\""); + break; + default: sb.append(ch); + break; + } + } + char[] cs = Utility.charArray(sb); + writeTo(expandsize, true, cs, 0, sb.length()); + } + + @Override + public String toString() { + return Objects.toString(this); + } +} diff --git a/src/main/java/org/redkale/convert/json/JsonBytesWriter.java b/src/main/java/org/redkale/convert/json/JsonBytesWriter.java index c4bc555e2..780e8f686 100644 --- a/src/main/java/org/redkale/convert/json/JsonBytesWriter.java +++ b/src/main/java/org/redkale/convert/json/JsonBytesWriter.java @@ -1,582 +1,582 @@ -/* - * 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.convert.json; - -import java.lang.reflect.Type; -import java.nio.charset.StandardCharsets; -import java.util.function.Consumer; -import org.redkale.convert.*; -import static org.redkale.convert.json.JsonWriter.*; -import org.redkale.util.*; - -/** - * - * writeTo绯诲垪鐨勬柟娉曡緭鍑虹殑瀛楃涓嶈兘鍚壒娈婂瓧绗 - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * - * @since 2.3.0 - */ -public class JsonBytesWriter extends JsonWriter implements ByteTuple { - - private static final byte[] BYTES_TUREVALUE = "true".getBytes(); - - private static final byte[] BYTES_FALSEVALUE = "false".getBytes(); - - private static final int TENTHOUSAND_MAX = 10001; - - private static final byte[][] TENTHOUSAND_BYTES = new byte[TENTHOUSAND_MAX][]; - - static { - for (int i = 0; i < TENTHOUSAND_BYTES.length; i++) { - TENTHOUSAND_BYTES[i] = String.valueOf(i).getBytes(); - } - } - - private int count; - - private byte[] content; - - public JsonBytesWriter() { - this(defaultSize); - } - - public JsonBytesWriter(int size) { - this.content = new byte[size > 1024 ? size : 1024]; - } - - public JsonBytesWriter(ByteArray array) { - this.content = array.content(); - this.count = array.length(); - } - - public JsonBytesWriter(boolean tiny, ByteArray array) { - this.tiny = tiny; - this.content = array.content(); - this.count = array.length(); - } - - protected byte[] expand(int len) { - int newcount = count + len; - if (newcount <= content.length) return content; - byte[] newdata = new byte[Math.max(content.length * 3 / 2, newcount)]; - System.arraycopy(content, 0, newdata, 0, count); - this.content = newdata; - return newdata; - } - - @Override - public byte[] content() { - return content; - } - - @Override - public int offset() { - return 0; - } - - @Override - public int length() { - return count; - } - - /** - * 灏嗘湰瀵硅薄鐨勫唴瀹瑰紩鐢ㄥ鍒剁粰array - * - * @param array ByteArray - */ - public void directTo(ByteArray array) { - array.directFrom(content, count); - } - - @Override - public final void writeFieldName(EnMember member, String fieldName, Type fieldType, int fieldPos) { - if (this.comma) writeTo(','); - if (member != null) { - byte[] bs = member.getJsonFieldNameBytes(); - expand(bs.length); - System.arraycopy(bs, 0, content, count, bs.length); - count += bs.length; - } else { - writeLatin1To(true, fieldName); - writeTo(':'); - } - } - - @Override - public void writeTo(final char ch) { //鍙兘鏄 0 - 127 鐨勫瓧绗 - expand(1); - content[count++] = (byte) ch; - } - - @Override - public void writeTo(final char[] chs, final int start, final int len) { //鍙兘鏄 0 - 127 鐨勫瓧绗 - expand(len); - for (int i = 0; i < len; i++) { - content[count + i] = (byte) chs[start + i]; - } - count += len; - } - - @Override - public void writeTo(final byte ch) { //鍙兘鏄 0 - 127 鐨勫瓧绗 - expand(1); - content[count++] = ch; - } - - @Override - public void writeTo(final byte[] chs, final int start, final int len) { //鍙兘鏄 0 - 127 鐨勫瓧绗 - expand(len); - System.arraycopy(chs, start, content, count, len); - count += len; - } - - /** - * 娉ㄦ剰锛 璇tring鍊间笉鑳戒负null涓斾笉浼氳繘琛岃浆涔夛紝 鍙敤浜庝笉鍚渶瑕佽浆涔夊瓧绗︾殑瀛楃涓诧紝渚嬪enum銆乨ouble銆丅igInteger杞崲鐨凷tring - * - * @param quote 鏄惁鍔犲弻寮曞彿 - * @param value 闈瀗ull涓斾笉鍚渶瑕佽浆涔夌殑瀛楃鐨凷tring鍊 - */ - @Override - public void writeLatin1To(final boolean quote, final String value) { - byte[] bs = Utility.latin1ByteArray(value); - int len = bs.length; - if (quote) { - byte[] src = expand(len + 2); - src[count++] = '"'; - System.arraycopy(bs, 0, src, count, bs.length); - count += len; - src[count++] = '"'; - } else { - byte[] src = expand(len); - System.arraycopy(bs, 0, src, count, bs.length); - count += len; - } - } - - @Override - public void writeFieldShortValue(final byte[] fieldBytes, final short value) { - byte[] bs1 = fieldBytes; - byte[] bs2 = (value >= 0 && value < TENTHOUSAND_MAX) ? TENTHOUSAND_BYTES[(int) value] : Utility.latin1ByteArray(String.valueOf(value)); - int len1 = bs1.length; - int len2 = bs2.length; - byte[] src = expand(len1 + len2); - System.arraycopy(bs1, 0, src, count, len1); - count += len1; - System.arraycopy(bs2, 0, src, count, len2); - count += len2; - } - - @Override - public void writeFieldIntValue(final byte[] fieldBytes, final int value) { - byte[] bs1 = fieldBytes; - byte[] bs2 = (value >= 0 && value < TENTHOUSAND_MAX) ? TENTHOUSAND_BYTES[value] : Utility.latin1ByteArray(String.valueOf(value)); - int len1 = bs1.length; - int len2 = bs2.length; - byte[] src = expand(len1 + len2); - System.arraycopy(bs1, 0, src, count, len1); - count += len1; - System.arraycopy(bs2, 0, src, count, len2); - count += len2; - } - - @Override - public void writeFieldLongValue(final byte[] fieldBytes, final long value) { - byte[] bs1 = fieldBytes; - byte[] bs2 = (value >= 0 && value < TENTHOUSAND_MAX) ? TENTHOUSAND_BYTES[(int) value] : Utility.latin1ByteArray(String.valueOf(value)); - int len1 = bs1.length; - int len2 = bs2.length; - byte[] src = expand(len1 + len2); - System.arraycopy(bs1, 0, src, count, len1); - count += len1; - System.arraycopy(bs2, 0, src, count, len2); - count += len2; - } - - @Override - public void writeFieldLatin1Value(final byte[] fieldBytes, final String value) { - byte[] bs1 = fieldBytes; - byte[] bs2 = Utility.latin1ByteArray(value); - int len1 = bs1.length; - int len2 = bs2.length; - byte[] src = expand(len1 + len2 + 2); - System.arraycopy(bs1, 0, src, count, len1); - count += len1; - src[count++] = '"'; - System.arraycopy(bs2, 0, src, count, len2); - count += len2; - src[count++] = '"'; - } - - @Override - public void writeLastFieldShortValue(final byte[] fieldBytes, final short value) { - byte[] bs1 = fieldBytes; - byte[] bs2 = (value >= 0 && value < TENTHOUSAND_MAX) ? TENTHOUSAND_BYTES[(int) value] : Utility.latin1ByteArray(String.valueOf(value)); - int len1 = bs1.length; - int len2 = bs2.length; - byte[] src = expand(len1 + len2 + 1); - System.arraycopy(bs1, 0, src, count, len1); - count += len1; - System.arraycopy(bs2, 0, src, count, len2); - count += len2; - src[count++] = '}'; - } - - @Override - public void writeLastFieldIntValue(final byte[] fieldBytes, final int value) { - byte[] bs1 = fieldBytes; - byte[] bs2 = (value >= 0 && value < TENTHOUSAND_MAX) ? TENTHOUSAND_BYTES[value] : Utility.latin1ByteArray(String.valueOf(value)); - int len1 = bs1.length; - int len2 = bs2.length; - byte[] src = expand(len1 + len2 + 1); - System.arraycopy(bs1, 0, src, count, len1); - count += len1; - System.arraycopy(bs2, 0, src, count, len2); - count += len2; - src[count++] = '}'; - } - - @Override - public void writeLastFieldLongValue(final byte[] fieldBytes, final long value) { - byte[] bs1 = fieldBytes; - byte[] bs2 = (value >= 0 && value < TENTHOUSAND_MAX) ? TENTHOUSAND_BYTES[(int) value] : Utility.latin1ByteArray(String.valueOf(value)); - int len1 = bs1.length; - int len2 = bs2.length; - byte[] src = expand(len1 + len2 + 1); - System.arraycopy(bs1, 0, src, count, len1); - count += len1; - System.arraycopy(bs2, 0, src, count, len2); - count += len2; - src[count++] = '}'; - } - - @Override - public void writeLastFieldLatin1Value(final byte[] fieldBytes, final String value) { - if (value == null || (tiny && value.isEmpty())) { - expand(1); - content[count++] = '}'; - } else { - byte[] bs1 = fieldBytes; - byte[] bs2 = Utility.latin1ByteArray(value); - int len1 = bs1.length; - int len2 = bs2.length; - byte[] src = expand(len1 + len2 + 3); - int c = count; - System.arraycopy(bs1, 0, src, c, len1); - c += len1; - src[c++] = '"'; - System.arraycopy(bs2, 0, src, c, len2); - c += len2; - src[c++] = '"'; - src[c++] = '}'; - count = c; - } - } - - @Override //firstFieldBytes 蹇呴』甯寮澶 - public void writeObjectByOnlyOneLatin1FieldValue(final byte[] firstFieldBytes, final String value) { - if (value == null || (tiny && value.isEmpty())) { - expand(2); - content[count++] = '{'; - content[count++] = '}'; - } else { - byte[] bs1 = firstFieldBytes; - byte[] bs2 = Utility.latin1ByteArray(value); - int len1 = bs1.length; - int len2 = bs2.length; - byte[] src = expand(len1 + len2 + 3); - int c = count; - System.arraycopy(bs1, 0, src, c, len1); - c += len1; - src[c++] = '"'; - System.arraycopy(bs2, 0, src, c, len2); - c += len2; - src[c++] = '"'; - content[c++] = '}'; - count = c; - } - } - - @Override //firstFieldBytes 蹇呴』甯寮澶, lastFieldBytes蹇呴』,寮澶 - public void writeObjectByOnlyTwoIntFieldValue(final byte[] firstFieldBytes, final int value1, final byte[] lastFieldBytes, final int value2) { - byte[] bs1 = firstFieldBytes; - byte[] bs2 = (value1 >= 0 && value1 < TENTHOUSAND_MAX) ? TENTHOUSAND_BYTES[value1] : Utility.latin1ByteArray(String.valueOf(value1)); - byte[] bs3 = lastFieldBytes; - byte[] bs4 = (value2 >= 0 && value2 < TENTHOUSAND_MAX) ? TENTHOUSAND_BYTES[value2] : Utility.latin1ByteArray(String.valueOf(value2)); - int len1 = bs1.length; - int len2 = bs2.length; - int len3 = bs3.length; - int len4 = bs4.length; - byte[] src = expand(len1 + len2 + len3 + len4 + 1); - System.arraycopy(bs1, 0, src, count, len1); - count += len1; - System.arraycopy(bs2, 0, src, count, len2); - count += len2; - System.arraycopy(bs3, 0, src, count, len3); - count += len3; - System.arraycopy(bs4, 0, src, count, len4); - count += len4; - src[count++] = '}'; - } - - public JsonBytesWriter clear() { - this.count = 0; - return this; - } - - @Override - public boolean recycle() { - super.recycle(); - this.count = 0; - this.specify = null; - if (this.content != null && this.content.length > defaultSize * 100) { - this.content = new byte[defaultSize]; - } - return true; - } - - /** - * 鐩存帴鑾峰彇鍏ㄩ儴鏁版嵁, 瀹為檯鏁版嵁闇瑕佹牴鎹甤ount闀垮害鏉ユ埅鍙 - * - * @return byte[] - */ - public byte[] directBytes() { - return content; - } - - public void completed(ConvertBytesHandler handler, Consumer callback) { - handler.completed(content, 0, count, callback, this); - } - - public byte[] toBytes() { - byte[] copy = new byte[count]; - System.arraycopy(content, 0, copy, 0, count); - return copy; - } - - public int count() { - return this.count; - } - - private void writeEscapeLatinString(byte[] value) { - byte[] bytes = expand(value.length * 2 + 2); - int curr = count; - bytes[curr++] = '"'; - for (byte b : value) { - if (b == '"') { - bytes[curr++] = '\\'; - bytes[curr++] = '"'; - } else if (b == '\\') { - bytes[curr++] = '\\'; - bytes[curr++] = '\\'; - } else if (b < 32) { - if (b == '\n') { - bytes[curr++] = '\\'; - bytes[curr++] = 'n'; - } else if (b == '\r') { - bytes[curr++] = '\\'; - bytes[curr++] = 'r'; - } else if (b == '\t') { - bytes[curr++] = '\\'; - bytes[curr++] = 't'; - } else { - bytes[curr++] = b; - } - } else { - bytes[curr++] = b; - } - } - bytes[curr++] = '"'; - count = curr; - } - - @Override - public void writeString(String value) { - if (value == null) { - writeNull(); - return; - } - if (Utility.isLatin1(value)) { - writeEscapeLatinString(Utility.latin1ByteArray(value)); - return; - } - byte[] bytes = expand(value.length() * 4 + 2); - int curr = count; - bytes[curr++] = '"'; - int len = value.length(); - for (int i = 0; i < len; i++) { - char ch = value.charAt(i); - switch (ch) { - case '\n': - bytes[curr++] = '\\'; - bytes[curr++] = 'n'; - break; - case '\r': - bytes[curr++] = '\\'; - bytes[curr++] = 'r'; - break; - case '\t': - bytes[curr++] = '\\'; - bytes[curr++] = 't'; - break; - case '\\': - bytes[curr++] = '\\'; - bytes[curr++] = '\\'; - break; - case '"': - bytes[curr++] = '\\'; - bytes[curr++] = '"'; - break; - default: - if (ch < 0x80) { - bytes[curr++] = (byte) ch; - } else if (ch < 0x800) { - bytes[curr++] = (byte) (0xc0 | (ch >> 6)); - bytes[curr++] = (byte) (0x80 | (ch & 0x3f)); - } else if (Character.isSurrogate(ch)) { //杩炲彇涓や釜 - int uc = Character.toCodePoint(ch, value.charAt(++i)); - bytes[curr++] = (byte) (0xf0 | ((uc >> 18))); - bytes[curr++] = (byte) (0x80 | ((uc >> 12) & 0x3f)); - bytes[curr++] = (byte) (0x80 | ((uc >> 6) & 0x3f)); - bytes[curr++] = (byte) (0x80 | (uc & 0x3f)); - } else { - bytes[curr++] = (byte) (0xe0 | ((ch >> 12))); - bytes[curr++] = (byte) (0x80 | ((ch >> 6) & 0x3f)); - bytes[curr++] = (byte) (0x80 | (ch & 0x3f)); - } - break; - } - } - bytes[curr++] = '"'; - count = curr; - } - - @Override - public String toString() { - return new String(content, 0, count, StandardCharsets.UTF_8); - } - - //---------------------------------------------------------------------------------------------- - @Override - public void writeBoolean(boolean value) { - byte[] bs = value ? BYTES_TUREVALUE : BYTES_FALSEVALUE; - expand(bs.length); - System.arraycopy(bs, 0, content, count, bs.length); - count += bs.length; - } - - @Override - public void writeInt(int value) { - if (value >= 0 && value < TENTHOUSAND_MAX) { - byte[] bs = TENTHOUSAND_BYTES[value]; - expand(bs.length); - System.arraycopy(bs, 0, content, count, bs.length); - count += bs.length; - return; - } - final char sign = value >= 0 ? 0 : '-'; - if (value < 0) value = -value; - int size; - for (int i = 0;; i++) { - if (value <= sizeTable[i]) { - size = i + 1; - break; - } - } - if (sign != 0) size++; //璐熸暟 - byte[] bytes = expand(size); - - int q, r; - int charPos = count + size; - - // Generate two digits per iteration - while (value >= 65536) { - q = value / 100; - // really: r = i - (q * 100); - r = value - ((q << 6) + (q << 5) + (q << 2)); - value = q; - bytes[--charPos] = (byte) DigitOnes[r]; - bytes[--charPos] = (byte) DigitTens[r]; - } - - // Fall thru to fast mode for smaller numbers - // assert(i <= 65536, i); - for (;;) { - q = (value * 52429) >>> (16 + 3); - r = value - ((q << 3) + (q << 1)); // r = i-(q*10) ... - bytes[--charPos] = (byte) digits[r]; - value = q; - if (value == 0) break; - } - if (sign != 0) bytes[--charPos] = (byte) sign; - count += size; - } - - @Override - public void writeLong(long value) { - if (value >= 0 && value < TENTHOUSAND_MAX) { - byte[] bs = TENTHOUSAND_BYTES[(int) value]; - expand(bs.length); - System.arraycopy(bs, 0, content, count, bs.length); - count += bs.length; - return; - } - final char sign = value >= 0 ? 0 : '-'; - if (value < 0) value = -value; - int size = 19; - long p = 10; - for (int i = 1; i < 19; i++) { - if (value < p) { - size = i; - break; - } - p = 10 * p; - } - if (sign != 0) size++; //璐熸暟 - byte[] bytes = expand(size); - - long q; - int r; - int charPos = count + size; - - // Get 2 digits/iteration using longs until quotient fits into an int - while (value > Integer.MAX_VALUE) { - q = value / 100; - // really: r = i - (q * 100); - r = (int) (value - ((q << 6) + (q << 5) + (q << 2))); - value = q; - content[--charPos] = (byte) DigitOnes[r]; - content[--charPos] = (byte) DigitTens[r]; - } - - // Get 2 digits/iteration using ints - int q2; - int i2 = (int) value; - while (i2 >= 65536) { - q2 = i2 / 100; - // really: r = i2 - (q * 100); - r = i2 - ((q2 << 6) + (q2 << 5) + (q2 << 2)); - i2 = q2; - bytes[--charPos] = (byte) DigitOnes[r]; - bytes[--charPos] = (byte) DigitTens[r]; - } - - // Fall thru to fast mode for smaller numbers - // assert(i2 <= 65536, i2); - for (;;) { - q2 = (i2 * 52429) >>> (16 + 3); - r = i2 - ((q2 << 3) + (q2 << 1)); // r = i2-(q2*10) ... - bytes[--charPos] = (byte) digits[r]; - i2 = q2; - if (i2 == 0) break; - } - if (sign != 0) bytes[--charPos] = (byte) sign; - count += size; - } - -} +/* + * 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.convert.json; + +import java.lang.reflect.Type; +import java.nio.charset.StandardCharsets; +import java.util.function.Consumer; +import org.redkale.convert.*; +import static org.redkale.convert.json.JsonWriter.*; +import org.redkale.util.*; + +/** + * + * writeTo绯诲垪鐨勬柟娉曡緭鍑虹殑瀛楃涓嶈兘鍚壒娈婂瓧绗 + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.3.0 + */ +public class JsonBytesWriter extends JsonWriter implements ByteTuple { + + private static final byte[] BYTES_TUREVALUE = "true".getBytes(); + + private static final byte[] BYTES_FALSEVALUE = "false".getBytes(); + + private static final int TENTHOUSAND_MAX = 10001; + + private static final byte[][] TENTHOUSAND_BYTES = new byte[TENTHOUSAND_MAX][]; + + static { + for (int i = 0; i < TENTHOUSAND_BYTES.length; i++) { + TENTHOUSAND_BYTES[i] = String.valueOf(i).getBytes(); + } + } + + private int count; + + private byte[] content; + + public JsonBytesWriter() { + this(defaultSize); + } + + public JsonBytesWriter(int size) { + this.content = new byte[size > 1024 ? size : 1024]; + } + + public JsonBytesWriter(ByteArray array) { + this.content = array.content(); + this.count = array.length(); + } + + public JsonBytesWriter(boolean tiny, ByteArray array) { + this.tiny = tiny; + this.content = array.content(); + this.count = array.length(); + } + + protected byte[] expand(int len) { + int newcount = count + len; + if (newcount <= content.length) return content; + byte[] newdata = new byte[Math.max(content.length * 3 / 2, newcount)]; + System.arraycopy(content, 0, newdata, 0, count); + this.content = newdata; + return newdata; + } + + @Override + public byte[] content() { + return content; + } + + @Override + public int offset() { + return 0; + } + + @Override + public int length() { + return count; + } + + /** + * 灏嗘湰瀵硅薄鐨勫唴瀹瑰紩鐢ㄥ鍒剁粰array + * + * @param array ByteArray + */ + public void directTo(ByteArray array) { + array.directFrom(content, count); + } + + @Override + public final void writeFieldName(EnMember member, String fieldName, Type fieldType, int fieldPos) { + if (this.comma) writeTo(','); + if (member != null) { + byte[] bs = member.getJsonFieldNameBytes(); + expand(bs.length); + System.arraycopy(bs, 0, content, count, bs.length); + count += bs.length; + } else { + writeLatin1To(true, fieldName); + writeTo(':'); + } + } + + @Override + public void writeTo(final char ch) { //鍙兘鏄 0 - 127 鐨勫瓧绗 + expand(1); + content[count++] = (byte) ch; + } + + @Override + public void writeTo(final char[] chs, final int start, final int len) { //鍙兘鏄 0 - 127 鐨勫瓧绗 + expand(len); + for (int i = 0; i < len; i++) { + content[count + i] = (byte) chs[start + i]; + } + count += len; + } + + @Override + public void writeTo(final byte ch) { //鍙兘鏄 0 - 127 鐨勫瓧绗 + expand(1); + content[count++] = ch; + } + + @Override + public void writeTo(final byte[] chs, final int start, final int len) { //鍙兘鏄 0 - 127 鐨勫瓧绗 + expand(len); + System.arraycopy(chs, start, content, count, len); + count += len; + } + + /** + * 娉ㄦ剰锛 璇tring鍊间笉鑳戒负null涓斾笉浼氳繘琛岃浆涔夛紝 鍙敤浜庝笉鍚渶瑕佽浆涔夊瓧绗︾殑瀛楃涓诧紝渚嬪enum銆乨ouble銆丅igInteger杞崲鐨凷tring + * + * @param quote 鏄惁鍔犲弻寮曞彿 + * @param value 闈瀗ull涓斾笉鍚渶瑕佽浆涔夌殑瀛楃鐨凷tring鍊 + */ + @Override + public void writeLatin1To(final boolean quote, final String value) { + byte[] bs = Utility.latin1ByteArray(value); + int len = bs.length; + if (quote) { + byte[] src = expand(len + 2); + src[count++] = '"'; + System.arraycopy(bs, 0, src, count, bs.length); + count += len; + src[count++] = '"'; + } else { + byte[] src = expand(len); + System.arraycopy(bs, 0, src, count, bs.length); + count += len; + } + } + + @Override + public void writeFieldShortValue(final byte[] fieldBytes, final short value) { + byte[] bs1 = fieldBytes; + byte[] bs2 = (value >= 0 && value < TENTHOUSAND_MAX) ? TENTHOUSAND_BYTES[(int) value] : Utility.latin1ByteArray(String.valueOf(value)); + int len1 = bs1.length; + int len2 = bs2.length; + byte[] src = expand(len1 + len2); + System.arraycopy(bs1, 0, src, count, len1); + count += len1; + System.arraycopy(bs2, 0, src, count, len2); + count += len2; + } + + @Override + public void writeFieldIntValue(final byte[] fieldBytes, final int value) { + byte[] bs1 = fieldBytes; + byte[] bs2 = (value >= 0 && value < TENTHOUSAND_MAX) ? TENTHOUSAND_BYTES[value] : Utility.latin1ByteArray(String.valueOf(value)); + int len1 = bs1.length; + int len2 = bs2.length; + byte[] src = expand(len1 + len2); + System.arraycopy(bs1, 0, src, count, len1); + count += len1; + System.arraycopy(bs2, 0, src, count, len2); + count += len2; + } + + @Override + public void writeFieldLongValue(final byte[] fieldBytes, final long value) { + byte[] bs1 = fieldBytes; + byte[] bs2 = (value >= 0 && value < TENTHOUSAND_MAX) ? TENTHOUSAND_BYTES[(int) value] : Utility.latin1ByteArray(String.valueOf(value)); + int len1 = bs1.length; + int len2 = bs2.length; + byte[] src = expand(len1 + len2); + System.arraycopy(bs1, 0, src, count, len1); + count += len1; + System.arraycopy(bs2, 0, src, count, len2); + count += len2; + } + + @Override + public void writeFieldLatin1Value(final byte[] fieldBytes, final String value) { + byte[] bs1 = fieldBytes; + byte[] bs2 = Utility.latin1ByteArray(value); + int len1 = bs1.length; + int len2 = bs2.length; + byte[] src = expand(len1 + len2 + 2); + System.arraycopy(bs1, 0, src, count, len1); + count += len1; + src[count++] = '"'; + System.arraycopy(bs2, 0, src, count, len2); + count += len2; + src[count++] = '"'; + } + + @Override + public void writeLastFieldShortValue(final byte[] fieldBytes, final short value) { + byte[] bs1 = fieldBytes; + byte[] bs2 = (value >= 0 && value < TENTHOUSAND_MAX) ? TENTHOUSAND_BYTES[(int) value] : Utility.latin1ByteArray(String.valueOf(value)); + int len1 = bs1.length; + int len2 = bs2.length; + byte[] src = expand(len1 + len2 + 1); + System.arraycopy(bs1, 0, src, count, len1); + count += len1; + System.arraycopy(bs2, 0, src, count, len2); + count += len2; + src[count++] = '}'; + } + + @Override + public void writeLastFieldIntValue(final byte[] fieldBytes, final int value) { + byte[] bs1 = fieldBytes; + byte[] bs2 = (value >= 0 && value < TENTHOUSAND_MAX) ? TENTHOUSAND_BYTES[value] : Utility.latin1ByteArray(String.valueOf(value)); + int len1 = bs1.length; + int len2 = bs2.length; + byte[] src = expand(len1 + len2 + 1); + System.arraycopy(bs1, 0, src, count, len1); + count += len1; + System.arraycopy(bs2, 0, src, count, len2); + count += len2; + src[count++] = '}'; + } + + @Override + public void writeLastFieldLongValue(final byte[] fieldBytes, final long value) { + byte[] bs1 = fieldBytes; + byte[] bs2 = (value >= 0 && value < TENTHOUSAND_MAX) ? TENTHOUSAND_BYTES[(int) value] : Utility.latin1ByteArray(String.valueOf(value)); + int len1 = bs1.length; + int len2 = bs2.length; + byte[] src = expand(len1 + len2 + 1); + System.arraycopy(bs1, 0, src, count, len1); + count += len1; + System.arraycopy(bs2, 0, src, count, len2); + count += len2; + src[count++] = '}'; + } + + @Override + public void writeLastFieldLatin1Value(final byte[] fieldBytes, final String value) { + if (value == null || (tiny && value.isEmpty())) { + expand(1); + content[count++] = '}'; + } else { + byte[] bs1 = fieldBytes; + byte[] bs2 = Utility.latin1ByteArray(value); + int len1 = bs1.length; + int len2 = bs2.length; + byte[] src = expand(len1 + len2 + 3); + int c = count; + System.arraycopy(bs1, 0, src, c, len1); + c += len1; + src[c++] = '"'; + System.arraycopy(bs2, 0, src, c, len2); + c += len2; + src[c++] = '"'; + src[c++] = '}'; + count = c; + } + } + + @Override //firstFieldBytes 蹇呴』甯寮澶 + public void writeObjectByOnlyOneLatin1FieldValue(final byte[] firstFieldBytes, final String value) { + if (value == null || (tiny && value.isEmpty())) { + expand(2); + content[count++] = '{'; + content[count++] = '}'; + } else { + byte[] bs1 = firstFieldBytes; + byte[] bs2 = Utility.latin1ByteArray(value); + int len1 = bs1.length; + int len2 = bs2.length; + byte[] src = expand(len1 + len2 + 3); + int c = count; + System.arraycopy(bs1, 0, src, c, len1); + c += len1; + src[c++] = '"'; + System.arraycopy(bs2, 0, src, c, len2); + c += len2; + src[c++] = '"'; + content[c++] = '}'; + count = c; + } + } + + @Override //firstFieldBytes 蹇呴』甯寮澶, lastFieldBytes蹇呴』,寮澶 + public void writeObjectByOnlyTwoIntFieldValue(final byte[] firstFieldBytes, final int value1, final byte[] lastFieldBytes, final int value2) { + byte[] bs1 = firstFieldBytes; + byte[] bs2 = (value1 >= 0 && value1 < TENTHOUSAND_MAX) ? TENTHOUSAND_BYTES[value1] : Utility.latin1ByteArray(String.valueOf(value1)); + byte[] bs3 = lastFieldBytes; + byte[] bs4 = (value2 >= 0 && value2 < TENTHOUSAND_MAX) ? TENTHOUSAND_BYTES[value2] : Utility.latin1ByteArray(String.valueOf(value2)); + int len1 = bs1.length; + int len2 = bs2.length; + int len3 = bs3.length; + int len4 = bs4.length; + byte[] src = expand(len1 + len2 + len3 + len4 + 1); + System.arraycopy(bs1, 0, src, count, len1); + count += len1; + System.arraycopy(bs2, 0, src, count, len2); + count += len2; + System.arraycopy(bs3, 0, src, count, len3); + count += len3; + System.arraycopy(bs4, 0, src, count, len4); + count += len4; + src[count++] = '}'; + } + + public JsonBytesWriter clear() { + this.count = 0; + return this; + } + + @Override + public boolean recycle() { + super.recycle(); + this.count = 0; + this.specify = null; + if (this.content != null && this.content.length > defaultSize * 100) { + this.content = new byte[defaultSize]; + } + return true; + } + + /** + * 鐩存帴鑾峰彇鍏ㄩ儴鏁版嵁, 瀹為檯鏁版嵁闇瑕佹牴鎹甤ount闀垮害鏉ユ埅鍙 + * + * @return byte[] + */ + public byte[] directBytes() { + return content; + } + + public void completed(ConvertBytesHandler handler, Consumer callback) { + handler.completed(content, 0, count, callback, this); + } + + public byte[] toBytes() { + byte[] copy = new byte[count]; + System.arraycopy(content, 0, copy, 0, count); + return copy; + } + + public int count() { + return this.count; + } + + private void writeEscapeLatinString(byte[] value) { + byte[] bytes = expand(value.length * 2 + 2); + int curr = count; + bytes[curr++] = '"'; + for (byte b : value) { + if (b == '"') { + bytes[curr++] = '\\'; + bytes[curr++] = '"'; + } else if (b == '\\') { + bytes[curr++] = '\\'; + bytes[curr++] = '\\'; + } else if (b < 32) { + if (b == '\n') { + bytes[curr++] = '\\'; + bytes[curr++] = 'n'; + } else if (b == '\r') { + bytes[curr++] = '\\'; + bytes[curr++] = 'r'; + } else if (b == '\t') { + bytes[curr++] = '\\'; + bytes[curr++] = 't'; + } else { + bytes[curr++] = b; + } + } else { + bytes[curr++] = b; + } + } + bytes[curr++] = '"'; + count = curr; + } + + @Override + public void writeString(String value) { + if (value == null) { + writeNull(); + return; + } + if (Utility.isLatin1(value)) { + writeEscapeLatinString(Utility.latin1ByteArray(value)); + return; + } + byte[] bytes = expand(value.length() * 4 + 2); + int curr = count; + bytes[curr++] = '"'; + int len = value.length(); + for (int i = 0; i < len; i++) { + char ch = value.charAt(i); + switch (ch) { + case '\n': + bytes[curr++] = '\\'; + bytes[curr++] = 'n'; + break; + case '\r': + bytes[curr++] = '\\'; + bytes[curr++] = 'r'; + break; + case '\t': + bytes[curr++] = '\\'; + bytes[curr++] = 't'; + break; + case '\\': + bytes[curr++] = '\\'; + bytes[curr++] = '\\'; + break; + case '"': + bytes[curr++] = '\\'; + bytes[curr++] = '"'; + break; + default: + if (ch < 0x80) { + bytes[curr++] = (byte) ch; + } else if (ch < 0x800) { + bytes[curr++] = (byte) (0xc0 | (ch >> 6)); + bytes[curr++] = (byte) (0x80 | (ch & 0x3f)); + } else if (Character.isSurrogate(ch)) { //杩炲彇涓や釜 + int uc = Character.toCodePoint(ch, value.charAt(++i)); + bytes[curr++] = (byte) (0xf0 | ((uc >> 18))); + bytes[curr++] = (byte) (0x80 | ((uc >> 12) & 0x3f)); + bytes[curr++] = (byte) (0x80 | ((uc >> 6) & 0x3f)); + bytes[curr++] = (byte) (0x80 | (uc & 0x3f)); + } else { + bytes[curr++] = (byte) (0xe0 | ((ch >> 12))); + bytes[curr++] = (byte) (0x80 | ((ch >> 6) & 0x3f)); + bytes[curr++] = (byte) (0x80 | (ch & 0x3f)); + } + break; + } + } + bytes[curr++] = '"'; + count = curr; + } + + @Override + public String toString() { + return new String(content, 0, count, StandardCharsets.UTF_8); + } + + //---------------------------------------------------------------------------------------------- + @Override + public void writeBoolean(boolean value) { + byte[] bs = value ? BYTES_TUREVALUE : BYTES_FALSEVALUE; + expand(bs.length); + System.arraycopy(bs, 0, content, count, bs.length); + count += bs.length; + } + + @Override + public void writeInt(int value) { + if (value >= 0 && value < TENTHOUSAND_MAX) { + byte[] bs = TENTHOUSAND_BYTES[value]; + expand(bs.length); + System.arraycopy(bs, 0, content, count, bs.length); + count += bs.length; + return; + } + final char sign = value >= 0 ? 0 : '-'; + if (value < 0) value = -value; + int size; + for (int i = 0;; i++) { + if (value <= sizeTable[i]) { + size = i + 1; + break; + } + } + if (sign != 0) size++; //璐熸暟 + byte[] bytes = expand(size); + + int q, r; + int charPos = count + size; + + // Generate two digits per iteration + while (value >= 65536) { + q = value / 100; + // really: r = i - (q * 100); + r = value - ((q << 6) + (q << 5) + (q << 2)); + value = q; + bytes[--charPos] = (byte) DigitOnes[r]; + bytes[--charPos] = (byte) DigitTens[r]; + } + + // Fall thru to fast mode for smaller numbers + // assert(i <= 65536, i); + for (;;) { + q = (value * 52429) >>> (16 + 3); + r = value - ((q << 3) + (q << 1)); // r = i-(q*10) ... + bytes[--charPos] = (byte) digits[r]; + value = q; + if (value == 0) break; + } + if (sign != 0) bytes[--charPos] = (byte) sign; + count += size; + } + + @Override + public void writeLong(long value) { + if (value >= 0 && value < TENTHOUSAND_MAX) { + byte[] bs = TENTHOUSAND_BYTES[(int) value]; + expand(bs.length); + System.arraycopy(bs, 0, content, count, bs.length); + count += bs.length; + return; + } + final char sign = value >= 0 ? 0 : '-'; + if (value < 0) value = -value; + int size = 19; + long p = 10; + for (int i = 1; i < 19; i++) { + if (value < p) { + size = i; + break; + } + p = 10 * p; + } + if (sign != 0) size++; //璐熸暟 + byte[] bytes = expand(size); + + long q; + int r; + int charPos = count + size; + + // Get 2 digits/iteration using longs until quotient fits into an int + while (value > Integer.MAX_VALUE) { + q = value / 100; + // really: r = i - (q * 100); + r = (int) (value - ((q << 6) + (q << 5) + (q << 2))); + value = q; + content[--charPos] = (byte) DigitOnes[r]; + content[--charPos] = (byte) DigitTens[r]; + } + + // Get 2 digits/iteration using ints + int q2; + int i2 = (int) value; + while (i2 >= 65536) { + q2 = i2 / 100; + // really: r = i2 - (q * 100); + r = i2 - ((q2 << 6) + (q2 << 5) + (q2 << 2)); + i2 = q2; + bytes[--charPos] = (byte) DigitOnes[r]; + bytes[--charPos] = (byte) DigitTens[r]; + } + + // Fall thru to fast mode for smaller numbers + // assert(i2 <= 65536, i2); + for (;;) { + q2 = (i2 * 52429) >>> (16 + 3); + r = i2 - ((q2 << 3) + (q2 << 1)); // r = i2-(q2*10) ... + bytes[--charPos] = (byte) digits[r]; + i2 = q2; + if (i2 == 0) break; + } + if (sign != 0) bytes[--charPos] = (byte) sign; + count += size; + } + +} diff --git a/src/main/java/org/redkale/convert/json/JsonCharsWriter.java b/src/main/java/org/redkale/convert/json/JsonCharsWriter.java index 8f9ca1404..cb481cbeb 100644 --- a/src/main/java/org/redkale/convert/json/JsonCharsWriter.java +++ b/src/main/java/org/redkale/convert/json/JsonCharsWriter.java @@ -1,461 +1,461 @@ -/* - * 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.convert.json; - -import java.nio.ByteBuffer; -import org.redkale.util.*; - -/** - * - * writeTo绯诲垪鐨勬柟娉曡緭鍑虹殑瀛楃涓嶈兘鍚壒娈婂瓧绗 - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * - * @since 2.3.0 - * - * @deprecated 2.5.0 JDK9浠ヤ笂鐢╞yte[]浠f浛char[]浼氭湁鏇村ソ鐨勬ц兘 - */ -@Deprecated -public class JsonCharsWriter extends JsonWriter { - - private static final char[] CHARS_TUREVALUE = "true".toCharArray(); - - private static final char[] CHARS_FALSEVALUE = "false".toCharArray(); - - private static final int TENTHOUSAND_MAX = 10001; - - private static final char[][] TENTHOUSAND_BYTES = new char[TENTHOUSAND_MAX][]; - - static { - for (int i = 0; i < TENTHOUSAND_BYTES.length; i++) { - TENTHOUSAND_BYTES[i] = String.valueOf(i).toCharArray(); - } - } - - private int count; - - private char[] content; - - public JsonCharsWriter() { - this(defaultSize); - } - - public JsonCharsWriter(int size) { - this.content = new char[size > 1024 ? size : 1024]; - } - - //----------------------------------------------------------------------- - /** - * 杩斿洖鎸囧畾鑷冲皯鎸囧畾闀垮害鐨勭紦鍐插尯 - * - * @param len - * - * @return - */ - private char[] expand(int len) { - int newcount = count + len; - if (newcount <= content.length) return content; - char[] newdata = new char[Math.max(content.length * 3 / 2, newcount)]; - System.arraycopy(content, 0, newdata, 0, count); - this.content = newdata; - return newdata; - } - - @Override - public void writeTo(final char ch) { //鍙兘鏄 0 - 127 鐨勫瓧绗 - expand(1); - content[count++] = ch; - } - - @Override - public void writeTo(final char[] chs, final int start, final int len) { //鍙兘鏄 0 - 127 鐨勫瓧绗 - expand(len); - System.arraycopy(chs, start, content, count, len); - count += len; - } - - @Override - public void writeTo(final byte ch) { //鍙兘鏄 0 - 127 鐨勫瓧绗 - expand(1); - content[count++] = (char) ch; - } - - @Override - public void writeTo(final byte[] chs, final int start, final int len) { //鍙兘鏄 0 - 127 鐨勫瓧绗 - expand(len); - for (int i = 0; i < len; i++) { - content[count + i] = (char) chs[start + i]; - } - count += len; - } - - /** - * 娉ㄦ剰锛 璇tring鍊间笉鑳戒负null涓斾笉浼氳繘琛岃浆涔夛紝 鍙敤浜庝笉鍚渶瑕佽浆涔夊瓧绗︾殑瀛楃涓诧紝渚嬪enum銆乨ouble銆丅igInteger杞崲鐨凷tring - * - * @param quote 鏄惁鍔犲弻寮曞彿 - * @param value 闈瀗ull涓斾笉鍚渶瑕佽浆涔夌殑瀛楃鐨凷tring鍊 - */ - @Override - public void writeLatin1To(final boolean quote, final String value) { - int len = value.length(); - expand(len + (quote ? 2 : 0)); - if (quote) content[count++] = '"'; - value.getChars(0, len, content, count); - count += len; - if (quote) content[count++] = '"'; - } - - @Override - public void writeFieldShortValue(final byte[] fieldBytes, final short value) { - String val = String.valueOf(value); - int len1 = fieldBytes.length; - int len2 = val.length(); - expand(len1 + len2); - for (int i = 0; i < len1; i++) { - content[count + i] = (char) fieldBytes[i]; - } - count += len1; - val.getChars(0, len2, content, count); - count += len2; - } - - @Override - public void writeFieldIntValue(final byte[] fieldBytes, final int value) { - String val = String.valueOf(value); - int len1 = fieldBytes.length; - int len2 = val.length(); - expand(len1 + len2); - for (int i = 0; i < len1; i++) { - content[count + i] = (char) fieldBytes[i]; - } - count += len1; - val.getChars(0, len2, content, count); - count += len2; - } - - @Override - public void writeFieldLongValue(final byte[] fieldBytes, final long value) { - String val = String.valueOf(value); - int len1 = fieldBytes.length; - int len2 = val.length(); - expand(len1 + len2); - for (int i = 0; i < len1; i++) { - content[count + i] = (char) fieldBytes[i]; - } - count += len1; - val.getChars(0, len2, content, count); - count += len2; - } - - @Override - public void writeFieldLatin1Value(final byte[] fieldBytes, final String value) { - int len1 = fieldBytes.length; - int len2 = value.length(); - expand(len1 + len2 + 2); - for (int i = 0; i < len1; i++) { - content[count + i] = (char) fieldBytes[i]; - } - count += len1; - content[count++] = '"'; - value.getChars(0, len2, content, count); - count += len2; - content[count++] = '"'; - } - - @Override - public void writeLastFieldShortValue(final byte[] fieldBytes, final short value) { - String val = String.valueOf(value); - int len1 = fieldBytes.length; - int len2 = val.length(); - expand(len1 + len2 + 1); - for (int i = 0; i < len1; i++) { - content[count + i] = (char) fieldBytes[i]; - } - count += len1; - val.getChars(0, len2, content, count); - count += len2; - content[count++] = '}'; - } - - @Override - public void writeLastFieldIntValue(final byte[] fieldBytes, final int value) { - String val = String.valueOf(value); - int len1 = fieldBytes.length; - int len2 = val.length(); - expand(len1 + len2 + 1); - for (int i = 0; i < len1; i++) { - content[count + i] = (char) fieldBytes[i]; - } - count += len1; - val.getChars(0, len2, content, count); - count += len2; - content[count++] = '}'; - } - - @Override - public void writeLastFieldLongValue(final byte[] fieldBytes, final long value) { - String val = String.valueOf(value); - int len1 = fieldBytes.length; - int len2 = val.length(); - expand(len1 + len2 + 1); - for (int i = 0; i < len1; i++) { - content[count + i] = (char) fieldBytes[i]; - } - count += len1; - val.getChars(0, len2, content, count); - count += len2; - content[count++] = '}'; - } - - @Override - public void writeLastFieldLatin1Value(final byte[] fieldBytes, final String value) { - if (value == null || (tiny && value.isEmpty())) { - expand(1); - content[count++] = '}'; - } else { - int len1 = fieldBytes.length; - int len2 = value.length(); - expand(len1 + len2 + 3); - for (int i = 0; i < len1; i++) { - content[count + i] = (char) fieldBytes[i]; - } - count += len1; - content[count++] = '"'; - value.getChars(0, len2, content, count); - count += len2; - content[count++] = '"'; - content[count++] = '}'; - } - } - - @Override //firstFieldBytes 蹇呴』甯寮澶 - public void writeObjectByOnlyOneLatin1FieldValue(final byte[] firstFieldBytes, final String value) { - if (value == null || (tiny && value.isEmpty())) { - expand(2); - content[count++] = '{'; - content[count++] = '}'; - } else { - byte[] fieldBytes = firstFieldBytes; - int len1 = fieldBytes.length; - int len2 = value.length(); - expand(len1 + len2 + 3); - for (int i = 0; i < len1; i++) { - content[count + i] = (char) fieldBytes[i]; - } - count += len1; - content[count++] = '"'; - value.getChars(0, len2, content, count); - count += len2; - content[count++] = '"'; - content[count++] = '}'; - } - } - - @Override //firstFieldBytes 蹇呴』甯寮澶, lastFieldBytes蹇呴』,寮澶 - public void writeObjectByOnlyTwoIntFieldValue(final byte[] firstFieldBytes, final int value1, final byte[] lastFieldBytes, final int value2) { - String val1 = String.valueOf(value1); - String val2 = String.valueOf(value2); - int len1 = firstFieldBytes.length; - int len2 = val1.length(); - int len3 = lastFieldBytes.length; - int len4 = val2.length(); - expand(len1 + len2 + len3 + len4 + 1); - - for (int i = 0; i < len1; i++) { - content[count + i] = (char) firstFieldBytes[i]; - } - count += len1; - val1.getChars(0, len2, content, count); - count += len2; - - for (int i = 0; i < len3; i++) { - content[count + i] = (char) lastFieldBytes[i]; - } - count += len3; - val2.getChars(0, len4, content, count); - count += len4; - - content[count++] = '}'; - } - - @Override - protected boolean recycle() { - super.recycle(); - this.count = 0; - this.specify = null; - if (this.content != null && this.content.length > defaultSize) { - this.content = new char[defaultSize]; - } - return true; - } - - public ByteBuffer[] toBuffers() { - return new ByteBuffer[]{ByteBuffer.wrap(Utility.encodeUTF8(content, 0, count))}; - } - - public byte[] toBytes() { - return Utility.encodeUTF8(content, 0, count); - } - - public int count() { - return this.count; - } - - @Override - public void writeString(String value) { - if (value == null) { - writeNull(); - return; - } - expand(value.length() * 2 + 2); - content[count++] = '"'; - for (char ch : Utility.charArray(value)) { - switch (ch) { - case '\n': - content[count++] = '\\'; - content[count++] = 'n'; - break; - case '\r': - content[count++] = '\\'; - content[count++] = 'r'; - break; - case '\t': - content[count++] = '\\'; - content[count++] = 't'; - break; - case '\\': - content[count++] = '\\'; - content[count++] = ch; - break; - case '"': - content[count++] = '\\'; - content[count++] = ch; - break; - default: - content[count++] = ch; - break; - } - } - content[count++] = '"'; - } - - @Override - public String toString() { - return new String(content, 0, count); - } - - //---------------------------------------------------------------------------------------------- - @Override - public void writeBoolean(boolean value) { - writeTo(value ? CHARS_TUREVALUE : CHARS_FALSEVALUE); - } - - @Override - public void writeInt(int value) { - if (value >= 0 && value < TENTHOUSAND_MAX) { - writeTo(TENTHOUSAND_BYTES[value]); - return; - } - final char sign = value >= 0 ? 0 : '-'; - if (value < 0) value = -value; - int size; - for (int i = 0;; i++) { - if (value <= sizeTable[i]) { - size = i + 1; - break; - } - } - if (sign != 0) size++; //璐熸暟 - expand(size); - - int q, r; - int charPos = count + size; - - // Generate two digits per iteration - while (value >= 65536) { - q = value / 100; - // really: r = i - (q * 100); - r = value - ((q << 6) + (q << 5) + (q << 2)); - value = q; - content[--charPos] = DigitOnes[r]; - content[--charPos] = DigitTens[r]; - } - - // Fall thru to fast mode for smaller numbers - // assert(i <= 65536, i); - for (;;) { - q = (value * 52429) >>> (16 + 3); - r = value - ((q << 3) + (q << 1)); // r = i-(q*10) ... - content[--charPos] = digits[r]; - value = q; - if (value == 0) break; - } - if (sign != 0) content[--charPos] = sign; - count += size; - } - - @Override - public void writeLong(long value) { - if (value >= 0 && value < TENTHOUSAND_MAX) { - writeTo(TENTHOUSAND_BYTES[(int) value]); - return; - } - final char sign = value >= 0 ? 0 : '-'; - if (value < 0) value = -value; - int size = 19; - long p = 10; - for (int i = 1; i < 19; i++) { - if (value < p) { - size = i; - break; - } - p = 10 * p; - } - if (sign != 0) size++; //璐熸暟 - expand(size); - - long q; - int r; - int charPos = count + size; - - // Get 2 digits/iteration using longs until quotient fits into an int - while (value > Integer.MAX_VALUE) { - q = value / 100; - // really: r = i - (q * 100); - r = (int) (value - ((q << 6) + (q << 5) + (q << 2))); - value = q; - content[--charPos] = DigitOnes[r]; - content[--charPos] = DigitTens[r]; - } - - // Get 2 digits/iteration using ints - int q2; - int i2 = (int) value; - while (i2 >= 65536) { - q2 = i2 / 100; - // really: r = i2 - (q * 100); - r = i2 - ((q2 << 6) + (q2 << 5) + (q2 << 2)); - i2 = q2; - content[--charPos] = DigitOnes[r]; - content[--charPos] = DigitTens[r]; - } - - // Fall thru to fast mode for smaller numbers - // assert(i2 <= 65536, i2); - for (;;) { - q2 = (i2 * 52429) >>> (16 + 3); - r = i2 - ((q2 << 3) + (q2 << 1)); // r = i2-(q2*10) ... - content[--charPos] = digits[r]; - i2 = q2; - if (i2 == 0) break; - } - if (sign != 0) content[--charPos] = sign; - count += size; - } - -} +/* + * 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.convert.json; + +import java.nio.ByteBuffer; +import org.redkale.util.*; + +/** + * + * writeTo绯诲垪鐨勬柟娉曡緭鍑虹殑瀛楃涓嶈兘鍚壒娈婂瓧绗 + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.3.0 + * + * @deprecated 2.5.0 JDK9浠ヤ笂鐢╞yte[]浠f浛char[]浼氭湁鏇村ソ鐨勬ц兘 + */ +@Deprecated +public class JsonCharsWriter extends JsonWriter { + + private static final char[] CHARS_TUREVALUE = "true".toCharArray(); + + private static final char[] CHARS_FALSEVALUE = "false".toCharArray(); + + private static final int TENTHOUSAND_MAX = 10001; + + private static final char[][] TENTHOUSAND_BYTES = new char[TENTHOUSAND_MAX][]; + + static { + for (int i = 0; i < TENTHOUSAND_BYTES.length; i++) { + TENTHOUSAND_BYTES[i] = String.valueOf(i).toCharArray(); + } + } + + private int count; + + private char[] content; + + public JsonCharsWriter() { + this(defaultSize); + } + + public JsonCharsWriter(int size) { + this.content = new char[size > 1024 ? size : 1024]; + } + + //----------------------------------------------------------------------- + /** + * 杩斿洖鎸囧畾鑷冲皯鎸囧畾闀垮害鐨勭紦鍐插尯 + * + * @param len + * + * @return + */ + private char[] expand(int len) { + int newcount = count + len; + if (newcount <= content.length) return content; + char[] newdata = new char[Math.max(content.length * 3 / 2, newcount)]; + System.arraycopy(content, 0, newdata, 0, count); + this.content = newdata; + return newdata; + } + + @Override + public void writeTo(final char ch) { //鍙兘鏄 0 - 127 鐨勫瓧绗 + expand(1); + content[count++] = ch; + } + + @Override + public void writeTo(final char[] chs, final int start, final int len) { //鍙兘鏄 0 - 127 鐨勫瓧绗 + expand(len); + System.arraycopy(chs, start, content, count, len); + count += len; + } + + @Override + public void writeTo(final byte ch) { //鍙兘鏄 0 - 127 鐨勫瓧绗 + expand(1); + content[count++] = (char) ch; + } + + @Override + public void writeTo(final byte[] chs, final int start, final int len) { //鍙兘鏄 0 - 127 鐨勫瓧绗 + expand(len); + for (int i = 0; i < len; i++) { + content[count + i] = (char) chs[start + i]; + } + count += len; + } + + /** + * 娉ㄦ剰锛 璇tring鍊间笉鑳戒负null涓斾笉浼氳繘琛岃浆涔夛紝 鍙敤浜庝笉鍚渶瑕佽浆涔夊瓧绗︾殑瀛楃涓诧紝渚嬪enum銆乨ouble銆丅igInteger杞崲鐨凷tring + * + * @param quote 鏄惁鍔犲弻寮曞彿 + * @param value 闈瀗ull涓斾笉鍚渶瑕佽浆涔夌殑瀛楃鐨凷tring鍊 + */ + @Override + public void writeLatin1To(final boolean quote, final String value) { + int len = value.length(); + expand(len + (quote ? 2 : 0)); + if (quote) content[count++] = '"'; + value.getChars(0, len, content, count); + count += len; + if (quote) content[count++] = '"'; + } + + @Override + public void writeFieldShortValue(final byte[] fieldBytes, final short value) { + String val = String.valueOf(value); + int len1 = fieldBytes.length; + int len2 = val.length(); + expand(len1 + len2); + for (int i = 0; i < len1; i++) { + content[count + i] = (char) fieldBytes[i]; + } + count += len1; + val.getChars(0, len2, content, count); + count += len2; + } + + @Override + public void writeFieldIntValue(final byte[] fieldBytes, final int value) { + String val = String.valueOf(value); + int len1 = fieldBytes.length; + int len2 = val.length(); + expand(len1 + len2); + for (int i = 0; i < len1; i++) { + content[count + i] = (char) fieldBytes[i]; + } + count += len1; + val.getChars(0, len2, content, count); + count += len2; + } + + @Override + public void writeFieldLongValue(final byte[] fieldBytes, final long value) { + String val = String.valueOf(value); + int len1 = fieldBytes.length; + int len2 = val.length(); + expand(len1 + len2); + for (int i = 0; i < len1; i++) { + content[count + i] = (char) fieldBytes[i]; + } + count += len1; + val.getChars(0, len2, content, count); + count += len2; + } + + @Override + public void writeFieldLatin1Value(final byte[] fieldBytes, final String value) { + int len1 = fieldBytes.length; + int len2 = value.length(); + expand(len1 + len2 + 2); + for (int i = 0; i < len1; i++) { + content[count + i] = (char) fieldBytes[i]; + } + count += len1; + content[count++] = '"'; + value.getChars(0, len2, content, count); + count += len2; + content[count++] = '"'; + } + + @Override + public void writeLastFieldShortValue(final byte[] fieldBytes, final short value) { + String val = String.valueOf(value); + int len1 = fieldBytes.length; + int len2 = val.length(); + expand(len1 + len2 + 1); + for (int i = 0; i < len1; i++) { + content[count + i] = (char) fieldBytes[i]; + } + count += len1; + val.getChars(0, len2, content, count); + count += len2; + content[count++] = '}'; + } + + @Override + public void writeLastFieldIntValue(final byte[] fieldBytes, final int value) { + String val = String.valueOf(value); + int len1 = fieldBytes.length; + int len2 = val.length(); + expand(len1 + len2 + 1); + for (int i = 0; i < len1; i++) { + content[count + i] = (char) fieldBytes[i]; + } + count += len1; + val.getChars(0, len2, content, count); + count += len2; + content[count++] = '}'; + } + + @Override + public void writeLastFieldLongValue(final byte[] fieldBytes, final long value) { + String val = String.valueOf(value); + int len1 = fieldBytes.length; + int len2 = val.length(); + expand(len1 + len2 + 1); + for (int i = 0; i < len1; i++) { + content[count + i] = (char) fieldBytes[i]; + } + count += len1; + val.getChars(0, len2, content, count); + count += len2; + content[count++] = '}'; + } + + @Override + public void writeLastFieldLatin1Value(final byte[] fieldBytes, final String value) { + if (value == null || (tiny && value.isEmpty())) { + expand(1); + content[count++] = '}'; + } else { + int len1 = fieldBytes.length; + int len2 = value.length(); + expand(len1 + len2 + 3); + for (int i = 0; i < len1; i++) { + content[count + i] = (char) fieldBytes[i]; + } + count += len1; + content[count++] = '"'; + value.getChars(0, len2, content, count); + count += len2; + content[count++] = '"'; + content[count++] = '}'; + } + } + + @Override //firstFieldBytes 蹇呴』甯寮澶 + public void writeObjectByOnlyOneLatin1FieldValue(final byte[] firstFieldBytes, final String value) { + if (value == null || (tiny && value.isEmpty())) { + expand(2); + content[count++] = '{'; + content[count++] = '}'; + } else { + byte[] fieldBytes = firstFieldBytes; + int len1 = fieldBytes.length; + int len2 = value.length(); + expand(len1 + len2 + 3); + for (int i = 0; i < len1; i++) { + content[count + i] = (char) fieldBytes[i]; + } + count += len1; + content[count++] = '"'; + value.getChars(0, len2, content, count); + count += len2; + content[count++] = '"'; + content[count++] = '}'; + } + } + + @Override //firstFieldBytes 蹇呴』甯寮澶, lastFieldBytes蹇呴』,寮澶 + public void writeObjectByOnlyTwoIntFieldValue(final byte[] firstFieldBytes, final int value1, final byte[] lastFieldBytes, final int value2) { + String val1 = String.valueOf(value1); + String val2 = String.valueOf(value2); + int len1 = firstFieldBytes.length; + int len2 = val1.length(); + int len3 = lastFieldBytes.length; + int len4 = val2.length(); + expand(len1 + len2 + len3 + len4 + 1); + + for (int i = 0; i < len1; i++) { + content[count + i] = (char) firstFieldBytes[i]; + } + count += len1; + val1.getChars(0, len2, content, count); + count += len2; + + for (int i = 0; i < len3; i++) { + content[count + i] = (char) lastFieldBytes[i]; + } + count += len3; + val2.getChars(0, len4, content, count); + count += len4; + + content[count++] = '}'; + } + + @Override + protected boolean recycle() { + super.recycle(); + this.count = 0; + this.specify = null; + if (this.content != null && this.content.length > defaultSize) { + this.content = new char[defaultSize]; + } + return true; + } + + public ByteBuffer[] toBuffers() { + return new ByteBuffer[]{ByteBuffer.wrap(Utility.encodeUTF8(content, 0, count))}; + } + + public byte[] toBytes() { + return Utility.encodeUTF8(content, 0, count); + } + + public int count() { + return this.count; + } + + @Override + public void writeString(String value) { + if (value == null) { + writeNull(); + return; + } + expand(value.length() * 2 + 2); + content[count++] = '"'; + for (char ch : Utility.charArray(value)) { + switch (ch) { + case '\n': + content[count++] = '\\'; + content[count++] = 'n'; + break; + case '\r': + content[count++] = '\\'; + content[count++] = 'r'; + break; + case '\t': + content[count++] = '\\'; + content[count++] = 't'; + break; + case '\\': + content[count++] = '\\'; + content[count++] = ch; + break; + case '"': + content[count++] = '\\'; + content[count++] = ch; + break; + default: + content[count++] = ch; + break; + } + } + content[count++] = '"'; + } + + @Override + public String toString() { + return new String(content, 0, count); + } + + //---------------------------------------------------------------------------------------------- + @Override + public void writeBoolean(boolean value) { + writeTo(value ? CHARS_TUREVALUE : CHARS_FALSEVALUE); + } + + @Override + public void writeInt(int value) { + if (value >= 0 && value < TENTHOUSAND_MAX) { + writeTo(TENTHOUSAND_BYTES[value]); + return; + } + final char sign = value >= 0 ? 0 : '-'; + if (value < 0) value = -value; + int size; + for (int i = 0;; i++) { + if (value <= sizeTable[i]) { + size = i + 1; + break; + } + } + if (sign != 0) size++; //璐熸暟 + expand(size); + + int q, r; + int charPos = count + size; + + // Generate two digits per iteration + while (value >= 65536) { + q = value / 100; + // really: r = i - (q * 100); + r = value - ((q << 6) + (q << 5) + (q << 2)); + value = q; + content[--charPos] = DigitOnes[r]; + content[--charPos] = DigitTens[r]; + } + + // Fall thru to fast mode for smaller numbers + // assert(i <= 65536, i); + for (;;) { + q = (value * 52429) >>> (16 + 3); + r = value - ((q << 3) + (q << 1)); // r = i-(q*10) ... + content[--charPos] = digits[r]; + value = q; + if (value == 0) break; + } + if (sign != 0) content[--charPos] = sign; + count += size; + } + + @Override + public void writeLong(long value) { + if (value >= 0 && value < TENTHOUSAND_MAX) { + writeTo(TENTHOUSAND_BYTES[(int) value]); + return; + } + final char sign = value >= 0 ? 0 : '-'; + if (value < 0) value = -value; + int size = 19; + long p = 10; + for (int i = 1; i < 19; i++) { + if (value < p) { + size = i; + break; + } + p = 10 * p; + } + if (sign != 0) size++; //璐熸暟 + expand(size); + + long q; + int r; + int charPos = count + size; + + // Get 2 digits/iteration using longs until quotient fits into an int + while (value > Integer.MAX_VALUE) { + q = value / 100; + // really: r = i - (q * 100); + r = (int) (value - ((q << 6) + (q << 5) + (q << 2))); + value = q; + content[--charPos] = DigitOnes[r]; + content[--charPos] = DigitTens[r]; + } + + // Get 2 digits/iteration using ints + int q2; + int i2 = (int) value; + while (i2 >= 65536) { + q2 = i2 / 100; + // really: r = i2 - (q * 100); + r = i2 - ((q2 << 6) + (q2 << 5) + (q2 << 2)); + i2 = q2; + content[--charPos] = DigitOnes[r]; + content[--charPos] = DigitTens[r]; + } + + // Fall thru to fast mode for smaller numbers + // assert(i2 <= 65536, i2); + for (;;) { + q2 = (i2 * 52429) >>> (16 + 3); + r = i2 - ((q2 << 3) + (q2 << 1)); // r = i2-(q2*10) ... + content[--charPos] = digits[r]; + i2 = q2; + if (i2 == 0) break; + } + if (sign != 0) content[--charPos] = sign; + count += size; + } + +} diff --git a/src/main/java/org/redkale/convert/json/JsonConvert.java b/src/main/java/org/redkale/convert/json/JsonConvert.java index e4d6a96ff..e4365f641 100644 --- a/src/main/java/org/redkale/convert/json/JsonConvert.java +++ b/src/main/java/org/redkale/convert/json/JsonConvert.java @@ -1,388 +1,388 @@ -/* - * 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.convert.json; - -import java.io.*; -import java.lang.reflect.*; -import java.nio.*; -import java.nio.charset.*; -import java.util.function.*; -import org.redkale.convert.*; -import org.redkale.service.RetResult; -import org.redkale.util.*; - -/** - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@SuppressWarnings("unchecked") -public class JsonConvert extends TextConvert { - - public static final Type TYPE_MAP_STRING_STRING = new TypeToken>() { - }.getType(); - - public static final Type TYPE_RETRESULT_STRING = new TypeToken>() { - }.getType(); - - private final ThreadLocal bytesWriterPool = ThreadLocal.withInitial(JsonBytesWriter::new); - - private final Consumer offerBytesConsumer = w -> offerJsonBytesWriter(w); - - private final boolean tiny; - - private Encodeable lastConvertEncodeable; - - private Decodeable lastConvertDecodeable; - - protected JsonConvert(JsonFactory factory, boolean tiny) { - super(factory); - this.tiny = tiny; - } - - @Override - public JsonFactory getFactory() { - return (JsonFactory) factory; - } - - public static JsonConvert root() { - return JsonFactory.root().getConvert(); - } - - @Override - public JsonConvert newConvert(final BiFunction fieldFunc) { - return newConvert(fieldFunc, null); - } - - @Override - public JsonConvert newConvert(final BiFunction fieldFunc, Function objExtFunc) { - return new JsonConvert(getFactory(), tiny) { - @Override - protected S configWrite(S writer) { - return fieldFunc(writer, fieldFunc, objExtFunc); - } - }; - } - - //------------------------------ writer ----------------------------------------------------------- - private JsonBytesWriter pollJsonBytesWriter() { - JsonBytesWriter writer = bytesWriterPool.get(); - if (writer == null) { - writer = new JsonBytesWriter(); - } else { - bytesWriterPool.set(null); - } - return configWrite((JsonBytesWriter) writer.tiny(tiny)); - } - - private void offerJsonBytesWriter(final JsonBytesWriter writer) { - if (writer != null) { - writer.recycle(); - bytesWriterPool.set(writer); - } - } - - //------------------------------ convertFrom ----------------------------------------------------------- - @Override - public T convertFrom(final Type type, final byte[] bytes) { - if (bytes == null) return null; - return convertFrom(type, new String(bytes, StandardCharsets.UTF_8)); - } - - @Override - public T convertFrom(final Type type, final byte[] bytes, final int offset, final int length) { - if (bytes == null) return null; - return convertFrom(type, new String(bytes, offset, length, StandardCharsets.UTF_8)); - } - - public T convertFrom(final Type type, final String text) { - if (text == null) return null; - return convertFrom(type, Utility.charArray(text)); - } - - public T convertFrom(final Type type, final char[] text) { - if (text == null) return null; - return convertFrom(type, text, 0, text.length); - } - - public T convertFrom(final Type type, final char[] text, final int offset, final int length) { - if (text == null || type == null) return null; - Decodeable decoder = this.lastConvertDecodeable; - if (decoder == null || decoder.getType() != type) { - decoder = factory.loadDecoder(type); - this.lastConvertDecodeable = decoder; - } - T rs = (T) decoder.convertFrom(new JsonReader(text, offset, length)); - return rs; - } - - public T convertFrom(final Type type, final InputStream in) { - if (type == null || in == null) return null; - Decodeable decoder = this.lastConvertDecodeable; - if (decoder == null || decoder.getType() != type) { - decoder = factory.loadDecoder(type); - this.lastConvertDecodeable = decoder; - } - return (T) decoder.convertFrom(new JsonStreamReader(in)); - } - - @Override - public T convertFrom(final Type type, final ByteBuffer... buffers) { - if (type == null || buffers == null || buffers.length == 0) return null; - Decodeable decoder = this.lastConvertDecodeable; - if (decoder == null || decoder.getType() != type) { - decoder = factory.loadDecoder(type); - this.lastConvertDecodeable = decoder; - } - return (T) decoder.convertFrom(new JsonByteBufferReader((ConvertMask) null, buffers)); - } - - @Override - public T convertFrom(final Type type, final ConvertMask mask, final ByteBuffer... buffers) { - if (type == null || buffers == null || buffers.length == 0) return null; - Decodeable decoder = this.lastConvertDecodeable; - if (decoder == null || decoder.getType() != type) { - decoder = factory.loadDecoder(type); - this.lastConvertDecodeable = decoder; - } - return (T) decoder.convertFrom(new JsonByteBufferReader(mask, buffers)); - } - - public T convertFrom(final Type type, final JsonReader reader) { - if (type == null) return null; - Decodeable decoder = this.lastConvertDecodeable; - if (decoder == null || decoder.getType() != type) { - decoder = factory.loadDecoder(type); - this.lastConvertDecodeable = decoder; - } - @SuppressWarnings("unchecked") - T rs = (T) decoder.convertFrom(reader); - return rs; - } - - //杩斿洖闈瀗ull鐨勫兼槸鐢盨tring銆丄rrayList銆丠ashMap浠绘剰缁勫悎鐨勫璞 - public V convertFrom(final String text) { - if (text == null) return null; - return (V) convertFrom(Utility.charArray(text)); - } - - //杩斿洖闈瀗ull鐨勫兼槸鐢盨tring銆丄rrayList銆丠ashMap浠绘剰缁勫悎鐨勫璞 - public V convertFrom(final char[] text) { - if (text == null) return null; - return (V) convertFrom(text, 0, text.length); - } - - //杩斿洖闈瀗ull鐨勫兼槸鐢盨tring銆丄rrayList銆丠ashMap浠绘剰缁勫悎鐨勫璞 - public V convertFrom(final char[] text, final int offset, final int length) { - if (text == null) return null; - //final JsonReader in = readerPool.get(); - //in.setText(text, offset, length); - Object rs = new AnyDecoder(factory).convertFrom(new JsonReader(text, offset, length)); - //readerPool.accept(in); - return (V) rs; - } - - //杩斿洖闈瀗ull鐨勫兼槸鐢盨tring銆丄rrayList銆丠ashMap浠绘剰缁勫悎鐨勫璞 - public V convertFrom(final InputStream in) { - if (in == null) return null; - return (V) new AnyDecoder(factory).convertFrom(new JsonStreamReader(in)); - } - - //杩斿洖闈瀗ull鐨勫兼槸鐢盨tring銆丄rrayList銆丠ashMap浠绘剰缁勫悎鐨勫璞 - public V convertFrom(final ByteBuffer... buffers) { - if (buffers == null || buffers.length == 0) return null; - return (V) new AnyDecoder(factory).convertFrom(new JsonByteBufferReader((ConvertMask) null, buffers)); - } - - //杩斿洖闈瀗ull鐨勫兼槸鐢盨tring銆丄rrayList銆丠ashMap浠绘剰缁勫悎鐨勫璞 - public V convertFrom(final ConvertMask mask, final ByteBuffer... buffers) { - if (buffers == null || buffers.length == 0) return null; - return (V) new AnyDecoder(factory).convertFrom(new JsonByteBufferReader(mask, buffers)); - } - - //杩斿洖闈瀗ull鐨勫兼槸鐢盨tring銆丄rrayList銆丠ashMap浠绘剰缁勫悎鐨勫璞 - public V convertFrom(final JsonReader reader) { - if (reader == null) return null; - return (V) new AnyDecoder(factory).convertFrom(reader); - } - - //------------------------------ convertTo ----------------------------------------------------------- - @Override - public String convertTo(final Object value) { - if (value == null) return "null"; - return convertTo(value.getClass(), value); - } - - @Override - public String convertTo(final Type type, final Object value) { - if (type == null) return null; - if (value == null) return "null"; - JsonBytesWriter writer = pollJsonBytesWriter(); - Encodeable encoder = this.lastConvertEncodeable; - if (encoder == null || encoder.getType() != type) { - encoder = factory.loadEncoder(type); - this.lastConvertEncodeable = encoder; - } - if (encoder.specifyable()) writer.specify(type); - encoder.convertTo(writer, value); - - String result = writer.toString(); - offerJsonBytesWriter(writer); - return result; - } - - @Override - public byte[] convertToBytes(final Object value) { - if (value == null) return null; - return convertToBytes(value.getClass(), value); - } - - @Override - public byte[] convertToBytes(final Type type, final Object value) { - if (type == null) return null; - if (value == null) return null; - JsonBytesWriter writer = pollJsonBytesWriter(); - Encodeable encoder = this.lastConvertEncodeable; - if (encoder == null || encoder.getType() != type) { - encoder = factory.loadEncoder(type); - this.lastConvertEncodeable = encoder; - } - if (encoder.specifyable()) writer.specify(type); - encoder.convertTo(writer, value); - - byte[] result = writer.toBytes(); - offerJsonBytesWriter(writer); - return result; - } - - @Override - public void convertToBytes(final Object value, final ConvertBytesHandler handler) { - convertToBytes(value == null ? null : value.getClass(), value, handler); - } - - @Override - public void convertToBytes(final Type type, final Object value, final ConvertBytesHandler handler) { - JsonBytesWriter writer = pollJsonBytesWriter(); - if (type == null) { - writer.writeNull(); - } else { - Encodeable encoder = this.lastConvertEncodeable; - if (encoder == null || encoder.getType() != type) { - encoder = factory.loadEncoder(type); - this.lastConvertEncodeable = encoder; - } - if (encoder.specifyable()) writer.specify(type); - encoder.convertTo(writer, value); - } - writer.completed(handler, offerBytesConsumer); - } - - @Override - public void convertToBytes(final ByteArray array, final Object value) { - convertToBytes(array, value == null ? null : value.getClass(), value); - } - - @Override - public void convertToBytes(final ByteArray array, final Type type, final Object value) { - JsonBytesWriter writer = configWrite(new JsonBytesWriter(tiny, array)); - if (type == null) { - writer.writeNull(); - } else { - Encodeable encoder = this.lastConvertEncodeable; - if (encoder == null || encoder.getType() != type) { - encoder = factory.loadEncoder(type); - this.lastConvertEncodeable = encoder; - } - if (encoder.specifyable()) writer.specify(type); - encoder.convertTo(writer, value); - } - writer.directTo(array); - } - - public void convertTo(final OutputStream out, final Object value) { - if (value == null) { - configWrite(new JsonStreamWriter(tiny, out)).writeNull(); - } else { - convertTo(out, value.getClass(), value); - } - } - - public void convertTo(final OutputStream out, final Type type, final Object value) { - if (type == null) return; - if (value == null) { - configWrite(new JsonStreamWriter(tiny, out)).writeNull(); - } else { - JsonStreamWriter writer = configWrite(new JsonStreamWriter(tiny, out)); - Encodeable encoder = this.lastConvertEncodeable; - if (encoder == null || encoder.getType() != type) { - encoder = factory.loadEncoder(type); - this.lastConvertEncodeable = encoder; - } - if (encoder.specifyable()) writer.specify(type); - encoder.convertTo(writer, value); - } - } - - @Override - public ByteBuffer[] convertTo(final Supplier supplier, final Object value) { - if (supplier == null) return null; - JsonByteBufferWriter out = configWrite(new JsonByteBufferWriter(tiny, supplier)); - if (value == null) { - out.writeNull(); - } else { - factory.loadEncoder(value.getClass()).convertTo(out, value); - } - return out.toBuffers(); - } - - @Override - public ByteBuffer[] convertTo(final Supplier supplier, final Type type, final Object value) { - if (supplier == null || type == null) return null; - JsonByteBufferWriter out = configWrite(new JsonByteBufferWriter(tiny, supplier)); - if (value == null) { - out.writeNull(); - } else { - out.specify(type); - factory.loadEncoder(type).convertTo(out, value); - } - return out.toBuffers(); - } - - @Override - public void convertTo(final JsonWriter writer, final Object value) { - if (value == null) { - writer.writeNull(); - } else { - Class type = value.getClass(); - Encodeable encoder = this.lastConvertEncodeable; - if (encoder == null || encoder.getType() != type) { - encoder = factory.loadEncoder(type); - this.lastConvertEncodeable = encoder; - } - if (encoder.specifyable()) writer.specify(type); - encoder.convertTo(writer, value); - } - } - - @Override - public void convertTo(final JsonWriter writer, final Type type, final Object value) { - if (type == null) return; - if (value == null) { - writer.writeNull(); - } else { - Encodeable encoder = this.lastConvertEncodeable; - if (encoder == null || encoder.getType() != type) { - encoder = factory.loadEncoder(type); - this.lastConvertEncodeable = encoder; - } - if (encoder.specifyable()) writer.specify(type); - encoder.convertTo(writer, value); - } - } - -} +/* + * 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.convert.json; + +import java.io.*; +import java.lang.reflect.*; +import java.nio.*; +import java.nio.charset.*; +import java.util.function.*; +import org.redkale.convert.*; +import org.redkale.service.RetResult; +import org.redkale.util.*; + +/** + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@SuppressWarnings("unchecked") +public class JsonConvert extends TextConvert { + + public static final Type TYPE_MAP_STRING_STRING = new TypeToken>() { + }.getType(); + + public static final Type TYPE_RETRESULT_STRING = new TypeToken>() { + }.getType(); + + private final ThreadLocal bytesWriterPool = ThreadLocal.withInitial(JsonBytesWriter::new); + + private final Consumer offerBytesConsumer = w -> offerJsonBytesWriter(w); + + private final boolean tiny; + + private Encodeable lastConvertEncodeable; + + private Decodeable lastConvertDecodeable; + + protected JsonConvert(JsonFactory factory, boolean tiny) { + super(factory); + this.tiny = tiny; + } + + @Override + public JsonFactory getFactory() { + return (JsonFactory) factory; + } + + public static JsonConvert root() { + return JsonFactory.root().getConvert(); + } + + @Override + public JsonConvert newConvert(final BiFunction fieldFunc) { + return newConvert(fieldFunc, null); + } + + @Override + public JsonConvert newConvert(final BiFunction fieldFunc, Function objExtFunc) { + return new JsonConvert(getFactory(), tiny) { + @Override + protected S configWrite(S writer) { + return fieldFunc(writer, fieldFunc, objExtFunc); + } + }; + } + + //------------------------------ writer ----------------------------------------------------------- + private JsonBytesWriter pollJsonBytesWriter() { + JsonBytesWriter writer = bytesWriterPool.get(); + if (writer == null) { + writer = new JsonBytesWriter(); + } else { + bytesWriterPool.set(null); + } + return configWrite((JsonBytesWriter) writer.tiny(tiny)); + } + + private void offerJsonBytesWriter(final JsonBytesWriter writer) { + if (writer != null) { + writer.recycle(); + bytesWriterPool.set(writer); + } + } + + //------------------------------ convertFrom ----------------------------------------------------------- + @Override + public T convertFrom(final Type type, final byte[] bytes) { + if (bytes == null) return null; + return convertFrom(type, new String(bytes, StandardCharsets.UTF_8)); + } + + @Override + public T convertFrom(final Type type, final byte[] bytes, final int offset, final int length) { + if (bytes == null) return null; + return convertFrom(type, new String(bytes, offset, length, StandardCharsets.UTF_8)); + } + + public T convertFrom(final Type type, final String text) { + if (text == null) return null; + return convertFrom(type, Utility.charArray(text)); + } + + public T convertFrom(final Type type, final char[] text) { + if (text == null) return null; + return convertFrom(type, text, 0, text.length); + } + + public T convertFrom(final Type type, final char[] text, final int offset, final int length) { + if (text == null || type == null) return null; + Decodeable decoder = this.lastConvertDecodeable; + if (decoder == null || decoder.getType() != type) { + decoder = factory.loadDecoder(type); + this.lastConvertDecodeable = decoder; + } + T rs = (T) decoder.convertFrom(new JsonReader(text, offset, length)); + return rs; + } + + public T convertFrom(final Type type, final InputStream in) { + if (type == null || in == null) return null; + Decodeable decoder = this.lastConvertDecodeable; + if (decoder == null || decoder.getType() != type) { + decoder = factory.loadDecoder(type); + this.lastConvertDecodeable = decoder; + } + return (T) decoder.convertFrom(new JsonStreamReader(in)); + } + + @Override + public T convertFrom(final Type type, final ByteBuffer... buffers) { + if (type == null || buffers == null || buffers.length == 0) return null; + Decodeable decoder = this.lastConvertDecodeable; + if (decoder == null || decoder.getType() != type) { + decoder = factory.loadDecoder(type); + this.lastConvertDecodeable = decoder; + } + return (T) decoder.convertFrom(new JsonByteBufferReader((ConvertMask) null, buffers)); + } + + @Override + public T convertFrom(final Type type, final ConvertMask mask, final ByteBuffer... buffers) { + if (type == null || buffers == null || buffers.length == 0) return null; + Decodeable decoder = this.lastConvertDecodeable; + if (decoder == null || decoder.getType() != type) { + decoder = factory.loadDecoder(type); + this.lastConvertDecodeable = decoder; + } + return (T) decoder.convertFrom(new JsonByteBufferReader(mask, buffers)); + } + + public T convertFrom(final Type type, final JsonReader reader) { + if (type == null) return null; + Decodeable decoder = this.lastConvertDecodeable; + if (decoder == null || decoder.getType() != type) { + decoder = factory.loadDecoder(type); + this.lastConvertDecodeable = decoder; + } + @SuppressWarnings("unchecked") + T rs = (T) decoder.convertFrom(reader); + return rs; + } + + //杩斿洖闈瀗ull鐨勫兼槸鐢盨tring銆丄rrayList銆丠ashMap浠绘剰缁勫悎鐨勫璞 + public V convertFrom(final String text) { + if (text == null) return null; + return (V) convertFrom(Utility.charArray(text)); + } + + //杩斿洖闈瀗ull鐨勫兼槸鐢盨tring銆丄rrayList銆丠ashMap浠绘剰缁勫悎鐨勫璞 + public V convertFrom(final char[] text) { + if (text == null) return null; + return (V) convertFrom(text, 0, text.length); + } + + //杩斿洖闈瀗ull鐨勫兼槸鐢盨tring銆丄rrayList銆丠ashMap浠绘剰缁勫悎鐨勫璞 + public V convertFrom(final char[] text, final int offset, final int length) { + if (text == null) return null; + //final JsonReader in = readerPool.get(); + //in.setText(text, offset, length); + Object rs = new AnyDecoder(factory).convertFrom(new JsonReader(text, offset, length)); + //readerPool.accept(in); + return (V) rs; + } + + //杩斿洖闈瀗ull鐨勫兼槸鐢盨tring銆丄rrayList銆丠ashMap浠绘剰缁勫悎鐨勫璞 + public V convertFrom(final InputStream in) { + if (in == null) return null; + return (V) new AnyDecoder(factory).convertFrom(new JsonStreamReader(in)); + } + + //杩斿洖闈瀗ull鐨勫兼槸鐢盨tring銆丄rrayList銆丠ashMap浠绘剰缁勫悎鐨勫璞 + public V convertFrom(final ByteBuffer... buffers) { + if (buffers == null || buffers.length == 0) return null; + return (V) new AnyDecoder(factory).convertFrom(new JsonByteBufferReader((ConvertMask) null, buffers)); + } + + //杩斿洖闈瀗ull鐨勫兼槸鐢盨tring銆丄rrayList銆丠ashMap浠绘剰缁勫悎鐨勫璞 + public V convertFrom(final ConvertMask mask, final ByteBuffer... buffers) { + if (buffers == null || buffers.length == 0) return null; + return (V) new AnyDecoder(factory).convertFrom(new JsonByteBufferReader(mask, buffers)); + } + + //杩斿洖闈瀗ull鐨勫兼槸鐢盨tring銆丄rrayList銆丠ashMap浠绘剰缁勫悎鐨勫璞 + public V convertFrom(final JsonReader reader) { + if (reader == null) return null; + return (V) new AnyDecoder(factory).convertFrom(reader); + } + + //------------------------------ convertTo ----------------------------------------------------------- + @Override + public String convertTo(final Object value) { + if (value == null) return "null"; + return convertTo(value.getClass(), value); + } + + @Override + public String convertTo(final Type type, final Object value) { + if (type == null) return null; + if (value == null) return "null"; + JsonBytesWriter writer = pollJsonBytesWriter(); + Encodeable encoder = this.lastConvertEncodeable; + if (encoder == null || encoder.getType() != type) { + encoder = factory.loadEncoder(type); + this.lastConvertEncodeable = encoder; + } + if (encoder.specifyable()) writer.specify(type); + encoder.convertTo(writer, value); + + String result = writer.toString(); + offerJsonBytesWriter(writer); + return result; + } + + @Override + public byte[] convertToBytes(final Object value) { + if (value == null) return null; + return convertToBytes(value.getClass(), value); + } + + @Override + public byte[] convertToBytes(final Type type, final Object value) { + if (type == null) return null; + if (value == null) return null; + JsonBytesWriter writer = pollJsonBytesWriter(); + Encodeable encoder = this.lastConvertEncodeable; + if (encoder == null || encoder.getType() != type) { + encoder = factory.loadEncoder(type); + this.lastConvertEncodeable = encoder; + } + if (encoder.specifyable()) writer.specify(type); + encoder.convertTo(writer, value); + + byte[] result = writer.toBytes(); + offerJsonBytesWriter(writer); + return result; + } + + @Override + public void convertToBytes(final Object value, final ConvertBytesHandler handler) { + convertToBytes(value == null ? null : value.getClass(), value, handler); + } + + @Override + public void convertToBytes(final Type type, final Object value, final ConvertBytesHandler handler) { + JsonBytesWriter writer = pollJsonBytesWriter(); + if (type == null) { + writer.writeNull(); + } else { + Encodeable encoder = this.lastConvertEncodeable; + if (encoder == null || encoder.getType() != type) { + encoder = factory.loadEncoder(type); + this.lastConvertEncodeable = encoder; + } + if (encoder.specifyable()) writer.specify(type); + encoder.convertTo(writer, value); + } + writer.completed(handler, offerBytesConsumer); + } + + @Override + public void convertToBytes(final ByteArray array, final Object value) { + convertToBytes(array, value == null ? null : value.getClass(), value); + } + + @Override + public void convertToBytes(final ByteArray array, final Type type, final Object value) { + JsonBytesWriter writer = configWrite(new JsonBytesWriter(tiny, array)); + if (type == null) { + writer.writeNull(); + } else { + Encodeable encoder = this.lastConvertEncodeable; + if (encoder == null || encoder.getType() != type) { + encoder = factory.loadEncoder(type); + this.lastConvertEncodeable = encoder; + } + if (encoder.specifyable()) writer.specify(type); + encoder.convertTo(writer, value); + } + writer.directTo(array); + } + + public void convertTo(final OutputStream out, final Object value) { + if (value == null) { + configWrite(new JsonStreamWriter(tiny, out)).writeNull(); + } else { + convertTo(out, value.getClass(), value); + } + } + + public void convertTo(final OutputStream out, final Type type, final Object value) { + if (type == null) return; + if (value == null) { + configWrite(new JsonStreamWriter(tiny, out)).writeNull(); + } else { + JsonStreamWriter writer = configWrite(new JsonStreamWriter(tiny, out)); + Encodeable encoder = this.lastConvertEncodeable; + if (encoder == null || encoder.getType() != type) { + encoder = factory.loadEncoder(type); + this.lastConvertEncodeable = encoder; + } + if (encoder.specifyable()) writer.specify(type); + encoder.convertTo(writer, value); + } + } + + @Override + public ByteBuffer[] convertTo(final Supplier supplier, final Object value) { + if (supplier == null) return null; + JsonByteBufferWriter out = configWrite(new JsonByteBufferWriter(tiny, supplier)); + if (value == null) { + out.writeNull(); + } else { + factory.loadEncoder(value.getClass()).convertTo(out, value); + } + return out.toBuffers(); + } + + @Override + public ByteBuffer[] convertTo(final Supplier supplier, final Type type, final Object value) { + if (supplier == null || type == null) return null; + JsonByteBufferWriter out = configWrite(new JsonByteBufferWriter(tiny, supplier)); + if (value == null) { + out.writeNull(); + } else { + out.specify(type); + factory.loadEncoder(type).convertTo(out, value); + } + return out.toBuffers(); + } + + @Override + public void convertTo(final JsonWriter writer, final Object value) { + if (value == null) { + writer.writeNull(); + } else { + Class type = value.getClass(); + Encodeable encoder = this.lastConvertEncodeable; + if (encoder == null || encoder.getType() != type) { + encoder = factory.loadEncoder(type); + this.lastConvertEncodeable = encoder; + } + if (encoder.specifyable()) writer.specify(type); + encoder.convertTo(writer, value); + } + } + + @Override + public void convertTo(final JsonWriter writer, final Type type, final Object value) { + if (type == null) return; + if (value == null) { + writer.writeNull(); + } else { + Encodeable encoder = this.lastConvertEncodeable; + if (encoder == null || encoder.getType() != type) { + encoder = factory.loadEncoder(type); + this.lastConvertEncodeable = encoder; + } + if (encoder.specifyable()) writer.specify(type); + encoder.convertTo(writer, value); + } + } + +} diff --git a/src/main/java/org/redkale/convert/json/JsonDynEncoder.java b/src/main/java/org/redkale/convert/json/JsonDynEncoder.java index a67c0a295..157c1c256 100644 --- a/src/main/java/org/redkale/convert/json/JsonDynEncoder.java +++ b/src/main/java/org/redkale/convert/json/JsonDynEncoder.java @@ -1,715 +1,715 @@ -/* - * 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.convert.json; - -import java.lang.reflect.*; -import java.lang.reflect.Type; -import java.util.*; -import org.redkale.asm.*; -import static org.redkale.asm.ClassWriter.COMPUTE_FRAMES; -import static org.redkale.asm.Opcodes.*; -import org.redkale.convert.*; -import org.redkale.convert.ext.*; -import org.redkale.util.*; - -/** - * 绠鍗曞璞$殑JSON搴忓垪鍖栨搷浣滅被 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @since 2.3.0 - * - * @param 搴忓垪鍖栫殑鏁版嵁绫诲瀷 - */ -@SuppressWarnings("unchecked") -public abstract class JsonDynEncoder implements Encodeable { - - protected final Class typeClass; - - protected final ObjectEncoder objectEncoder; - - protected JsonDynEncoder(final JsonFactory factory, Type type) { - this.typeClass = (Class) type; - factory.register(type, this); - this.objectEncoder = factory.createObjectEncoder(type); - } - - @Override - public boolean specifyable() { - return false; - } - - private static boolean checkMemberType(final JsonFactory factory, Type type, Class clazz) { - if (type == String.class) return true; - if (clazz.isPrimitive()) return true; - if (clazz.isEnum()) return true; - if (type == boolean[].class) return true; - if (type == byte[].class) return true; - if (type == short[].class) return true; - if (type == char[].class) return true; - if (type == int[].class) return true; - if (type == float[].class) return true; - if (type == long[].class) return true; - if (type == double[].class) return true; - if (type == Boolean[].class) return true; - if (type == Byte[].class) return true; - if (type == Short[].class) return true; - if (type == Character[].class) return true; - if (type == Integer[].class) return true; - if (type == Float[].class) return true; - if (type == Long[].class) return true; - if (type == Double[].class) return true; - if (type == String[].class) return true; - if (Collection.class.isAssignableFrom(clazz) && type instanceof ParameterizedType) { - Type[] ts = ((ParameterizedType) type).getActualTypeArguments(); - if (ts.length == 1) { - Type t = ts[0]; - if (t == Boolean.class || t == Byte.class || t == Short.class || t == Character.class - || t == Integer.class || t == Float.class || t == Long.class || t == Double.class - || t == String.class || ((t instanceof Class) && ((Class) t).isEnum())) return true; - if (factory.loadEncoder(t) instanceof JsonDynEncoder) return true; - } - } - if (type instanceof TypeVariable) return false; - try { - if (factory.loadEncoder(type) instanceof JsonDynEncoder) return true; - } catch (Exception e) { - return false; - } - return false; - } - - //瀛楁鍏ㄩ儴鏄痯rimitive鎴朣tring绫诲瀷锛屼笖娌℃湁娉涘瀷鐨勭被鎵嶈兘鍔ㄦ佺敓鎴怞sonDynEncoder锛 涓嶆敮鎸佺殑杩斿洖null - public static JsonDynEncoder createDyncEncoder(final JsonFactory factory, final Type type) { - if (!(type instanceof Class)) return null; - //鍙戠幇鏈夎嚜瀹氫箟鐨勫熀纭鏁版嵁绫诲瀷Encoder灏变笉鍔ㄦ佺敓鎴怞sonDynEncoder浜 - if (factory.loadEncoder(boolean.class) != BoolSimpledCoder.instance) return null; - if (factory.loadEncoder(byte.class) != ByteSimpledCoder.instance) return null; - if (factory.loadEncoder(short.class) != ShortSimpledCoder.instance) return null; - if (factory.loadEncoder(char.class) != CharSimpledCoder.instance) return null; - if (factory.loadEncoder(int.class) != IntSimpledCoder.instance) return null; - if (factory.loadEncoder(float.class) != FloatSimpledCoder.instance) return null; - if (factory.loadEncoder(long.class) != LongSimpledCoder.instance) return null; - if (factory.loadEncoder(double.class) != DoubleSimpledCoder.instance) return null; - if (factory.loadEncoder(String.class) != StringSimpledCoder.instance) return null; - //array - if (factory.loadEncoder(boolean[].class) != BoolArraySimpledCoder.instance) return null; - if (factory.loadEncoder(byte[].class) != ByteArraySimpledCoder.instance) return null; - if (factory.loadEncoder(short[].class) != ShortArraySimpledCoder.instance) return null; - if (factory.loadEncoder(char[].class) != CharArraySimpledCoder.instance) return null; - if (factory.loadEncoder(int[].class) != IntArraySimpledCoder.instance) return null; - if (factory.loadEncoder(float[].class) != FloatArraySimpledCoder.instance) return null; - if (factory.loadEncoder(long[].class) != LongArraySimpledCoder.instance) return null; - if (factory.loadEncoder(double[].class) != DoubleArraySimpledCoder.instance) return null; - if (factory.loadEncoder(String[].class) != StringArraySimpledCoder.instance) return null; - - final Class clazz = (Class) type; - List members = null; - Set names = new HashSet<>(); - try { - ConvertColumnEntry ref; - RedkaleClassLoader.putReflectionPublicFields(clazz.getName()); - for (final Field field : clazz.getFields()) { - if (Modifier.isStatic(field.getModifiers())) continue; - if (factory.isConvertDisabled(field)) continue; - ref = factory.findRef(clazz, field); - if (ref != null && ref.ignore()) continue; - if (!(checkMemberType(factory, field.getGenericType(), field.getType()))) return null; - String name = convertFieldName(factory, clazz, field); - if (names.contains(name)) continue; - names.add(name); - if (members == null) members = new ArrayList<>(); - members.add(field); - } - RedkaleClassLoader.putReflectionPublicMethods(clazz.getName()); - for (final Method method : clazz.getMethods()) { - if (Modifier.isStatic(method.getModifiers())) continue; - if (Modifier.isAbstract(method.getModifiers())) continue; - if (method.isSynthetic()) continue; - if (method.getName().length() < 3) continue; - if (method.getName().equals("getClass")) continue; - if (!method.getName().startsWith("is") && !method.getName().startsWith("get")) continue; - if (factory.isConvertDisabled(method)) continue; - if (method.getParameterTypes().length != 0) continue; - if (method.getReturnType() == void.class) continue; - ref = factory.findRef(clazz, method); - if (ref != null && ref.ignore()) continue; - if (!(checkMemberType(factory, method.getGenericReturnType(), method.getReturnType()))) return null; - String name = convertFieldName(factory, clazz, method); - if (names.contains(name)) continue; - names.add(name); - if (members == null) members = new ArrayList<>(); - members.add(method); - } - if (members == null) return null; - Collections.sort(members, (o1, o2) -> { - ConvertColumnEntry ref1 = factory.findRef(clazz, o1); - ConvertColumnEntry ref2 = factory.findRef(clazz, o2); - if ((ref1 != null && ref1.getIndex() > 0) || (ref2 != null && ref2.getIndex() > 0)) { - int idx1 = ref1 == null ? Integer.MAX_VALUE / 2 : ref1.getIndex(); - int idx2 = ref2 == null ? Integer.MAX_VALUE / 2 : ref2.getIndex(); - if (idx1 != idx2) return idx1 - idx2; - } - String n1 = ref1 == null || ref1.name().isEmpty() ? readGetSetFieldName(o1) : ref1.name(); - String n2 = ref2 == null || ref2.name().isEmpty() ? readGetSetFieldName(o2) : ref2.name(); - if (n1 == null && n2 == null) return 0; - if (n1 == null) return -1; - if (n2 == null) return 1; - return n1.compareTo(n2); - }); - return generateDyncEncoder(factory, clazz, members); - } catch (Exception ex) { - ex.printStackTrace(); - return null; - } - } - - protected static String convertFieldName(final JsonFactory factory, Class clazz, AccessibleObject element) { - ConvertColumnEntry ref = factory.findRef(clazz, element); - String name = ref == null || ref.name().isEmpty() ? readGetSetFieldName(element) : ref.name(); - return name; - } - - protected static ConvertSmallString readConvertSmallString(AccessibleObject element) { - if (element instanceof Field) return ((Field) element).getAnnotation(ConvertSmallString.class); - Method method = (Method) element; - ConvertSmallString small = method.getAnnotation(ConvertSmallString.class); - if (small == null) { - try { - Field f = method.getDeclaringClass().getDeclaredField(readGetSetFieldName(method)); - if (f != null) small = f.getAnnotation(ConvertSmallString.class); - } catch (Exception e) { - } - } - return small; - } - - protected static Class readGetSetFieldType(AccessibleObject element) { - if (element instanceof Field) return ((Field) element).getType(); - return element == null ? null : ((Method) element).getReturnType(); - } - - protected static String readGetSetFieldName(AccessibleObject element) { - if (element instanceof Field) return ((Field) element).getName(); - Method method = (Method) element; - if (method == null) return null; - String fname = method.getName(); - if (!fname.startsWith("is") && !fname.startsWith("get") && !fname.startsWith("set")) return fname; - fname = fname.substring(fname.startsWith("is") ? 2 : 3); - if (fname.length() > 1 && !(fname.charAt(1) >= 'A' && fname.charAt(1) <= 'Z')) { - fname = Character.toLowerCase(fname.charAt(0)) + fname.substring(1); - } else if (fname.length() == 1) { - fname = "" + Character.toLowerCase(fname.charAt(0)); - } - return fname; - } - - protected static JsonDynEncoder generateDyncEncoder(final JsonFactory factory, final Class clazz, final List members) { - final String supDynName = JsonDynEncoder.class.getName().replace('.', '/'); - final String valtypeName = clazz.getName().replace('.', '/'); - final String writerName = JsonWriter.class.getName().replace('.', '/'); - final String encodeableName = Encodeable.class.getName().replace('.', '/'); - final String objEncoderName = ObjectEncoder.class.getName().replace('.', '/'); - final String typeDesc = org.redkale.asm.Type.getDescriptor(Type.class); - final String jsonfactoryDesc = org.redkale.asm.Type.getDescriptor(JsonFactory.class); - final String jsonwriterDesc = org.redkale.asm.Type.getDescriptor(JsonWriter.class); - final String writerDesc = org.redkale.asm.Type.getDescriptor(Writer.class); - final String encodeableDesc = org.redkale.asm.Type.getDescriptor(Encodeable.class); - final String objEncoderDesc = org.redkale.asm.Type.getDescriptor(ObjectEncoder.class); - final String valtypeDesc = org.redkale.asm.Type.getDescriptor(clazz); - - Map mixedNames0 = null; - for (AccessibleObject element : members) { - ConvertColumnEntry ref1 = factory.findRef(clazz, element); - final String fieldname = ref1 == null || ref1.name().isEmpty() ? readGetSetFieldName(element) : ref1.name(); - final Class fieldtype = readGetSetFieldType(element); - if (fieldtype != String.class && !fieldtype.isPrimitive()) { - if (mixedNames0 == null) mixedNames0 = new HashMap<>(); - mixedNames0.put(fieldname, element); - } - } - final Map mixedNames = mixedNames0; - final ClassLoader loader = Thread.currentThread().getContextClassLoader(); - final String newDynName = "org/redkaledyn/json/_Dyn" + JsonDynEncoder.class.getSimpleName() + "__" + clazz.getName().replace('.', '_').replace('$', '_'); - final ObjectEncoder selfObjEncoder = factory.createObjectEncoder(clazz); - selfObjEncoder.init(factory); - try { - Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); - Class newClazz = clz == null ? loader.loadClass(newDynName.replace('/', '.')) : clz; - JsonDynEncoder resultEncoder = (JsonDynEncoder) newClazz.getDeclaredConstructor(JsonFactory.class, Type.class).newInstance(factory, clazz); - Field selfField = newClazz.getDeclaredField("objectEncoderSelf"); - selfField.setAccessible(true); - selfField.set(resultEncoder, selfObjEncoder); - if (mixedNames != null) { - for (Map.Entry en : mixedNames.entrySet()) { - Field f = newClazz.getDeclaredField(en.getKey() + "Encoder"); - f.setAccessible(true); - f.set(resultEncoder, factory.loadEncoder(en.getValue() instanceof Field ? ((Field) en.getValue()).getGenericType() : ((Method) en.getValue()).getGenericReturnType())); - } - } - return resultEncoder; - } catch (Throwable ex) { - } - // ------------------------------------------------------------------------------ - ClassWriter cw = new ClassWriter(COMPUTE_FRAMES); - FieldVisitor fv; - MethodVisitor mv; - AnnotationVisitor av0; - - cw.visit(V11, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, "L" + supDynName + "<" + valtypeDesc + ">;", supDynName, null); - - fv = cw.visitField(ACC_PROTECTED, "objectEncoderSelf", objEncoderDesc, null, null); - fv.visitEnd(); - final int membersSize = members.size(); - boolean onlyTwoIntFieldObjectFlag = false; //鍙寘鍚袱涓猧nt瀛楁 - boolean onlyOneLatin1FieldObjectFlag = false; //鍙寘鍚竴涓狶atin1 String瀛楁 - boolean onlyShotIntLongLatin1MoreFieldObjectFlag = true; - int intFieldCount = 0; - for (AccessibleObject element : members) { - ConvertColumnEntry ref1 = factory.findRef(clazz, element); - final String fieldname = ref1 == null || ref1.name().isEmpty() ? readGetSetFieldName(element) : ref1.name(); - fv = cw.visitField(ACC_PROTECTED + ACC_FINAL, fieldname + "FieldBytes", "[B", null, null); - fv.visitEnd(); - fv = cw.visitField(ACC_PROTECTED + ACC_FINAL, fieldname + "CommaFieldBytes", "[B", null, null); - fv.visitEnd(); - fv = cw.visitField(ACC_PROTECTED + ACC_FINAL, fieldname + "FirstFieldBytes", "[B", null, null); - fv.visitEnd(); - final Class fieldtype = readGetSetFieldType(element); - if (fieldtype != String.class && !fieldtype.isPrimitive()) { - fv = cw.visitField(ACC_PROTECTED, fieldname + "Encoder", encodeableDesc, null, null); - fv.visitEnd(); - } - if (fieldtype == int.class) intFieldCount++; - if (fieldtype == String.class && membersSize == 1 && readConvertSmallString(element) != null) { - onlyOneLatin1FieldObjectFlag = true; - } else if (fieldtype != short.class && fieldtype != int.class && fieldtype != long.class && !(fieldtype == String.class && readConvertSmallString(element) != null)) { - onlyShotIntLongLatin1MoreFieldObjectFlag = false; - } - } - if (intFieldCount == 2 && intFieldCount == membersSize) onlyTwoIntFieldObjectFlag = true; - if (onlyShotIntLongLatin1MoreFieldObjectFlag && membersSize < 2) onlyShotIntLongLatin1MoreFieldObjectFlag = false; //瀛楁涓暟蹇呴』澶т簬1 - - { // 鏋勯犲嚱鏁 - mv = (cw.visitMethod(ACC_PUBLIC, "", "(" + jsonfactoryDesc + typeDesc + ")V", null, null)); - //mv.setDebug(true); - mv.visitVarInsn(ALOAD, 0); - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(ALOAD, 2); - mv.visitMethodInsn(INVOKESPECIAL, supDynName, "", "(" + jsonfactoryDesc + typeDesc + ")V", false); - - for (AccessibleObject element : members) { - ConvertColumnEntry ref1 = factory.findRef(clazz, element); - final String fieldname = ref1 == null || ref1.name().isEmpty() ? readGetSetFieldName(element) : ref1.name(); - //xxxFieldBytes - mv.visitVarInsn(ALOAD, 0); - mv.visitLdcInsn("\"" + fieldname + "\":"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "getBytes", "()[B", false); - mv.visitFieldInsn(PUTFIELD, newDynName, fieldname + "FieldBytes", "[B"); - //xxxCommaFieldBytes - mv.visitVarInsn(ALOAD, 0); - mv.visitLdcInsn(",\"" + fieldname + "\":"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "getBytes", "()[B", false); - mv.visitFieldInsn(PUTFIELD, newDynName, fieldname + "CommaFieldBytes", "[B"); - //xxxFirstFieldBytes - mv.visitVarInsn(ALOAD, 0); - mv.visitLdcInsn("{\"" + fieldname + "\":"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "getBytes", "()[B", false); - mv.visitFieldInsn(PUTFIELD, newDynName, fieldname + "FirstFieldBytes", "[B"); - } - mv.visitInsn(RETURN); - mv.visitMaxs(1 + members.size(), 1 + members.size()); - mv.visitEnd(); - } - - { - mv = (cw.visitMethod(ACC_PUBLIC, "convertTo", "(" + jsonwriterDesc + valtypeDesc + ")V", null, null)); - //mv.setDebug(true); - { //if (value == null) { out.writeObjectNull(null); return; } - mv.visitVarInsn(ALOAD, 2); - Label valif = new Label(); - mv.visitJumpInsn(IFNONNULL, valif); - mv.visitVarInsn(ALOAD, 1); - mv.visitInsn(ACONST_NULL); - mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeObjectNull", "(Ljava/lang/Class;)V", false); - mv.visitInsn(RETURN); - mv.visitLabel(valif); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - } - { //if (!out.isExtFuncEmpty()) { objectEncoder.convertTo(out, value); return; } - mv.visitVarInsn(ALOAD, 1); - mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "isExtFuncEmpty", "()Z", false); - Label extif = new Label(); - mv.visitJumpInsn(IFNE, extif); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, "objectEncoderSelf", objEncoderDesc); - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(ALOAD, 2); - mv.visitMethodInsn(INVOKEVIRTUAL, objEncoderName, "convertTo", "(" + org.redkale.asm.Type.getDescriptor(Writer.class) + "Ljava/lang/Object;)V", false); - mv.visitInsn(RETURN); - mv.visitLabel(extif); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - } - - int maxLocals = 4; - int elementIndex = -1; - final Class firstType = readGetSetFieldType(members.get(0)); - final boolean mustHadComma = firstType.isPrimitive() && (firstType != boolean.class || !factory.tiny()); //byte/short/char/int/float/long/double - - if (onlyOneLatin1FieldObjectFlag) { - //out.writeObjectByOnlyOneLatin1FieldValue(messageFirstFieldBytes, value.getMessage());elementIndex++; - elementIndex++; - AccessibleObject element = members.get(elementIndex); - ConvertColumnEntry ref1 = factory.findRef(clazz, element); - final String fieldname = ref1 == null || ref1.name().isEmpty() ? readGetSetFieldName(element) : ref1.name(); - final Class fieldtype = readGetSetFieldType(element); - - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, fieldname + "FirstFieldBytes", "[B"); - - mv.visitVarInsn(ALOAD, 2); //String message = value.getMessage(); 鍔犺浇 value - if (element instanceof Field) { - mv.visitFieldInsn(GETFIELD, valtypeName, ((Field) element).getName(), org.redkale.asm.Type.getDescriptor(fieldtype)); - } else { - mv.visitMethodInsn(INVOKEVIRTUAL, valtypeName, ((Method) element).getName(), "()" + org.redkale.asm.Type.getDescriptor(fieldtype), false); - } - mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeObjectByOnlyOneLatin1FieldValue", "([BLjava/lang/String;)V", false); - maxLocals++; - } else if (onlyTwoIntFieldObjectFlag) { - elementIndex++; - AccessibleObject element1 = members.get(elementIndex); - ConvertColumnEntry ref1 = factory.findRef(clazz, element1); - final String fieldname1 = ref1 == null || ref1.name().isEmpty() ? readGetSetFieldName(element1) : ref1.name(); - final Class fieldtype1 = readGetSetFieldType(element1); - - elementIndex++; - AccessibleObject element2 = members.get(elementIndex); - ConvertColumnEntry ref2 = factory.findRef(clazz, element2); - final String fieldname2 = ref2 == null || ref2.name().isEmpty() ? readGetSetFieldName(element2) : ref2.name(); - final Class fieldtype2 = readGetSetFieldType(element2); - - mv.visitVarInsn(ALOAD, 1); - - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, fieldname1 + "FirstFieldBytes", "[B"); - - mv.visitVarInsn(ALOAD, 2); //String message = value.getMessage(); 鍔犺浇 value - if (element1 instanceof Field) { - mv.visitFieldInsn(GETFIELD, valtypeName, ((Field) element1).getName(), org.redkale.asm.Type.getDescriptor(fieldtype1)); - } else { - mv.visitMethodInsn(INVOKEVIRTUAL, valtypeName, ((Method) element1).getName(), "()" + org.redkale.asm.Type.getDescriptor(fieldtype1), false); - } - maxLocals ++; - - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, fieldname2 + "CommaFieldBytes", "[B"); - - mv.visitVarInsn(ALOAD, 2); //String message = value.getMessage(); 鍔犺浇 value - if (element2 instanceof Field) { - mv.visitFieldInsn(GETFIELD, valtypeName, ((Field) element2).getName(), org.redkale.asm.Type.getDescriptor(fieldtype2)); - } else { - mv.visitMethodInsn(INVOKEVIRTUAL, valtypeName, ((Method) element2).getName(), "()" + org.redkale.asm.Type.getDescriptor(fieldtype2), false); - } - maxLocals ++; - - mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeObjectByOnlyTwoIntFieldValue", "([BI[BI)V", false); - - } else if (onlyShotIntLongLatin1MoreFieldObjectFlag && mustHadComma) { - for (AccessibleObject element : members) { - elementIndex++; - ConvertColumnEntry ref1 = factory.findRef(clazz, element); - final String fieldname = ref1 == null || ref1.name().isEmpty() ? readGetSetFieldName(element) : ref1.name(); - final Class fieldtype = readGetSetFieldType(element); - - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, fieldname + (elementIndex == 0 ? "FirstFieldBytes" : "CommaFieldBytes"), "[B"); - - mv.visitVarInsn(ALOAD, 2); //String message = value.getMessage(); 鍔犺浇 value - if (element instanceof Field) { - mv.visitFieldInsn(GETFIELD, valtypeName, ((Field) element).getName(), org.redkale.asm.Type.getDescriptor(fieldtype)); - } else { - mv.visitMethodInsn(INVOKEVIRTUAL, valtypeName, ((Method) element).getName(), "()" + org.redkale.asm.Type.getDescriptor(fieldtype), false); - } - if (fieldtype == short.class) { - mv.visitMethodInsn(INVOKEVIRTUAL, writerName, elementIndex + 1 == membersSize ? "writeLastFieldShortValue" : "writeFieldShortValue", "([BS)V", false); - } else if (fieldtype == int.class) { - mv.visitMethodInsn(INVOKEVIRTUAL, writerName, elementIndex + 1 == membersSize ? "writeLastFieldIntValue" : "writeFieldIntValue", "([BI)V", false); - } else if (fieldtype == long.class) { - mv.visitMethodInsn(INVOKEVIRTUAL, writerName, elementIndex + 1 == membersSize ? "writeLastFieldLongValue" : "writeFieldLongValue", "([BJ)V", false); - } else { - mv.visitMethodInsn(INVOKEVIRTUAL, writerName, elementIndex + 1 == membersSize ? "writeLastFieldLatin1Value" : "writeFieldLatin1Value", "([BLjava/lang/String;)V", false); - } - - if (fieldtype == long.class || fieldtype == double.class) { - maxLocals += 2; - } else { - maxLocals++; - } - } - } else { - { //out.writeTo('{'); - mv.visitVarInsn(ALOAD, 1); - mv.visitIntInsn(BIPUSH, '{'); - mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeTo", "(B)V", false); - } - - if (!mustHadComma) { //boolean comma = false; - mv.visitInsn(ICONST_0); - mv.visitVarInsn(ISTORE, 3); - } - for (AccessibleObject element : members) { - elementIndex++; - ConvertColumnEntry ref1 = factory.findRef(clazz, element); - final String fieldname = ref1 == null || ref1.name().isEmpty() ? readGetSetFieldName(element) : ref1.name(); - final Class fieldtype = readGetSetFieldType(element); - int storeid = ASTORE; - int loadid = ALOAD; - { //String message = value.getMessage(); - mv.visitVarInsn(ALOAD, 2); //鍔犺浇 value - if (element instanceof Field) { - mv.visitFieldInsn(GETFIELD, valtypeName, ((Field) element).getName(), org.redkale.asm.Type.getDescriptor(fieldtype)); - } else { - mv.visitMethodInsn(INVOKEVIRTUAL, valtypeName, ((Method) element).getName(), "()" + org.redkale.asm.Type.getDescriptor(fieldtype), false); - } - if (fieldtype == boolean.class) { - storeid = ISTORE; - loadid = ILOAD; - mv.visitVarInsn(storeid, maxLocals); - } else if (fieldtype == byte.class) { - storeid = ISTORE; - loadid = ILOAD; - mv.visitVarInsn(storeid, maxLocals); - } else if (fieldtype == short.class) { - storeid = ISTORE; - loadid = ILOAD; - mv.visitVarInsn(storeid, maxLocals); - } else if (fieldtype == char.class) { - storeid = ISTORE; - loadid = ILOAD; - mv.visitVarInsn(storeid, maxLocals); - } else if (fieldtype == int.class) { - storeid = ISTORE; - loadid = ILOAD; - mv.visitVarInsn(storeid, maxLocals); - } else if (fieldtype == float.class) { - storeid = FSTORE; - loadid = FLOAD; - mv.visitVarInsn(storeid, maxLocals); - } else if (fieldtype == long.class) { - storeid = LSTORE; - loadid = LLOAD; - mv.visitVarInsn(storeid, maxLocals); - } else if (fieldtype == double.class) { - storeid = DSTORE; - loadid = DLOAD; - mv.visitVarInsn(storeid, maxLocals); - } else { - //storeid = ASTORE; - //loadid = ALOAD; - mv.visitVarInsn(storeid, maxLocals); - } - } - Label msgnotemptyif = null; - if (!fieldtype.isPrimitive()) { //if (message != null) { start - mv.visitVarInsn(loadid, maxLocals); - msgnotemptyif = new Label(); - mv.visitJumpInsn(IFNULL, msgnotemptyif); - if (factory.tiny() && fieldtype == String.class) { - mv.visitVarInsn(loadid, maxLocals); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "isEmpty", "()Z", false); - mv.visitJumpInsn(IFNE, msgnotemptyif); - } - } else if (fieldtype == boolean.class && factory.tiny()) { - mv.visitVarInsn(loadid, maxLocals); - msgnotemptyif = new Label(); - mv.visitJumpInsn(IFEQ, msgnotemptyif); - } - if (mustHadComma) { //绗竴涓瓧娈靛繀鐒朵細鍐欏叆 - if (elementIndex == 0) { //绗竴涓 - //out.writeTo(messageFieldBytes); - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, fieldname + "FieldBytes", "[B"); - mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeTo", "([B)V", false); - } else { - //out.writeTo(messageCommaFieldBytes); - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, fieldname + "CommaFieldBytes", "[B"); - mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeTo", "([B)V", false); - } - } else { //if(comma) {} else {} 浠g爜鍧 - //if (comma) { start - mv.visitVarInsn(ILOAD, 3); - Label commaif = new Label(); - mv.visitJumpInsn(IFEQ, commaif); - - //out.writeTo(messageCommaFieldBytes); - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, fieldname + "CommaFieldBytes", "[B"); - mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeTo", "([B)V", false); - - Label commaelse = new Label(); - mv.visitJumpInsn(GOTO, commaelse); - mv.visitLabel(commaif); - if (fieldtype == boolean.class) { - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Opcodes.INTEGER}, 0, null); - } else if (fieldtype == byte.class) { - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Opcodes.INTEGER}, 0, null); - } else if (fieldtype == short.class) { - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Opcodes.INTEGER}, 0, null); - } else if (fieldtype == char.class) { - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Opcodes.INTEGER}, 0, null); - } else if (fieldtype == int.class) { - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Opcodes.INTEGER}, 0, null); - } else if (fieldtype == float.class) { - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Opcodes.FLOAT}, 0, null); - } else if (fieldtype == long.class) { - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Opcodes.LONG}, 0, null); - } else if (fieldtype == double.class) { - mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Opcodes.DOUBLE}, 0, null); - } else { - mv.visitFrame(Opcodes.F_APPEND, 2, new Object[]{Opcodes.INTEGER, "java/lang/String"}, 0, null); // } else { comma - } - //out.writeTo(messageFieldBytes); - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, fieldname + "FieldBytes", "[B"); - mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeTo", "([B)V", false); - //comma = true; - mv.visitInsn(ICONST_1); - mv.visitVarInsn(ISTORE, 3); - mv.visitLabel(commaelse); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); //if (comma) } end - } - //out.writeString(message); - if (fieldtype == boolean.class) { - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(loadid, maxLocals); - mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeBoolean", "(Z)V", false); - } else if (fieldtype == byte.class) { - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(loadid, maxLocals); - mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeByte", "(B)V", false); - } else if (fieldtype == short.class) { - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(loadid, maxLocals); - mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeShort", "(S)V", false); - } else if (fieldtype == char.class) { - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(loadid, maxLocals); - mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeChar", "(C)V", false); - } else if (fieldtype == int.class) { - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(loadid, maxLocals); - mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeInt", "(I)V", false); - } else if (fieldtype == float.class) { - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(loadid, maxLocals); - mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeFloat", "(F)V", false); - } else if (fieldtype == long.class) { - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(loadid, maxLocals); - mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeLong", "(J)V", false); - } else if (fieldtype == double.class) { - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(loadid, maxLocals); - mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeDouble", "(D)V", false); - } else if (fieldtype == String.class) { - if (readConvertSmallString(element) == null) { - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(loadid, maxLocals); - mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeString", "(Ljava/lang/String;)V", false); - } else { - mv.visitVarInsn(ALOAD, 1); - mv.visitInsn(ICONST_1); - mv.visitVarInsn(loadid, maxLocals); - mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeLatin1To", "(ZLjava/lang/String;)V", false); - } - } else { //int[],Boolean[],String[] - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, fieldname + "Encoder", encodeableDesc); - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(loadid, maxLocals); - mv.visitMethodInsn(INVOKEINTERFACE, encodeableName, "convertTo", "(" + writerDesc + "Ljava/lang/Object;)V", true); - } - if (!fieldtype.isPrimitive()) { //if (message != null) } end - mv.visitLabel(msgnotemptyif); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - } else if (fieldtype == boolean.class && factory.tiny()) { - mv.visitLabel(msgnotemptyif); - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - } - if (fieldtype == long.class || fieldtype == double.class) { - maxLocals += 2; - } else { - maxLocals++; - } - } - { //out.writeTo('}'); - mv.visitVarInsn(ALOAD, 1); - mv.visitIntInsn(BIPUSH, '}'); - mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeTo", "(B)V", false); - } - } - mv.visitInsn(RETURN); - mv.visitMaxs(maxLocals, maxLocals); - mv.visitEnd(); - } - { - mv = (cw.visitMethod(ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, "convertTo", "(" + jsonwriterDesc + "Ljava/lang/Object;)V", null, null)); - //mv.setDebug(true); - mv.visitVarInsn(ALOAD, 0); - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(ALOAD, 2); - mv.visitTypeInsn(CHECKCAST, valtypeName); - mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "convertTo", "(" + jsonwriterDesc + valtypeDesc + ")V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(3, 3); - mv.visitEnd(); - } - 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); - RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, newClazz); - RedkaleClassLoader.putReflectionDeclaredConstructors(newClazz, newDynName.replace('/', '.'), JsonFactory.class, Type.class); - try { - JsonDynEncoder resultEncoder = (JsonDynEncoder) newClazz.getDeclaredConstructor(JsonFactory.class, Type.class).newInstance(factory, clazz); - Field selfField = newClazz.getDeclaredField("objectEncoderSelf"); - selfField.setAccessible(true); - selfField.set(resultEncoder, selfObjEncoder); - RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), selfField); - if (mixedNames != null) { - for (Map.Entry en : mixedNames.entrySet()) { - Field f = newClazz.getDeclaredField(en.getKey() + "Encoder"); - f.setAccessible(true); - f.set(resultEncoder, factory.loadEncoder(en.getValue() instanceof Field ? ((Field) en.getValue()).getGenericType() : ((Method) en.getValue()).getGenericReturnType())); - RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), f); - } - } - return resultEncoder; - } catch (Exception ex) { - throw new RuntimeException(ex); - } - } - - @Override - public abstract void convertTo(JsonWriter out, T value); - - @Override - public Type getType() { - return typeClass; - } -} +/* + * 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.convert.json; + +import java.lang.reflect.*; +import java.lang.reflect.Type; +import java.util.*; +import org.redkale.asm.*; +import static org.redkale.asm.ClassWriter.COMPUTE_FRAMES; +import static org.redkale.asm.Opcodes.*; +import org.redkale.convert.*; +import org.redkale.convert.ext.*; +import org.redkale.util.*; + +/** + * 绠鍗曞璞$殑JSON搴忓垪鍖栨搷浣滅被 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @since 2.3.0 + * + * @param 搴忓垪鍖栫殑鏁版嵁绫诲瀷 + */ +@SuppressWarnings("unchecked") +public abstract class JsonDynEncoder implements Encodeable { + + protected final Class typeClass; + + protected final ObjectEncoder objectEncoder; + + protected JsonDynEncoder(final JsonFactory factory, Type type) { + this.typeClass = (Class) type; + factory.register(type, this); + this.objectEncoder = factory.createObjectEncoder(type); + } + + @Override + public boolean specifyable() { + return false; + } + + private static boolean checkMemberType(final JsonFactory factory, Type type, Class clazz) { + if (type == String.class) return true; + if (clazz.isPrimitive()) return true; + if (clazz.isEnum()) return true; + if (type == boolean[].class) return true; + if (type == byte[].class) return true; + if (type == short[].class) return true; + if (type == char[].class) return true; + if (type == int[].class) return true; + if (type == float[].class) return true; + if (type == long[].class) return true; + if (type == double[].class) return true; + if (type == Boolean[].class) return true; + if (type == Byte[].class) return true; + if (type == Short[].class) return true; + if (type == Character[].class) return true; + if (type == Integer[].class) return true; + if (type == Float[].class) return true; + if (type == Long[].class) return true; + if (type == Double[].class) return true; + if (type == String[].class) return true; + if (Collection.class.isAssignableFrom(clazz) && type instanceof ParameterizedType) { + Type[] ts = ((ParameterizedType) type).getActualTypeArguments(); + if (ts.length == 1) { + Type t = ts[0]; + if (t == Boolean.class || t == Byte.class || t == Short.class || t == Character.class + || t == Integer.class || t == Float.class || t == Long.class || t == Double.class + || t == String.class || ((t instanceof Class) && ((Class) t).isEnum())) return true; + if (factory.loadEncoder(t) instanceof JsonDynEncoder) return true; + } + } + if (type instanceof TypeVariable) return false; + try { + if (factory.loadEncoder(type) instanceof JsonDynEncoder) return true; + } catch (Exception e) { + return false; + } + return false; + } + + //瀛楁鍏ㄩ儴鏄痯rimitive鎴朣tring绫诲瀷锛屼笖娌℃湁娉涘瀷鐨勭被鎵嶈兘鍔ㄦ佺敓鎴怞sonDynEncoder锛 涓嶆敮鎸佺殑杩斿洖null + public static JsonDynEncoder createDyncEncoder(final JsonFactory factory, final Type type) { + if (!(type instanceof Class)) return null; + //鍙戠幇鏈夎嚜瀹氫箟鐨勫熀纭鏁版嵁绫诲瀷Encoder灏变笉鍔ㄦ佺敓鎴怞sonDynEncoder浜 + if (factory.loadEncoder(boolean.class) != BoolSimpledCoder.instance) return null; + if (factory.loadEncoder(byte.class) != ByteSimpledCoder.instance) return null; + if (factory.loadEncoder(short.class) != ShortSimpledCoder.instance) return null; + if (factory.loadEncoder(char.class) != CharSimpledCoder.instance) return null; + if (factory.loadEncoder(int.class) != IntSimpledCoder.instance) return null; + if (factory.loadEncoder(float.class) != FloatSimpledCoder.instance) return null; + if (factory.loadEncoder(long.class) != LongSimpledCoder.instance) return null; + if (factory.loadEncoder(double.class) != DoubleSimpledCoder.instance) return null; + if (factory.loadEncoder(String.class) != StringSimpledCoder.instance) return null; + //array + if (factory.loadEncoder(boolean[].class) != BoolArraySimpledCoder.instance) return null; + if (factory.loadEncoder(byte[].class) != ByteArraySimpledCoder.instance) return null; + if (factory.loadEncoder(short[].class) != ShortArraySimpledCoder.instance) return null; + if (factory.loadEncoder(char[].class) != CharArraySimpledCoder.instance) return null; + if (factory.loadEncoder(int[].class) != IntArraySimpledCoder.instance) return null; + if (factory.loadEncoder(float[].class) != FloatArraySimpledCoder.instance) return null; + if (factory.loadEncoder(long[].class) != LongArraySimpledCoder.instance) return null; + if (factory.loadEncoder(double[].class) != DoubleArraySimpledCoder.instance) return null; + if (factory.loadEncoder(String[].class) != StringArraySimpledCoder.instance) return null; + + final Class clazz = (Class) type; + List members = null; + Set names = new HashSet<>(); + try { + ConvertColumnEntry ref; + RedkaleClassLoader.putReflectionPublicFields(clazz.getName()); + for (final Field field : clazz.getFields()) { + if (Modifier.isStatic(field.getModifiers())) continue; + if (factory.isConvertDisabled(field)) continue; + ref = factory.findRef(clazz, field); + if (ref != null && ref.ignore()) continue; + if (!(checkMemberType(factory, field.getGenericType(), field.getType()))) return null; + String name = convertFieldName(factory, clazz, field); + if (names.contains(name)) continue; + names.add(name); + if (members == null) members = new ArrayList<>(); + members.add(field); + } + RedkaleClassLoader.putReflectionPublicMethods(clazz.getName()); + for (final Method method : clazz.getMethods()) { + if (Modifier.isStatic(method.getModifiers())) continue; + if (Modifier.isAbstract(method.getModifiers())) continue; + if (method.isSynthetic()) continue; + if (method.getName().length() < 3) continue; + if (method.getName().equals("getClass")) continue; + if (!method.getName().startsWith("is") && !method.getName().startsWith("get")) continue; + if (factory.isConvertDisabled(method)) continue; + if (method.getParameterTypes().length != 0) continue; + if (method.getReturnType() == void.class) continue; + ref = factory.findRef(clazz, method); + if (ref != null && ref.ignore()) continue; + if (!(checkMemberType(factory, method.getGenericReturnType(), method.getReturnType()))) return null; + String name = convertFieldName(factory, clazz, method); + if (names.contains(name)) continue; + names.add(name); + if (members == null) members = new ArrayList<>(); + members.add(method); + } + if (members == null) return null; + Collections.sort(members, (o1, o2) -> { + ConvertColumnEntry ref1 = factory.findRef(clazz, o1); + ConvertColumnEntry ref2 = factory.findRef(clazz, o2); + if ((ref1 != null && ref1.getIndex() > 0) || (ref2 != null && ref2.getIndex() > 0)) { + int idx1 = ref1 == null ? Integer.MAX_VALUE / 2 : ref1.getIndex(); + int idx2 = ref2 == null ? Integer.MAX_VALUE / 2 : ref2.getIndex(); + if (idx1 != idx2) return idx1 - idx2; + } + String n1 = ref1 == null || ref1.name().isEmpty() ? readGetSetFieldName(o1) : ref1.name(); + String n2 = ref2 == null || ref2.name().isEmpty() ? readGetSetFieldName(o2) : ref2.name(); + if (n1 == null && n2 == null) return 0; + if (n1 == null) return -1; + if (n2 == null) return 1; + return n1.compareTo(n2); + }); + return generateDyncEncoder(factory, clazz, members); + } catch (Exception ex) { + ex.printStackTrace(); + return null; + } + } + + protected static String convertFieldName(final JsonFactory factory, Class clazz, AccessibleObject element) { + ConvertColumnEntry ref = factory.findRef(clazz, element); + String name = ref == null || ref.name().isEmpty() ? readGetSetFieldName(element) : ref.name(); + return name; + } + + protected static ConvertSmallString readConvertSmallString(AccessibleObject element) { + if (element instanceof Field) return ((Field) element).getAnnotation(ConvertSmallString.class); + Method method = (Method) element; + ConvertSmallString small = method.getAnnotation(ConvertSmallString.class); + if (small == null) { + try { + Field f = method.getDeclaringClass().getDeclaredField(readGetSetFieldName(method)); + if (f != null) small = f.getAnnotation(ConvertSmallString.class); + } catch (Exception e) { + } + } + return small; + } + + protected static Class readGetSetFieldType(AccessibleObject element) { + if (element instanceof Field) return ((Field) element).getType(); + return element == null ? null : ((Method) element).getReturnType(); + } + + protected static String readGetSetFieldName(AccessibleObject element) { + if (element instanceof Field) return ((Field) element).getName(); + Method method = (Method) element; + if (method == null) return null; + String fname = method.getName(); + if (!fname.startsWith("is") && !fname.startsWith("get") && !fname.startsWith("set")) return fname; + fname = fname.substring(fname.startsWith("is") ? 2 : 3); + if (fname.length() > 1 && !(fname.charAt(1) >= 'A' && fname.charAt(1) <= 'Z')) { + fname = Character.toLowerCase(fname.charAt(0)) + fname.substring(1); + } else if (fname.length() == 1) { + fname = "" + Character.toLowerCase(fname.charAt(0)); + } + return fname; + } + + protected static JsonDynEncoder generateDyncEncoder(final JsonFactory factory, final Class clazz, final List members) { + final String supDynName = JsonDynEncoder.class.getName().replace('.', '/'); + final String valtypeName = clazz.getName().replace('.', '/'); + final String writerName = JsonWriter.class.getName().replace('.', '/'); + final String encodeableName = Encodeable.class.getName().replace('.', '/'); + final String objEncoderName = ObjectEncoder.class.getName().replace('.', '/'); + final String typeDesc = org.redkale.asm.Type.getDescriptor(Type.class); + final String jsonfactoryDesc = org.redkale.asm.Type.getDescriptor(JsonFactory.class); + final String jsonwriterDesc = org.redkale.asm.Type.getDescriptor(JsonWriter.class); + final String writerDesc = org.redkale.asm.Type.getDescriptor(Writer.class); + final String encodeableDesc = org.redkale.asm.Type.getDescriptor(Encodeable.class); + final String objEncoderDesc = org.redkale.asm.Type.getDescriptor(ObjectEncoder.class); + final String valtypeDesc = org.redkale.asm.Type.getDescriptor(clazz); + + Map mixedNames0 = null; + for (AccessibleObject element : members) { + ConvertColumnEntry ref1 = factory.findRef(clazz, element); + final String fieldname = ref1 == null || ref1.name().isEmpty() ? readGetSetFieldName(element) : ref1.name(); + final Class fieldtype = readGetSetFieldType(element); + if (fieldtype != String.class && !fieldtype.isPrimitive()) { + if (mixedNames0 == null) mixedNames0 = new HashMap<>(); + mixedNames0.put(fieldname, element); + } + } + final Map mixedNames = mixedNames0; + final ClassLoader loader = Thread.currentThread().getContextClassLoader(); + final String newDynName = "org/redkaledyn/json/_Dyn" + JsonDynEncoder.class.getSimpleName() + "__" + clazz.getName().replace('.', '_').replace('$', '_'); + final ObjectEncoder selfObjEncoder = factory.createObjectEncoder(clazz); + selfObjEncoder.init(factory); + try { + Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); + Class newClazz = clz == null ? loader.loadClass(newDynName.replace('/', '.')) : clz; + JsonDynEncoder resultEncoder = (JsonDynEncoder) newClazz.getDeclaredConstructor(JsonFactory.class, Type.class).newInstance(factory, clazz); + Field selfField = newClazz.getDeclaredField("objectEncoderSelf"); + selfField.setAccessible(true); + selfField.set(resultEncoder, selfObjEncoder); + if (mixedNames != null) { + for (Map.Entry en : mixedNames.entrySet()) { + Field f = newClazz.getDeclaredField(en.getKey() + "Encoder"); + f.setAccessible(true); + f.set(resultEncoder, factory.loadEncoder(en.getValue() instanceof Field ? ((Field) en.getValue()).getGenericType() : ((Method) en.getValue()).getGenericReturnType())); + } + } + return resultEncoder; + } catch (Throwable ex) { + } + // ------------------------------------------------------------------------------ + ClassWriter cw = new ClassWriter(COMPUTE_FRAMES); + FieldVisitor fv; + MethodVisitor mv; + AnnotationVisitor av0; + + cw.visit(V11, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, "L" + supDynName + "<" + valtypeDesc + ">;", supDynName, null); + + fv = cw.visitField(ACC_PROTECTED, "objectEncoderSelf", objEncoderDesc, null, null); + fv.visitEnd(); + final int membersSize = members.size(); + boolean onlyTwoIntFieldObjectFlag = false; //鍙寘鍚袱涓猧nt瀛楁 + boolean onlyOneLatin1FieldObjectFlag = false; //鍙寘鍚竴涓狶atin1 String瀛楁 + boolean onlyShotIntLongLatin1MoreFieldObjectFlag = true; + int intFieldCount = 0; + for (AccessibleObject element : members) { + ConvertColumnEntry ref1 = factory.findRef(clazz, element); + final String fieldname = ref1 == null || ref1.name().isEmpty() ? readGetSetFieldName(element) : ref1.name(); + fv = cw.visitField(ACC_PROTECTED + ACC_FINAL, fieldname + "FieldBytes", "[B", null, null); + fv.visitEnd(); + fv = cw.visitField(ACC_PROTECTED + ACC_FINAL, fieldname + "CommaFieldBytes", "[B", null, null); + fv.visitEnd(); + fv = cw.visitField(ACC_PROTECTED + ACC_FINAL, fieldname + "FirstFieldBytes", "[B", null, null); + fv.visitEnd(); + final Class fieldtype = readGetSetFieldType(element); + if (fieldtype != String.class && !fieldtype.isPrimitive()) { + fv = cw.visitField(ACC_PROTECTED, fieldname + "Encoder", encodeableDesc, null, null); + fv.visitEnd(); + } + if (fieldtype == int.class) intFieldCount++; + if (fieldtype == String.class && membersSize == 1 && readConvertSmallString(element) != null) { + onlyOneLatin1FieldObjectFlag = true; + } else if (fieldtype != short.class && fieldtype != int.class && fieldtype != long.class && !(fieldtype == String.class && readConvertSmallString(element) != null)) { + onlyShotIntLongLatin1MoreFieldObjectFlag = false; + } + } + if (intFieldCount == 2 && intFieldCount == membersSize) onlyTwoIntFieldObjectFlag = true; + if (onlyShotIntLongLatin1MoreFieldObjectFlag && membersSize < 2) onlyShotIntLongLatin1MoreFieldObjectFlag = false; //瀛楁涓暟蹇呴』澶т簬1 + + { // 鏋勯犲嚱鏁 + mv = (cw.visitMethod(ACC_PUBLIC, "", "(" + jsonfactoryDesc + typeDesc + ")V", null, null)); + //mv.setDebug(true); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 2); + mv.visitMethodInsn(INVOKESPECIAL, supDynName, "", "(" + jsonfactoryDesc + typeDesc + ")V", false); + + for (AccessibleObject element : members) { + ConvertColumnEntry ref1 = factory.findRef(clazz, element); + final String fieldname = ref1 == null || ref1.name().isEmpty() ? readGetSetFieldName(element) : ref1.name(); + //xxxFieldBytes + mv.visitVarInsn(ALOAD, 0); + mv.visitLdcInsn("\"" + fieldname + "\":"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "getBytes", "()[B", false); + mv.visitFieldInsn(PUTFIELD, newDynName, fieldname + "FieldBytes", "[B"); + //xxxCommaFieldBytes + mv.visitVarInsn(ALOAD, 0); + mv.visitLdcInsn(",\"" + fieldname + "\":"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "getBytes", "()[B", false); + mv.visitFieldInsn(PUTFIELD, newDynName, fieldname + "CommaFieldBytes", "[B"); + //xxxFirstFieldBytes + mv.visitVarInsn(ALOAD, 0); + mv.visitLdcInsn("{\"" + fieldname + "\":"); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "getBytes", "()[B", false); + mv.visitFieldInsn(PUTFIELD, newDynName, fieldname + "FirstFieldBytes", "[B"); + } + mv.visitInsn(RETURN); + mv.visitMaxs(1 + members.size(), 1 + members.size()); + mv.visitEnd(); + } + + { + mv = (cw.visitMethod(ACC_PUBLIC, "convertTo", "(" + jsonwriterDesc + valtypeDesc + ")V", null, null)); + //mv.setDebug(true); + { //if (value == null) { out.writeObjectNull(null); return; } + mv.visitVarInsn(ALOAD, 2); + Label valif = new Label(); + mv.visitJumpInsn(IFNONNULL, valif); + mv.visitVarInsn(ALOAD, 1); + mv.visitInsn(ACONST_NULL); + mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeObjectNull", "(Ljava/lang/Class;)V", false); + mv.visitInsn(RETURN); + mv.visitLabel(valif); + mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); + } + { //if (!out.isExtFuncEmpty()) { objectEncoder.convertTo(out, value); return; } + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "isExtFuncEmpty", "()Z", false); + Label extif = new Label(); + mv.visitJumpInsn(IFNE, extif); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, "objectEncoderSelf", objEncoderDesc); + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 2); + mv.visitMethodInsn(INVOKEVIRTUAL, objEncoderName, "convertTo", "(" + org.redkale.asm.Type.getDescriptor(Writer.class) + "Ljava/lang/Object;)V", false); + mv.visitInsn(RETURN); + mv.visitLabel(extif); + mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); + } + + int maxLocals = 4; + int elementIndex = -1; + final Class firstType = readGetSetFieldType(members.get(0)); + final boolean mustHadComma = firstType.isPrimitive() && (firstType != boolean.class || !factory.tiny()); //byte/short/char/int/float/long/double + + if (onlyOneLatin1FieldObjectFlag) { + //out.writeObjectByOnlyOneLatin1FieldValue(messageFirstFieldBytes, value.getMessage());elementIndex++; + elementIndex++; + AccessibleObject element = members.get(elementIndex); + ConvertColumnEntry ref1 = factory.findRef(clazz, element); + final String fieldname = ref1 == null || ref1.name().isEmpty() ? readGetSetFieldName(element) : ref1.name(); + final Class fieldtype = readGetSetFieldType(element); + + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, fieldname + "FirstFieldBytes", "[B"); + + mv.visitVarInsn(ALOAD, 2); //String message = value.getMessage(); 鍔犺浇 value + if (element instanceof Field) { + mv.visitFieldInsn(GETFIELD, valtypeName, ((Field) element).getName(), org.redkale.asm.Type.getDescriptor(fieldtype)); + } else { + mv.visitMethodInsn(INVOKEVIRTUAL, valtypeName, ((Method) element).getName(), "()" + org.redkale.asm.Type.getDescriptor(fieldtype), false); + } + mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeObjectByOnlyOneLatin1FieldValue", "([BLjava/lang/String;)V", false); + maxLocals++; + } else if (onlyTwoIntFieldObjectFlag) { + elementIndex++; + AccessibleObject element1 = members.get(elementIndex); + ConvertColumnEntry ref1 = factory.findRef(clazz, element1); + final String fieldname1 = ref1 == null || ref1.name().isEmpty() ? readGetSetFieldName(element1) : ref1.name(); + final Class fieldtype1 = readGetSetFieldType(element1); + + elementIndex++; + AccessibleObject element2 = members.get(elementIndex); + ConvertColumnEntry ref2 = factory.findRef(clazz, element2); + final String fieldname2 = ref2 == null || ref2.name().isEmpty() ? readGetSetFieldName(element2) : ref2.name(); + final Class fieldtype2 = readGetSetFieldType(element2); + + mv.visitVarInsn(ALOAD, 1); + + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, fieldname1 + "FirstFieldBytes", "[B"); + + mv.visitVarInsn(ALOAD, 2); //String message = value.getMessage(); 鍔犺浇 value + if (element1 instanceof Field) { + mv.visitFieldInsn(GETFIELD, valtypeName, ((Field) element1).getName(), org.redkale.asm.Type.getDescriptor(fieldtype1)); + } else { + mv.visitMethodInsn(INVOKEVIRTUAL, valtypeName, ((Method) element1).getName(), "()" + org.redkale.asm.Type.getDescriptor(fieldtype1), false); + } + maxLocals ++; + + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, fieldname2 + "CommaFieldBytes", "[B"); + + mv.visitVarInsn(ALOAD, 2); //String message = value.getMessage(); 鍔犺浇 value + if (element2 instanceof Field) { + mv.visitFieldInsn(GETFIELD, valtypeName, ((Field) element2).getName(), org.redkale.asm.Type.getDescriptor(fieldtype2)); + } else { + mv.visitMethodInsn(INVOKEVIRTUAL, valtypeName, ((Method) element2).getName(), "()" + org.redkale.asm.Type.getDescriptor(fieldtype2), false); + } + maxLocals ++; + + mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeObjectByOnlyTwoIntFieldValue", "([BI[BI)V", false); + + } else if (onlyShotIntLongLatin1MoreFieldObjectFlag && mustHadComma) { + for (AccessibleObject element : members) { + elementIndex++; + ConvertColumnEntry ref1 = factory.findRef(clazz, element); + final String fieldname = ref1 == null || ref1.name().isEmpty() ? readGetSetFieldName(element) : ref1.name(); + final Class fieldtype = readGetSetFieldType(element); + + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, fieldname + (elementIndex == 0 ? "FirstFieldBytes" : "CommaFieldBytes"), "[B"); + + mv.visitVarInsn(ALOAD, 2); //String message = value.getMessage(); 鍔犺浇 value + if (element instanceof Field) { + mv.visitFieldInsn(GETFIELD, valtypeName, ((Field) element).getName(), org.redkale.asm.Type.getDescriptor(fieldtype)); + } else { + mv.visitMethodInsn(INVOKEVIRTUAL, valtypeName, ((Method) element).getName(), "()" + org.redkale.asm.Type.getDescriptor(fieldtype), false); + } + if (fieldtype == short.class) { + mv.visitMethodInsn(INVOKEVIRTUAL, writerName, elementIndex + 1 == membersSize ? "writeLastFieldShortValue" : "writeFieldShortValue", "([BS)V", false); + } else if (fieldtype == int.class) { + mv.visitMethodInsn(INVOKEVIRTUAL, writerName, elementIndex + 1 == membersSize ? "writeLastFieldIntValue" : "writeFieldIntValue", "([BI)V", false); + } else if (fieldtype == long.class) { + mv.visitMethodInsn(INVOKEVIRTUAL, writerName, elementIndex + 1 == membersSize ? "writeLastFieldLongValue" : "writeFieldLongValue", "([BJ)V", false); + } else { + mv.visitMethodInsn(INVOKEVIRTUAL, writerName, elementIndex + 1 == membersSize ? "writeLastFieldLatin1Value" : "writeFieldLatin1Value", "([BLjava/lang/String;)V", false); + } + + if (fieldtype == long.class || fieldtype == double.class) { + maxLocals += 2; + } else { + maxLocals++; + } + } + } else { + { //out.writeTo('{'); + mv.visitVarInsn(ALOAD, 1); + mv.visitIntInsn(BIPUSH, '{'); + mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeTo", "(B)V", false); + } + + if (!mustHadComma) { //boolean comma = false; + mv.visitInsn(ICONST_0); + mv.visitVarInsn(ISTORE, 3); + } + for (AccessibleObject element : members) { + elementIndex++; + ConvertColumnEntry ref1 = factory.findRef(clazz, element); + final String fieldname = ref1 == null || ref1.name().isEmpty() ? readGetSetFieldName(element) : ref1.name(); + final Class fieldtype = readGetSetFieldType(element); + int storeid = ASTORE; + int loadid = ALOAD; + { //String message = value.getMessage(); + mv.visitVarInsn(ALOAD, 2); //鍔犺浇 value + if (element instanceof Field) { + mv.visitFieldInsn(GETFIELD, valtypeName, ((Field) element).getName(), org.redkale.asm.Type.getDescriptor(fieldtype)); + } else { + mv.visitMethodInsn(INVOKEVIRTUAL, valtypeName, ((Method) element).getName(), "()" + org.redkale.asm.Type.getDescriptor(fieldtype), false); + } + if (fieldtype == boolean.class) { + storeid = ISTORE; + loadid = ILOAD; + mv.visitVarInsn(storeid, maxLocals); + } else if (fieldtype == byte.class) { + storeid = ISTORE; + loadid = ILOAD; + mv.visitVarInsn(storeid, maxLocals); + } else if (fieldtype == short.class) { + storeid = ISTORE; + loadid = ILOAD; + mv.visitVarInsn(storeid, maxLocals); + } else if (fieldtype == char.class) { + storeid = ISTORE; + loadid = ILOAD; + mv.visitVarInsn(storeid, maxLocals); + } else if (fieldtype == int.class) { + storeid = ISTORE; + loadid = ILOAD; + mv.visitVarInsn(storeid, maxLocals); + } else if (fieldtype == float.class) { + storeid = FSTORE; + loadid = FLOAD; + mv.visitVarInsn(storeid, maxLocals); + } else if (fieldtype == long.class) { + storeid = LSTORE; + loadid = LLOAD; + mv.visitVarInsn(storeid, maxLocals); + } else if (fieldtype == double.class) { + storeid = DSTORE; + loadid = DLOAD; + mv.visitVarInsn(storeid, maxLocals); + } else { + //storeid = ASTORE; + //loadid = ALOAD; + mv.visitVarInsn(storeid, maxLocals); + } + } + Label msgnotemptyif = null; + if (!fieldtype.isPrimitive()) { //if (message != null) { start + mv.visitVarInsn(loadid, maxLocals); + msgnotemptyif = new Label(); + mv.visitJumpInsn(IFNULL, msgnotemptyif); + if (factory.tiny() && fieldtype == String.class) { + mv.visitVarInsn(loadid, maxLocals); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "isEmpty", "()Z", false); + mv.visitJumpInsn(IFNE, msgnotemptyif); + } + } else if (fieldtype == boolean.class && factory.tiny()) { + mv.visitVarInsn(loadid, maxLocals); + msgnotemptyif = new Label(); + mv.visitJumpInsn(IFEQ, msgnotemptyif); + } + if (mustHadComma) { //绗竴涓瓧娈靛繀鐒朵細鍐欏叆 + if (elementIndex == 0) { //绗竴涓 + //out.writeTo(messageFieldBytes); + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, fieldname + "FieldBytes", "[B"); + mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeTo", "([B)V", false); + } else { + //out.writeTo(messageCommaFieldBytes); + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, fieldname + "CommaFieldBytes", "[B"); + mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeTo", "([B)V", false); + } + } else { //if(comma) {} else {} 浠g爜鍧 + //if (comma) { start + mv.visitVarInsn(ILOAD, 3); + Label commaif = new Label(); + mv.visitJumpInsn(IFEQ, commaif); + + //out.writeTo(messageCommaFieldBytes); + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, fieldname + "CommaFieldBytes", "[B"); + mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeTo", "([B)V", false); + + Label commaelse = new Label(); + mv.visitJumpInsn(GOTO, commaelse); + mv.visitLabel(commaif); + if (fieldtype == boolean.class) { + mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Opcodes.INTEGER}, 0, null); + } else if (fieldtype == byte.class) { + mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Opcodes.INTEGER}, 0, null); + } else if (fieldtype == short.class) { + mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Opcodes.INTEGER}, 0, null); + } else if (fieldtype == char.class) { + mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Opcodes.INTEGER}, 0, null); + } else if (fieldtype == int.class) { + mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Opcodes.INTEGER}, 0, null); + } else if (fieldtype == float.class) { + mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Opcodes.FLOAT}, 0, null); + } else if (fieldtype == long.class) { + mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Opcodes.LONG}, 0, null); + } else if (fieldtype == double.class) { + mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Opcodes.DOUBLE}, 0, null); + } else { + mv.visitFrame(Opcodes.F_APPEND, 2, new Object[]{Opcodes.INTEGER, "java/lang/String"}, 0, null); // } else { comma + } + //out.writeTo(messageFieldBytes); + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, fieldname + "FieldBytes", "[B"); + mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeTo", "([B)V", false); + //comma = true; + mv.visitInsn(ICONST_1); + mv.visitVarInsn(ISTORE, 3); + mv.visitLabel(commaelse); + mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); //if (comma) } end + } + //out.writeString(message); + if (fieldtype == boolean.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(loadid, maxLocals); + mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeBoolean", "(Z)V", false); + } else if (fieldtype == byte.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(loadid, maxLocals); + mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeByte", "(B)V", false); + } else if (fieldtype == short.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(loadid, maxLocals); + mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeShort", "(S)V", false); + } else if (fieldtype == char.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(loadid, maxLocals); + mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeChar", "(C)V", false); + } else if (fieldtype == int.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(loadid, maxLocals); + mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeInt", "(I)V", false); + } else if (fieldtype == float.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(loadid, maxLocals); + mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeFloat", "(F)V", false); + } else if (fieldtype == long.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(loadid, maxLocals); + mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeLong", "(J)V", false); + } else if (fieldtype == double.class) { + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(loadid, maxLocals); + mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeDouble", "(D)V", false); + } else if (fieldtype == String.class) { + if (readConvertSmallString(element) == null) { + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(loadid, maxLocals); + mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeString", "(Ljava/lang/String;)V", false); + } else { + mv.visitVarInsn(ALOAD, 1); + mv.visitInsn(ICONST_1); + mv.visitVarInsn(loadid, maxLocals); + mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeLatin1To", "(ZLjava/lang/String;)V", false); + } + } else { //int[],Boolean[],String[] + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, fieldname + "Encoder", encodeableDesc); + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(loadid, maxLocals); + mv.visitMethodInsn(INVOKEINTERFACE, encodeableName, "convertTo", "(" + writerDesc + "Ljava/lang/Object;)V", true); + } + if (!fieldtype.isPrimitive()) { //if (message != null) } end + mv.visitLabel(msgnotemptyif); + mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); + } else if (fieldtype == boolean.class && factory.tiny()) { + mv.visitLabel(msgnotemptyif); + mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); + } + if (fieldtype == long.class || fieldtype == double.class) { + maxLocals += 2; + } else { + maxLocals++; + } + } + { //out.writeTo('}'); + mv.visitVarInsn(ALOAD, 1); + mv.visitIntInsn(BIPUSH, '}'); + mv.visitMethodInsn(INVOKEVIRTUAL, writerName, "writeTo", "(B)V", false); + } + } + mv.visitInsn(RETURN); + mv.visitMaxs(maxLocals, maxLocals); + mv.visitEnd(); + } + { + mv = (cw.visitMethod(ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, "convertTo", "(" + jsonwriterDesc + "Ljava/lang/Object;)V", null, null)); + //mv.setDebug(true); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 2); + mv.visitTypeInsn(CHECKCAST, valtypeName); + mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "convertTo", "(" + jsonwriterDesc + valtypeDesc + ")V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(3, 3); + mv.visitEnd(); + } + 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); + RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, newClazz); + RedkaleClassLoader.putReflectionDeclaredConstructors(newClazz, newDynName.replace('/', '.'), JsonFactory.class, Type.class); + try { + JsonDynEncoder resultEncoder = (JsonDynEncoder) newClazz.getDeclaredConstructor(JsonFactory.class, Type.class).newInstance(factory, clazz); + Field selfField = newClazz.getDeclaredField("objectEncoderSelf"); + selfField.setAccessible(true); + selfField.set(resultEncoder, selfObjEncoder); + RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), selfField); + if (mixedNames != null) { + for (Map.Entry en : mixedNames.entrySet()) { + Field f = newClazz.getDeclaredField(en.getKey() + "Encoder"); + f.setAccessible(true); + f.set(resultEncoder, factory.loadEncoder(en.getValue() instanceof Field ? ((Field) en.getValue()).getGenericType() : ((Method) en.getValue()).getGenericReturnType())); + RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), f); + } + } + return resultEncoder; + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + + @Override + public abstract void convertTo(JsonWriter out, T value); + + @Override + public Type getType() { + return typeClass; + } +} diff --git a/src/main/java/org/redkale/convert/json/JsonFactory.java b/src/main/java/org/redkale/convert/json/JsonFactory.java index 5751a1cbe..fcbd1aab2 100644 --- a/src/main/java/org/redkale/convert/json/JsonFactory.java +++ b/src/main/java/org/redkale/convert/json/JsonFactory.java @@ -1,114 +1,114 @@ -/* - * 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.convert.json; - -import java.io.Serializable; -import java.lang.reflect.*; -import java.math.BigInteger; -import java.net.*; -import org.redkale.convert.*; -import org.redkale.convert.ext.*; -import org.redkale.util.*; - -/** - * JSON鐨凜onvertFactory - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@SuppressWarnings("unchecked") -public final class JsonFactory extends ConvertFactory { - - private static final JsonFactory instance = new JsonFactory(null, getSystemPropertyBoolean("redkaleconvert.json.tiny", "redkale.convert.tiny", true)); - - static { - instance.register(Serializable.class, instance.loadEncoder(Object.class)); - - //instance.register(AnyValue.class, instance.loadDecoder(AnyValue.DefaultAnyValue.class)); - //instance.register(AnyValue.class, instance.loadEncoder(AnyValue.DefaultAnyValue.class)); - } - - private JsonFactory(JsonFactory parent, boolean tiny) { - super(parent, tiny); - if (parent == null) { - this.register(InetAddress.class, InetAddressSimpledCoder.InetAddressJsonSimpledCoder.instance); - this.register(InetSocketAddress.class, InetAddressSimpledCoder.InetSocketAddressJsonSimpledCoder.instance); - this.register(DLong.class, DLongSimpledCoder.DLongJsonSimpledCoder.instance); - this.register(BigInteger.class, BigIntegerSimpledCoder.BigIntegerJsonSimpledCoder.instance); - this.register(java.time.Instant.class, InstantSimpledCoder.InstantJsonSimpledCoder.instance); - this.register(java.time.LocalDate.class, LocalDateSimpledCoder.LocalDateJsonSimpledCoder.instance); - this.register(java.time.LocalTime.class, LocalTimeSimpledCoder.LocalTimeJsonSimpledCoder.instance); - this.register(java.time.LocalDateTime.class, LocalDateTimeSimpledCoder.LocalDateTimeJsonSimpledCoder.instance); - } - } - - @Override - public JsonFactory tiny(boolean tiny) { - this.tiny = tiny; - return this; - } - - @Override - public JsonFactory skipAllIgnore(final boolean skipIgnore) { - this.registerSkipAllIgnore(skipIgnore); - return this; - } - - public static JsonFactory root() { - return instance; - } - - public static JsonFactory create() { - return new JsonFactory(null, getSystemPropertyBoolean("redkale.convert.json.tiny", "convert.tiny", true)); - } - - @Override - protected Encodeable createDyncEncoder(Type type) { - return JsonDynEncoder.createDyncEncoder(this, type); - } - - @Override - protected ObjectEncoder createObjectEncoder(Type type) { - return super.createObjectEncoder(type); - } - - protected boolean tiny() { - return this.tiny; - } - - @Override - public final JsonConvert getConvert() { - if (convert == null) convert = new JsonConvert(this, tiny); - return (JsonConvert) convert; - } - - @Override - public JsonFactory createChild() { - return new JsonFactory(this, this.tiny); - } - - @Override - public JsonFactory createChild(boolean tiny) { - return new JsonFactory(this, tiny); - } - - @Override - public ConvertType getConvertType() { - return ConvertType.JSON; - } - - @Override - public boolean isReversible() { - return false; - } - - @Override - public boolean isFieldSort() { - return true; - } -} +/* + * 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.convert.json; + +import java.io.Serializable; +import java.lang.reflect.*; +import java.math.BigInteger; +import java.net.*; +import org.redkale.convert.*; +import org.redkale.convert.ext.*; +import org.redkale.util.*; + +/** + * JSON鐨凜onvertFactory + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@SuppressWarnings("unchecked") +public final class JsonFactory extends ConvertFactory { + + private static final JsonFactory instance = new JsonFactory(null, getSystemPropertyBoolean("redkaleconvert.json.tiny", "redkale.convert.tiny", true)); + + static { + instance.register(Serializable.class, instance.loadEncoder(Object.class)); + + //instance.register(AnyValue.class, instance.loadDecoder(AnyValue.DefaultAnyValue.class)); + //instance.register(AnyValue.class, instance.loadEncoder(AnyValue.DefaultAnyValue.class)); + } + + private JsonFactory(JsonFactory parent, boolean tiny) { + super(parent, tiny); + if (parent == null) { + this.register(InetAddress.class, InetAddressSimpledCoder.InetAddressJsonSimpledCoder.instance); + this.register(InetSocketAddress.class, InetAddressSimpledCoder.InetSocketAddressJsonSimpledCoder.instance); + this.register(DLong.class, DLongSimpledCoder.DLongJsonSimpledCoder.instance); + this.register(BigInteger.class, BigIntegerSimpledCoder.BigIntegerJsonSimpledCoder.instance); + this.register(java.time.Instant.class, InstantSimpledCoder.InstantJsonSimpledCoder.instance); + this.register(java.time.LocalDate.class, LocalDateSimpledCoder.LocalDateJsonSimpledCoder.instance); + this.register(java.time.LocalTime.class, LocalTimeSimpledCoder.LocalTimeJsonSimpledCoder.instance); + this.register(java.time.LocalDateTime.class, LocalDateTimeSimpledCoder.LocalDateTimeJsonSimpledCoder.instance); + } + } + + @Override + public JsonFactory tiny(boolean tiny) { + this.tiny = tiny; + return this; + } + + @Override + public JsonFactory skipAllIgnore(final boolean skipIgnore) { + this.registerSkipAllIgnore(skipIgnore); + return this; + } + + public static JsonFactory root() { + return instance; + } + + public static JsonFactory create() { + return new JsonFactory(null, getSystemPropertyBoolean("redkale.convert.json.tiny", "convert.tiny", true)); + } + + @Override + protected Encodeable createDyncEncoder(Type type) { + return JsonDynEncoder.createDyncEncoder(this, type); + } + + @Override + protected ObjectEncoder createObjectEncoder(Type type) { + return super.createObjectEncoder(type); + } + + protected boolean tiny() { + return this.tiny; + } + + @Override + public final JsonConvert getConvert() { + if (convert == null) convert = new JsonConvert(this, tiny); + return (JsonConvert) convert; + } + + @Override + public JsonFactory createChild() { + return new JsonFactory(this, this.tiny); + } + + @Override + public JsonFactory createChild(boolean tiny) { + return new JsonFactory(this, tiny); + } + + @Override + public ConvertType getConvertType() { + return ConvertType.JSON; + } + + @Override + public boolean isReversible() { + return false; + } + + @Override + public boolean isFieldSort() { + return true; + } +} diff --git a/src/main/java/org/redkale/convert/json/JsonReader.java b/src/main/java/org/redkale/convert/json/JsonReader.java index b3d6da474..17c4683b7 100644 --- a/src/main/java/org/redkale/convert/json/JsonReader.java +++ b/src/main/java/org/redkale/convert/json/JsonReader.java @@ -1,706 +1,706 @@ -/* - * 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.convert.json; - -import org.redkale.convert.*; -import static org.redkale.convert.Reader.*; -import org.redkale.util.*; - -/** - * JSON鏁版嵁婧 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public class JsonReader extends Reader { - - protected int position = -1; - - private char[] text; - - private int limit; - -// public static ObjectPool createPool(int max) { -// return new ObjectPool<>(max, (Object... params) -> new JsonReader(), null, JsonReader::recycle); -// } - public JsonReader() { - } - - public JsonReader(String json) { - setText(Utility.charArray(json)); - } - - public JsonReader(char[] text) { - setText(text, 0, text.length); - } - - public JsonReader(char[] text, int start, int len) { - setText(text, start, len); - } - - public final void setText(String text) { - setText(Utility.charArray(text)); - } - - public final void setText(char[] text) { - setText(text, 0, text.length); - } - - public final void setText(char[] text, int start, int len) { - this.text = text; - this.position = start - 1; - this.limit = start + len - 1; - } - - protected boolean recycle() { - this.position = -1; - this.limit = -1; - this.text = null; - return true; - } - - public void close() { - this.recycle(); - } - - /** - * 鎵惧埌鎸囧畾鐨勫睘鎬у 渚嬪: {id : 1, data : { name : 'a', items : [1,2,3]}} seek('data.items') 鐩存帴璺宠浆鍒 [1,2,3]; - * - * @param key 鎸囧畾鐨勫睘鎬у悕 - */ - public final void seek(String key) { - if (key == null || key.length() < 1) return; - final String[] keys = key.split("\\."); - nextGoodChar(); //璇绘帀 { [ - for (String key1 : keys) { - while (this.hasNext()) { - String field = this.readSmallString(); - readBlank(); - if (key1.equals(field)) break; - skipValue(); - } - } - - } - - /** - * 璺宠繃灞炴х殑鍊 - */ - @Override - public final void skipValue() { - final char ch = nextGoodChar(); - switch (ch) { - case '"': - case '\'': - backChar(ch); - readString(); - break; - case '{': - while (hasNext()) { - this.readSmallString(); //璇绘帀field - this.readBlank(); - this.skipValue(); - } - break; - case '[': - while (hasNext()) { - this.skipValue(); - } - break; - default: - char c; - for (;;) { - c = nextChar(); - if (c <= ' ') return; - if (c == '}' || c == ']' || c == ',' || c == ':') { - backChar(c); - return; - } - } - } - } - - /** - * 璇诲彇涓嬩竴涓瓧绗︼紝 涓嶈烦杩囩┖鐧藉瓧绗 - * - * @return 绌虹櫧瀛楃鎴栨湁鏁堝瓧绗 - */ - protected char nextChar() { - return this.text[++this.position]; - } - - /** - * 璺宠繃绌虹櫧瀛楃锛 杩斿洖涓涓潪绌虹櫧瀛楃 - * - * @return 鏈夋晥瀛楃 - */ - protected char nextGoodChar() { - char c = nextChar(); - if (c > ' ') return c; - for (;;) { - c = nextChar(); - if (c > ' ') return c; - } - } - - /** - * 鍥為鏈鍚庤鍙栫殑瀛楃 - * - * @param ch 鍚庨鐨勫瓧绗 - */ - protected void backChar(char ch) { - this.position--; - } - - @Override - public final ValueType readType() { - char ch = nextGoodChar(); - if (ch == '{') { - backChar(ch); - return ValueType.MAP; - } - if (ch == '[') { - backChar(ch); - return ValueType.ARRAY; - } - backChar(ch); - return ValueType.STRING; - } - - /** - * 鍒ゆ柇涓嬩竴涓潪绌虹櫧瀛楃鏄惁涓簕 - * - * @param clazz 绫诲悕 - * - * @return 杩斿洖 null 琛ㄧず瀵硅薄涓簄ull锛 杩斿洖绌哄瓧绗︿覆琛ㄧず褰撳墠class涓庤繑鍥炵殑class涓鑷达紝杩斿洖闈炵┖瀛楃涓茶〃绀篶lass鏄綋鍓峜lass鐨勫瓙绫汇 - */ - @Override - public String readObjectB(final Class clazz) { - this.fieldIndex = 0; //蹇呴』瑕侀噸缃负0 - if (this.text.length == 0) return null; - char ch = this.text[++this.position]; - if (ch == '{') return ""; - if (ch <= ' ') { - for (;;) { - ch = this.text[++this.position]; - if (ch > ' ') break; - } - if (ch == '{') return ""; - } - if (ch == 'n' && text[++position] == 'u' && text[++position] == 'l' && text[++position] == 'l') return null; - if (ch == 'N' && text[++position] == 'U' && text[++position] == 'L' && text[++position] == 'L') return null; - throw new ConvertException("a json object text must begin with '{' (position = " + position + ") but '" + ch + "' in (" + new String(this.text) + ")"); - } - - @Override - public final void readObjectE(final Class clazz) { - } - - /** - * 鍒ゆ柇涓嬩竴涓潪绌虹櫧瀛楃鏄惁涓簕 - * - * @param member DeMember - * @param typevals byte[] - * @param keyDecoder Decodeable - * @param valuedecoder Decodeable - * - * @return SIGN_NOLENGTH 鎴 SIGN_NULL - */ - @Override - public final int readMapB(DeMember member, byte[] typevals, Decodeable keyDecoder, Decodeable valuedecoder) { - return readArrayB(member, typevals, keyDecoder); - } - - @Override - public final void readMapE() { - } - - /** - * 鍒ゆ柇涓嬩竴涓潪绌虹櫧瀛楃鏄惁涓篬 - * - * @param member DeMember - * @param typevals byte[] - * @param componentDecoder Decodeable - * - * @return SIGN_NOLENGTH 鎴 SIGN_NULL - */ - @Override - public int readArrayB(DeMember member, byte[] typevals, Decodeable componentDecoder) { - if (this.text.length == 0) return SIGN_NULL; - char ch = this.text[++this.position]; - if (ch == '[') return SIGN_NOLENGTH; - if (ch == '{') return SIGN_NOLENGTH; - if (ch <= ' ') { - for (;;) { - ch = this.text[++this.position]; - if (ch > ' ') break; - } - if (ch == '[') return SIGN_NOLENGTH; - if (ch == '{') return SIGN_NOLENGTH; - } - if (ch == 'n' && text[++position] == 'u' && text[++position] == 'l' && text[++position] == 'l') return SIGN_NULL; - if (ch == 'N' && text[++position] == 'U' && text[++position] == 'L' && text[++position] == 'L') return SIGN_NULL; - throw new ConvertException("a json array text must begin with '[' (position = " + position + ") but '" + ch + "' in (" + new String(this.text) + ")"); - } - - @Override - public final void readArrayE() { - } - - /** - * 鍒ゆ柇涓嬩竴涓潪绌虹櫧瀛楃鏄惁: - */ - @Override - public void readBlank() { - char ch = this.text[++this.position]; - if (ch == ':') return; - if (ch <= ' ') { - for (;;) { - ch = this.text[++this.position]; - if (ch > ' ') break; - } - if (ch == ':') return; - } - throw new ConvertException("'" + new String(text) + "'expected a ':' but '" + ch + "'(position = " + position + ") in (" + new String(this.text) + ")"); - } - - @Override - public int position() { - return this.position; - } - - @Override - public int readMemberContentLength(DeMember member, Decodeable decoder) { - return -1; - } - - /** - * 鍒ゆ柇瀵硅薄鏄惁瀛樺湪涓嬩竴涓睘鎬ф垨鑰呮暟缁勬槸鍚﹀瓨鍦ㄤ笅涓涓厓绱 - * - * @param startPosition 璧峰浣嶇疆 - * @param contentLength 鍐呭澶у皬锛 涓嶇‘瀹氱殑浼-1 - * - * @return 鏄惁瀛樺湪 - */ - @Override - public boolean hasNext(int startPosition, int contentLength) { - char ch = this.text[++this.position]; - if (ch == ',') return true; - if (ch == '}' || ch == ']') return false; - if (ch <= ' ') { - for (;;) { - ch = this.text[++this.position]; - if (ch > ' ') break; - } - if (ch == ',') return true; - if (ch == '}' || ch == ']') return false; - } - this.position--; // { [ 浜ょ敱 readObjectB 鎴 readMapB 鎴 readArrayB 璇诲彇 - return true; - } - - @Override - public final String readClassName() { - return null; - } - - @Override - public String readSmallString() { - final int eof = this.limit; - if (this.position == eof) return null; - final char[] text0 = this.text; - int currpos = this.position; - char ch = text0[++currpos]; - if (ch <= ' ') { - for (;;) { - ch = text0[++currpos]; - if (ch > ' ') break; - } - } - if (ch == '"' || ch == '\'') { - final char quote = ch; - final int start = currpos + 1; - for (;;) { - ch = text0[++currpos]; - if (ch == '\\') { - this.position = currpos - 1; - return readEscapeValue(quote, start); - } else if (ch == quote) { - break; - } - } - this.position = currpos; - char[] chs = new char[currpos - start]; - System.arraycopy(text0, start, chs, 0, chs.length); - return new String(chs); - } else { - int start = currpos; - for (;;) { - if (currpos == eof) break; - ch = text0[++currpos]; - if (ch == ',' || ch == ']' || ch == '}' || ch <= ' ' || ch == ':') break; - } - int len = currpos - start; - if (len < 1) { - this.position = currpos; - return String.valueOf(ch); - } - this.position = currpos - 1; - if (len == 4 && text0[start] == 'n' && text0[start + 1] == 'u' && text0[start + 2] == 'l' && text0[start + 3] == 'l') return null; - return new String(text0, start, len == eof ? (len + 1) : len); - } - } - - /** - * 璇诲彇涓涓猧nt鍊 - * - * @return int鍊 - */ - @Override - public int readInt() { - final char[] text0 = this.text; - final int eof = this.limit; - int currpos = this.position; - char firstchar = text0[++currpos]; - if (firstchar <= ' ') { - for (;;) { - firstchar = text0[++currpos]; - if (firstchar > ' ') break; - } - } - boolean quote = false; - if (firstchar == '"' || firstchar == '\'') { - quote = true; - firstchar = text0[++currpos]; - if (firstchar <= ' ') { - for (;;) { - firstchar = text0[++currpos]; - if (firstchar > ' ') break; - } - } - if (firstchar == '"' || firstchar == '\'') { - this.position = currpos; - return 0; - } - } - int value = 0; - final boolean negative = firstchar == '-'; - if (!negative) { - if (firstchar < '0' || firstchar > '9') throw new ConvertException("illegal escape(" + firstchar + ") (position = " + currpos + ") in (" + new String(this.text) + ")"); - value = firstchar - '0'; - } - boolean dot = false; - for (;;) { - if (currpos == eof) break; - char ch = text0[++currpos]; - int val = digits[ch]; - if (quote && val == -3) continue; - if (val <= -3) break; - if (dot) continue; - if (val == -1) { - if (ch == '.') { - dot = true; - continue; - } - throw new ConvertException("illegal escape(" + ch + ") (position = " + currpos + ") but '" + ch + "' in (" + new String(this.text) + ")"); - } - if (val != -2) value = value * 10 + val; - } - this.position = currpos - 1; - return negative ? -value : value; - } - - /** - * 璇诲彇涓涓猯ong鍊 - * - * @return long鍊 - */ - @Override - public long readLong() { - final char[] text0 = this.text; - final int eof = this.limit; - int currpos = this.position; - char firstchar = text0[++currpos]; - if (firstchar <= ' ') { - for (;;) { - firstchar = text0[++currpos]; - if (firstchar > ' ') break; - } - } - boolean quote = false; - if (firstchar == '"' || firstchar == '\'') { - quote = true; - firstchar = text0[++currpos]; - if (firstchar <= ' ') { - for (;;) { - firstchar = text0[++currpos]; - if (firstchar > ' ') break; - } - } - if (firstchar == '"' || firstchar == '\'') { - this.position = currpos; - return 0L; - } - } - long value = 0; - final boolean negative = firstchar == '-'; - if (!negative) { - if (firstchar < '0' || firstchar > '9') throw new ConvertException("illegal escape(" + firstchar + ") (position = " + currpos + ") in (" + new String(this.text) + ")"); - value = firstchar - '0'; - } - boolean dot = false; - for (;;) { - if (currpos == eof) break; - char ch = text0[++currpos]; - int val = digits[ch]; - if (quote && val == -3) continue; - if (val <= -3) break; - if (dot) continue; - if (val == -1) { - if (ch == '.') { - dot = true; - continue; - } - throw new ConvertException("illegal escape(" + ch + ") (position = " + currpos + ") but '" + ch + "' in (" + new String(this.text) + ")"); - } - if (val != -2) value = value * 10 + val; - } - this.position = currpos - 1; - return negative ? -value : value; - } - - @Override - public final DeMember readFieldName(final DeMember[] members) { - final String exceptedfield = this.readSmallString(); - if (exceptedfield == null) return null; - final int len = members.length; - if (this.fieldIndex >= len) this.fieldIndex = 0; - for (int k = this.fieldIndex; k < len; k++) { - if (exceptedfield.equals(members[k].getAttribute().field())) { - this.fieldIndex = k; - return members[k]; - } - } - for (int k = 0; k < this.fieldIndex; k++) { - if (exceptedfield.equals(members[k].getAttribute().field())) { - this.fieldIndex = k; - return members[k]; - } - } - return null; - //if (result == null && len == 1 && text0[start] == '@') return REFER; - } -//------------------------------------------------------------ - - @Override - public final boolean readBoolean() { - return "true".equalsIgnoreCase(this.readSmallString()); - } - - @Override - public final byte readByte() { - return (byte) readInt(); - } - - @Override - public final byte[] readByteArray() { - int len = readArrayB(null, null, null); - int contentLength = -1; - if (len == Reader.SIGN_NULL) return null; - if (len == Reader.SIGN_NOLENBUTBYTES) { - contentLength = readMemberContentLength(null, null); - len = Reader.SIGN_NOLENGTH; - } - if (len == Reader.SIGN_NOLENGTH) { - int size = 0; - byte[] data = new byte[8]; - int startPosition = position(); - while (hasNext(startPosition, contentLength)) { - if (size >= data.length) { - byte[] newdata = new byte[data.length + 4]; - System.arraycopy(data, 0, newdata, 0, size); - data = newdata; - } - data[size++] = readByte(); - } - readArrayE(); - byte[] newdata = new byte[size]; - System.arraycopy(data, 0, newdata, 0, size); - return newdata; - } else { - byte[] values = new byte[len]; - for (int i = 0; i < values.length; i++) { - values[i] = readByte(); - } - readArrayE(); - return values; - } - } - - @Override - public final char readChar() { - return (char) readInt(); - } - - @Override - public final short readShort() { - return (short) readInt(); - } - - @Override - public final float readFloat() { - String chars = readSmallString(); - if (chars != null) chars = chars.trim(); - if (chars == null || chars.isEmpty()) return 0.f; - return Float.parseFloat(chars); - } - - @Override - public final double readDouble() { - String chars = readSmallString(); - if (chars != null) chars = chars.trim(); - if (chars == null || chars.isEmpty()) return 0.0; - return Double.parseDouble(chars); - } - - /** - * 璇诲彇瀛楃涓诧紝 蹇呴』鏄"鎴栬'鍖呭洿鐨勫瓧绗︿覆鍊 - * - * @return String鍊 - */ - @Override - public String readString() { - final char[] text0 = this.text; - int currpos = this.position; - char expected = text0[++currpos]; - if (expected <= ' ') { - for (;;) { - expected = text0[++currpos]; - if (expected > ' ') break; - } - } - if (expected != '"' && expected != '\'') { - if (expected == 'n' && text0.length > currpos + 3 && (text0[1 + currpos] == 'u' && text0[2 + currpos] == 'l' && text0[3 + currpos] == 'l')) { - if (text0[++currpos] == 'u' && text0[++currpos] == 'l' && text0[++currpos] == 'l') { - this.position = currpos; - if (text0.length > currpos + 4) { - char ch = text0[currpos + 1]; - if (ch == ',' || ch <= ' ' || ch == '}' || ch == ']' || ch == ':') return null; - final int start = currpos - 3; - for (;;) { - if (currpos >= text0.length) break; - ch = text0[currpos]; - if (ch == ',' || ch <= ' ' || ch == '}' || ch == ']' || ch == ':') break; - currpos++; - } - if (currpos == start) throw new ConvertException("expected a string after a key but '" + text0[position] + "' (position = " + position + ") in (" + new String(this.text) + ")"); - this.position = currpos - 1; - return new String(text0, start, currpos - start); - } else { - return null; - } - } - } else { - final int start = currpos; - for (;;) { - if (currpos >= text0.length) break; - char ch = text0[currpos]; - if (ch == ',' || ch <= ' ' || ch == '}' || ch == ']' || ch == ':') break; - currpos++; - } - if (currpos == start) throw new ConvertException("expected a string after a key but '" + text0[position] + "' (position = " + position + ") in (" + new String(this.text) + ")"); - this.position = currpos - 1; - return new String(text0, start, currpos - start); - } - this.position = currpos; - throw new ConvertException("expected a ':' after a key but '" + text0[position] + "' (position = " + position + ") in (" + new String(this.text) + ")"); - } - final int start = ++currpos; - for (;;) { - char ch = text0[currpos]; - if (ch == expected) { - break; - } else if (ch == '\\') { - this.position = currpos - 1; - return readEscapeValue(expected, start); - } - currpos++; - } - this.position = currpos; - return new String(text0, start, currpos - start); - } - - private String readEscapeValue(final char expected, int start) { - StringBuilder array = new StringBuilder(); - final char[] text0 = this.text; - int pos = this.position; - array.append(text0, start, pos + 1 - start); - char c; - for (;;) { - c = text0[++pos]; - if (c == expected) { - this.position = pos; - return array.toString(); - } else if (c == '\\') { - c = text0[++pos]; - switch (c) { - case '"': - case '\'': - case '\\': - case '/': - array.append(c); - break; - case 'n': - array.append('\n'); - break; - case 'r': - array.append('\r'); - break; - case 'u': - array.append((char) Integer.parseInt(new String(new char[]{text0[++pos], text0[++pos], text0[++pos], text0[++pos]}), 16)); - break; - case 't': - array.append('\t'); - break; - case 'b': - array.append('\b'); - break; - case 'f': - array.append('\f'); - break; - default: - this.position = pos; - throw new ConvertException("illegal escape(" + c + ") (position = " + this.position + ") in (" + new String(this.text) + ")"); - } - } else { - array.append(c); - } - } - } - - final static int[] digits = new int[255]; - - static { - for (int i = 0; i < digits.length; i++) { - digits[i] = -1; //-1 閿欒 - } - for (int i = '0'; i <= '9'; i++) { - digits[i] = i - '0'; - } - for (int i = 'a'; i <= 'f'; i++) { - digits[i] = i - 'a' + 10; - } - for (int i = 'A'; i <= 'F'; i++) { - digits[i] = i - 'A' + 10; - } - digits['"'] = digits['\''] = -2; //-2 璺宠繃 - digits[' '] = digits['\t'] = digits['\r'] = digits['\n'] = -3; //-3鍙兘璺宠繃 - digits[','] = digits['}'] = digits[']'] = digits[':'] = -4; //-4閫鍑 - - } -} +/* + * 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.convert.json; + +import org.redkale.convert.*; +import static org.redkale.convert.Reader.*; +import org.redkale.util.*; + +/** + * JSON鏁版嵁婧 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public class JsonReader extends Reader { + + protected int position = -1; + + private char[] text; + + private int limit; + +// public static ObjectPool createPool(int max) { +// return new ObjectPool<>(max, (Object... params) -> new JsonReader(), null, JsonReader::recycle); +// } + public JsonReader() { + } + + public JsonReader(String json) { + setText(Utility.charArray(json)); + } + + public JsonReader(char[] text) { + setText(text, 0, text.length); + } + + public JsonReader(char[] text, int start, int len) { + setText(text, start, len); + } + + public final void setText(String text) { + setText(Utility.charArray(text)); + } + + public final void setText(char[] text) { + setText(text, 0, text.length); + } + + public final void setText(char[] text, int start, int len) { + this.text = text; + this.position = start - 1; + this.limit = start + len - 1; + } + + protected boolean recycle() { + this.position = -1; + this.limit = -1; + this.text = null; + return true; + } + + public void close() { + this.recycle(); + } + + /** + * 鎵惧埌鎸囧畾鐨勫睘鎬у 渚嬪: {id : 1, data : { name : 'a', items : [1,2,3]}} seek('data.items') 鐩存帴璺宠浆鍒 [1,2,3]; + * + * @param key 鎸囧畾鐨勫睘鎬у悕 + */ + public final void seek(String key) { + if (key == null || key.length() < 1) return; + final String[] keys = key.split("\\."); + nextGoodChar(); //璇绘帀 { [ + for (String key1 : keys) { + while (this.hasNext()) { + String field = this.readSmallString(); + readBlank(); + if (key1.equals(field)) break; + skipValue(); + } + } + + } + + /** + * 璺宠繃灞炴х殑鍊 + */ + @Override + public final void skipValue() { + final char ch = nextGoodChar(); + switch (ch) { + case '"': + case '\'': + backChar(ch); + readString(); + break; + case '{': + while (hasNext()) { + this.readSmallString(); //璇绘帀field + this.readBlank(); + this.skipValue(); + } + break; + case '[': + while (hasNext()) { + this.skipValue(); + } + break; + default: + char c; + for (;;) { + c = nextChar(); + if (c <= ' ') return; + if (c == '}' || c == ']' || c == ',' || c == ':') { + backChar(c); + return; + } + } + } + } + + /** + * 璇诲彇涓嬩竴涓瓧绗︼紝 涓嶈烦杩囩┖鐧藉瓧绗 + * + * @return 绌虹櫧瀛楃鎴栨湁鏁堝瓧绗 + */ + protected char nextChar() { + return this.text[++this.position]; + } + + /** + * 璺宠繃绌虹櫧瀛楃锛 杩斿洖涓涓潪绌虹櫧瀛楃 + * + * @return 鏈夋晥瀛楃 + */ + protected char nextGoodChar() { + char c = nextChar(); + if (c > ' ') return c; + for (;;) { + c = nextChar(); + if (c > ' ') return c; + } + } + + /** + * 鍥為鏈鍚庤鍙栫殑瀛楃 + * + * @param ch 鍚庨鐨勫瓧绗 + */ + protected void backChar(char ch) { + this.position--; + } + + @Override + public final ValueType readType() { + char ch = nextGoodChar(); + if (ch == '{') { + backChar(ch); + return ValueType.MAP; + } + if (ch == '[') { + backChar(ch); + return ValueType.ARRAY; + } + backChar(ch); + return ValueType.STRING; + } + + /** + * 鍒ゆ柇涓嬩竴涓潪绌虹櫧瀛楃鏄惁涓簕 + * + * @param clazz 绫诲悕 + * + * @return 杩斿洖 null 琛ㄧず瀵硅薄涓簄ull锛 杩斿洖绌哄瓧绗︿覆琛ㄧず褰撳墠class涓庤繑鍥炵殑class涓鑷达紝杩斿洖闈炵┖瀛楃涓茶〃绀篶lass鏄綋鍓峜lass鐨勫瓙绫汇 + */ + @Override + public String readObjectB(final Class clazz) { + this.fieldIndex = 0; //蹇呴』瑕侀噸缃负0 + if (this.text.length == 0) return null; + char ch = this.text[++this.position]; + if (ch == '{') return ""; + if (ch <= ' ') { + for (;;) { + ch = this.text[++this.position]; + if (ch > ' ') break; + } + if (ch == '{') return ""; + } + if (ch == 'n' && text[++position] == 'u' && text[++position] == 'l' && text[++position] == 'l') return null; + if (ch == 'N' && text[++position] == 'U' && text[++position] == 'L' && text[++position] == 'L') return null; + throw new ConvertException("a json object text must begin with '{' (position = " + position + ") but '" + ch + "' in (" + new String(this.text) + ")"); + } + + @Override + public final void readObjectE(final Class clazz) { + } + + /** + * 鍒ゆ柇涓嬩竴涓潪绌虹櫧瀛楃鏄惁涓簕 + * + * @param member DeMember + * @param typevals byte[] + * @param keyDecoder Decodeable + * @param valuedecoder Decodeable + * + * @return SIGN_NOLENGTH 鎴 SIGN_NULL + */ + @Override + public final int readMapB(DeMember member, byte[] typevals, Decodeable keyDecoder, Decodeable valuedecoder) { + return readArrayB(member, typevals, keyDecoder); + } + + @Override + public final void readMapE() { + } + + /** + * 鍒ゆ柇涓嬩竴涓潪绌虹櫧瀛楃鏄惁涓篬 + * + * @param member DeMember + * @param typevals byte[] + * @param componentDecoder Decodeable + * + * @return SIGN_NOLENGTH 鎴 SIGN_NULL + */ + @Override + public int readArrayB(DeMember member, byte[] typevals, Decodeable componentDecoder) { + if (this.text.length == 0) return SIGN_NULL; + char ch = this.text[++this.position]; + if (ch == '[') return SIGN_NOLENGTH; + if (ch == '{') return SIGN_NOLENGTH; + if (ch <= ' ') { + for (;;) { + ch = this.text[++this.position]; + if (ch > ' ') break; + } + if (ch == '[') return SIGN_NOLENGTH; + if (ch == '{') return SIGN_NOLENGTH; + } + if (ch == 'n' && text[++position] == 'u' && text[++position] == 'l' && text[++position] == 'l') return SIGN_NULL; + if (ch == 'N' && text[++position] == 'U' && text[++position] == 'L' && text[++position] == 'L') return SIGN_NULL; + throw new ConvertException("a json array text must begin with '[' (position = " + position + ") but '" + ch + "' in (" + new String(this.text) + ")"); + } + + @Override + public final void readArrayE() { + } + + /** + * 鍒ゆ柇涓嬩竴涓潪绌虹櫧瀛楃鏄惁: + */ + @Override + public void readBlank() { + char ch = this.text[++this.position]; + if (ch == ':') return; + if (ch <= ' ') { + for (;;) { + ch = this.text[++this.position]; + if (ch > ' ') break; + } + if (ch == ':') return; + } + throw new ConvertException("'" + new String(text) + "'expected a ':' but '" + ch + "'(position = " + position + ") in (" + new String(this.text) + ")"); + } + + @Override + public int position() { + return this.position; + } + + @Override + public int readMemberContentLength(DeMember member, Decodeable decoder) { + return -1; + } + + /** + * 鍒ゆ柇瀵硅薄鏄惁瀛樺湪涓嬩竴涓睘鎬ф垨鑰呮暟缁勬槸鍚﹀瓨鍦ㄤ笅涓涓厓绱 + * + * @param startPosition 璧峰浣嶇疆 + * @param contentLength 鍐呭澶у皬锛 涓嶇‘瀹氱殑浼-1 + * + * @return 鏄惁瀛樺湪 + */ + @Override + public boolean hasNext(int startPosition, int contentLength) { + char ch = this.text[++this.position]; + if (ch == ',') return true; + if (ch == '}' || ch == ']') return false; + if (ch <= ' ') { + for (;;) { + ch = this.text[++this.position]; + if (ch > ' ') break; + } + if (ch == ',') return true; + if (ch == '}' || ch == ']') return false; + } + this.position--; // { [ 浜ょ敱 readObjectB 鎴 readMapB 鎴 readArrayB 璇诲彇 + return true; + } + + @Override + public final String readClassName() { + return null; + } + + @Override + public String readSmallString() { + final int eof = this.limit; + if (this.position == eof) return null; + final char[] text0 = this.text; + int currpos = this.position; + char ch = text0[++currpos]; + if (ch <= ' ') { + for (;;) { + ch = text0[++currpos]; + if (ch > ' ') break; + } + } + if (ch == '"' || ch == '\'') { + final char quote = ch; + final int start = currpos + 1; + for (;;) { + ch = text0[++currpos]; + if (ch == '\\') { + this.position = currpos - 1; + return readEscapeValue(quote, start); + } else if (ch == quote) { + break; + } + } + this.position = currpos; + char[] chs = new char[currpos - start]; + System.arraycopy(text0, start, chs, 0, chs.length); + return new String(chs); + } else { + int start = currpos; + for (;;) { + if (currpos == eof) break; + ch = text0[++currpos]; + if (ch == ',' || ch == ']' || ch == '}' || ch <= ' ' || ch == ':') break; + } + int len = currpos - start; + if (len < 1) { + this.position = currpos; + return String.valueOf(ch); + } + this.position = currpos - 1; + if (len == 4 && text0[start] == 'n' && text0[start + 1] == 'u' && text0[start + 2] == 'l' && text0[start + 3] == 'l') return null; + return new String(text0, start, len == eof ? (len + 1) : len); + } + } + + /** + * 璇诲彇涓涓猧nt鍊 + * + * @return int鍊 + */ + @Override + public int readInt() { + final char[] text0 = this.text; + final int eof = this.limit; + int currpos = this.position; + char firstchar = text0[++currpos]; + if (firstchar <= ' ') { + for (;;) { + firstchar = text0[++currpos]; + if (firstchar > ' ') break; + } + } + boolean quote = false; + if (firstchar == '"' || firstchar == '\'') { + quote = true; + firstchar = text0[++currpos]; + if (firstchar <= ' ') { + for (;;) { + firstchar = text0[++currpos]; + if (firstchar > ' ') break; + } + } + if (firstchar == '"' || firstchar == '\'') { + this.position = currpos; + return 0; + } + } + int value = 0; + final boolean negative = firstchar == '-'; + if (!negative) { + if (firstchar < '0' || firstchar > '9') throw new ConvertException("illegal escape(" + firstchar + ") (position = " + currpos + ") in (" + new String(this.text) + ")"); + value = firstchar - '0'; + } + boolean dot = false; + for (;;) { + if (currpos == eof) break; + char ch = text0[++currpos]; + int val = digits[ch]; + if (quote && val == -3) continue; + if (val <= -3) break; + if (dot) continue; + if (val == -1) { + if (ch == '.') { + dot = true; + continue; + } + throw new ConvertException("illegal escape(" + ch + ") (position = " + currpos + ") but '" + ch + "' in (" + new String(this.text) + ")"); + } + if (val != -2) value = value * 10 + val; + } + this.position = currpos - 1; + return negative ? -value : value; + } + + /** + * 璇诲彇涓涓猯ong鍊 + * + * @return long鍊 + */ + @Override + public long readLong() { + final char[] text0 = this.text; + final int eof = this.limit; + int currpos = this.position; + char firstchar = text0[++currpos]; + if (firstchar <= ' ') { + for (;;) { + firstchar = text0[++currpos]; + if (firstchar > ' ') break; + } + } + boolean quote = false; + if (firstchar == '"' || firstchar == '\'') { + quote = true; + firstchar = text0[++currpos]; + if (firstchar <= ' ') { + for (;;) { + firstchar = text0[++currpos]; + if (firstchar > ' ') break; + } + } + if (firstchar == '"' || firstchar == '\'') { + this.position = currpos; + return 0L; + } + } + long value = 0; + final boolean negative = firstchar == '-'; + if (!negative) { + if (firstchar < '0' || firstchar > '9') throw new ConvertException("illegal escape(" + firstchar + ") (position = " + currpos + ") in (" + new String(this.text) + ")"); + value = firstchar - '0'; + } + boolean dot = false; + for (;;) { + if (currpos == eof) break; + char ch = text0[++currpos]; + int val = digits[ch]; + if (quote && val == -3) continue; + if (val <= -3) break; + if (dot) continue; + if (val == -1) { + if (ch == '.') { + dot = true; + continue; + } + throw new ConvertException("illegal escape(" + ch + ") (position = " + currpos + ") but '" + ch + "' in (" + new String(this.text) + ")"); + } + if (val != -2) value = value * 10 + val; + } + this.position = currpos - 1; + return negative ? -value : value; + } + + @Override + public final DeMember readFieldName(final DeMember[] members) { + final String exceptedfield = this.readSmallString(); + if (exceptedfield == null) return null; + final int len = members.length; + if (this.fieldIndex >= len) this.fieldIndex = 0; + for (int k = this.fieldIndex; k < len; k++) { + if (exceptedfield.equals(members[k].getAttribute().field())) { + this.fieldIndex = k; + return members[k]; + } + } + for (int k = 0; k < this.fieldIndex; k++) { + if (exceptedfield.equals(members[k].getAttribute().field())) { + this.fieldIndex = k; + return members[k]; + } + } + return null; + //if (result == null && len == 1 && text0[start] == '@') return REFER; + } +//------------------------------------------------------------ + + @Override + public final boolean readBoolean() { + return "true".equalsIgnoreCase(this.readSmallString()); + } + + @Override + public final byte readByte() { + return (byte) readInt(); + } + + @Override + public final byte[] readByteArray() { + int len = readArrayB(null, null, null); + int contentLength = -1; + if (len == Reader.SIGN_NULL) return null; + if (len == Reader.SIGN_NOLENBUTBYTES) { + contentLength = readMemberContentLength(null, null); + len = Reader.SIGN_NOLENGTH; + } + if (len == Reader.SIGN_NOLENGTH) { + int size = 0; + byte[] data = new byte[8]; + int startPosition = position(); + while (hasNext(startPosition, contentLength)) { + if (size >= data.length) { + byte[] newdata = new byte[data.length + 4]; + System.arraycopy(data, 0, newdata, 0, size); + data = newdata; + } + data[size++] = readByte(); + } + readArrayE(); + byte[] newdata = new byte[size]; + System.arraycopy(data, 0, newdata, 0, size); + return newdata; + } else { + byte[] values = new byte[len]; + for (int i = 0; i < values.length; i++) { + values[i] = readByte(); + } + readArrayE(); + return values; + } + } + + @Override + public final char readChar() { + return (char) readInt(); + } + + @Override + public final short readShort() { + return (short) readInt(); + } + + @Override + public final float readFloat() { + String chars = readSmallString(); + if (chars != null) chars = chars.trim(); + if (chars == null || chars.isEmpty()) return 0.f; + return Float.parseFloat(chars); + } + + @Override + public final double readDouble() { + String chars = readSmallString(); + if (chars != null) chars = chars.trim(); + if (chars == null || chars.isEmpty()) return 0.0; + return Double.parseDouble(chars); + } + + /** + * 璇诲彇瀛楃涓诧紝 蹇呴』鏄"鎴栬'鍖呭洿鐨勫瓧绗︿覆鍊 + * + * @return String鍊 + */ + @Override + public String readString() { + final char[] text0 = this.text; + int currpos = this.position; + char expected = text0[++currpos]; + if (expected <= ' ') { + for (;;) { + expected = text0[++currpos]; + if (expected > ' ') break; + } + } + if (expected != '"' && expected != '\'') { + if (expected == 'n' && text0.length > currpos + 3 && (text0[1 + currpos] == 'u' && text0[2 + currpos] == 'l' && text0[3 + currpos] == 'l')) { + if (text0[++currpos] == 'u' && text0[++currpos] == 'l' && text0[++currpos] == 'l') { + this.position = currpos; + if (text0.length > currpos + 4) { + char ch = text0[currpos + 1]; + if (ch == ',' || ch <= ' ' || ch == '}' || ch == ']' || ch == ':') return null; + final int start = currpos - 3; + for (;;) { + if (currpos >= text0.length) break; + ch = text0[currpos]; + if (ch == ',' || ch <= ' ' || ch == '}' || ch == ']' || ch == ':') break; + currpos++; + } + if (currpos == start) throw new ConvertException("expected a string after a key but '" + text0[position] + "' (position = " + position + ") in (" + new String(this.text) + ")"); + this.position = currpos - 1; + return new String(text0, start, currpos - start); + } else { + return null; + } + } + } else { + final int start = currpos; + for (;;) { + if (currpos >= text0.length) break; + char ch = text0[currpos]; + if (ch == ',' || ch <= ' ' || ch == '}' || ch == ']' || ch == ':') break; + currpos++; + } + if (currpos == start) throw new ConvertException("expected a string after a key but '" + text0[position] + "' (position = " + position + ") in (" + new String(this.text) + ")"); + this.position = currpos - 1; + return new String(text0, start, currpos - start); + } + this.position = currpos; + throw new ConvertException("expected a ':' after a key but '" + text0[position] + "' (position = " + position + ") in (" + new String(this.text) + ")"); + } + final int start = ++currpos; + for (;;) { + char ch = text0[currpos]; + if (ch == expected) { + break; + } else if (ch == '\\') { + this.position = currpos - 1; + return readEscapeValue(expected, start); + } + currpos++; + } + this.position = currpos; + return new String(text0, start, currpos - start); + } + + private String readEscapeValue(final char expected, int start) { + StringBuilder array = new StringBuilder(); + final char[] text0 = this.text; + int pos = this.position; + array.append(text0, start, pos + 1 - start); + char c; + for (;;) { + c = text0[++pos]; + if (c == expected) { + this.position = pos; + return array.toString(); + } else if (c == '\\') { + c = text0[++pos]; + switch (c) { + case '"': + case '\'': + case '\\': + case '/': + array.append(c); + break; + case 'n': + array.append('\n'); + break; + case 'r': + array.append('\r'); + break; + case 'u': + array.append((char) Integer.parseInt(new String(new char[]{text0[++pos], text0[++pos], text0[++pos], text0[++pos]}), 16)); + break; + case 't': + array.append('\t'); + break; + case 'b': + array.append('\b'); + break; + case 'f': + array.append('\f'); + break; + default: + this.position = pos; + throw new ConvertException("illegal escape(" + c + ") (position = " + this.position + ") in (" + new String(this.text) + ")"); + } + } else { + array.append(c); + } + } + } + + final static int[] digits = new int[255]; + + static { + for (int i = 0; i < digits.length; i++) { + digits[i] = -1; //-1 閿欒 + } + for (int i = '0'; i <= '9'; i++) { + digits[i] = i - '0'; + } + for (int i = 'a'; i <= 'f'; i++) { + digits[i] = i - 'a' + 10; + } + for (int i = 'A'; i <= 'F'; i++) { + digits[i] = i - 'A' + 10; + } + digits['"'] = digits['\''] = -2; //-2 璺宠繃 + digits[' '] = digits['\t'] = digits['\r'] = digits['\n'] = -3; //-3鍙兘璺宠繃 + digits[','] = digits['}'] = digits[']'] = digits[':'] = -4; //-4閫鍑 + + } +} diff --git a/src/main/java/org/redkale/convert/json/JsonSimpledCoder.java b/src/main/java/org/redkale/convert/json/JsonSimpledCoder.java index 6f5a067ce..c2fec1fb2 100644 --- a/src/main/java/org/redkale/convert/json/JsonSimpledCoder.java +++ b/src/main/java/org/redkale/convert/json/JsonSimpledCoder.java @@ -1,20 +1,20 @@ -/* - * 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.convert.json; - -import org.redkale.convert.SimpledCoder; - -/** - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param 搴忓垪鍖/鍙嶈В鏋愮殑鏁版嵁绫诲瀷 - */ -public abstract class JsonSimpledCoder extends SimpledCoder { - -} +/* + * 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.convert.json; + +import org.redkale.convert.SimpledCoder; + +/** + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param 搴忓垪鍖/鍙嶈В鏋愮殑鏁版嵁绫诲瀷 + */ +public abstract class JsonSimpledCoder extends SimpledCoder { + +} diff --git a/src/main/java/org/redkale/convert/json/JsonStreamReader.java b/src/main/java/org/redkale/convert/json/JsonStreamReader.java index 1a1e9b988..bd9a6186e 100644 --- a/src/main/java/org/redkale/convert/json/JsonStreamReader.java +++ b/src/main/java/org/redkale/convert/json/JsonStreamReader.java @@ -1,43 +1,43 @@ -/* - * 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.convert.json; - -import java.io.*; -import org.redkale.convert.*; - -/** - * - * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -class JsonStreamReader extends JsonByteBufferReader { - - private InputStream in; - - protected JsonStreamReader(InputStream in) { - super((ConvertMask) null); - this.in = in; - } - - @Override - protected boolean recycle() { - super.recycle(); // this.position 鍒濆鍖栧间负-1 - this.in = null; - return false; - } - - @Override - protected byte nextByte() { - try { - byte b = (byte) in.read(); - this.position++; - return b; - } catch (IOException e) { - throw new ConvertException(e); - } - } -} +/* + * 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.convert.json; + +import java.io.*; +import org.redkale.convert.*; + +/** + * + * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +class JsonStreamReader extends JsonByteBufferReader { + + private InputStream in; + + protected JsonStreamReader(InputStream in) { + super((ConvertMask) null); + this.in = in; + } + + @Override + protected boolean recycle() { + super.recycle(); // this.position 鍒濆鍖栧间负-1 + this.in = null; + return false; + } + + @Override + protected byte nextByte() { + try { + byte b = (byte) in.read(); + this.position++; + return b; + } catch (IOException e) { + throw new ConvertException(e); + } + } +} diff --git a/src/main/java/org/redkale/convert/json/JsonStreamWriter.java b/src/main/java/org/redkale/convert/json/JsonStreamWriter.java index c900e58a3..ad989ebc5 100644 --- a/src/main/java/org/redkale/convert/json/JsonStreamWriter.java +++ b/src/main/java/org/redkale/convert/json/JsonStreamWriter.java @@ -1,160 +1,160 @@ -/* - * 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.convert.json; - -import java.io.*; -import java.nio.*; -import java.nio.charset.*; -import org.redkale.convert.*; -import org.redkale.util.*; - -/** - * - * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -class JsonStreamWriter extends JsonByteBufferWriter { - - private OutputStream out; - - protected JsonStreamWriter(boolean tiny, OutputStream out) { - this(tiny, null, out); - } - - protected JsonStreamWriter(boolean tiny, Charset charset, OutputStream out) { - super(tiny, charset, null); - this.out = out; - } - - @Override - protected boolean recycle() { - super.recycle(); - this.out = null; - return false; - } - - @Override - public void writeTo(final char ch) { - if (ch > Byte.MAX_VALUE) throw new ConvertException("writeTo char(int.value = " + (int) ch + ") must be less 127"); - try { - out.write((byte) ch); - } catch (IOException e) { - throw new ConvertException(e); - } - } - - @Override - public void writeTo(final char[] chs, final int start, final int len) { - writeTo(false, chs, start, len); - } - - private void writeTo(final boolean quote, final char[] chs, final int start, final int len) { - try { - if (quote) out.write('"'); - if (charset == null) { //UTF-8 - final int limit = start + len; - for (int i = start; i < limit; i++) { - char c = chs[i]; - if (c < 0x80) { - out.write((byte) c); - } else if (c < 0x800) { - out.write((byte) (0xc0 | (c >> 6))); - out.write((byte) (0x80 | (c & 0x3f))); - } else if (Character.isSurrogate(c)) { //杩炲彇涓や釜 - int uc = Character.toCodePoint(c, chs[i + 1]); - out.write((byte) (0xf0 | ((uc >> 18)))); - out.write((byte) (0x80 | ((uc >> 12) & 0x3f))); - out.write((byte) (0x80 | ((uc >> 6) & 0x3f))); - out.write((byte) (0x80 | (uc & 0x3f))); - i++; - } else { - out.write((byte) (0xe0 | ((c >> 12)))); - out.write((byte) (0x80 | ((c >> 6) & 0x3f))); - out.write((byte) (0x80 | (c & 0x3f))); - } - } - } else { - ByteBuffer bb = charset.encode(CharBuffer.wrap(chs, start, len)); - out.write(bb.array()); - } - if (quote) out.write('"'); - } catch (IOException e) { - throw new ConvertException(e); - } - } - - /** - * 娉ㄦ剰锛 璇tring鍊间笉鑳戒负null涓斾笉浼氳繘琛岃浆涔夛紝 鍙敤浜庝笉鍚渶瑕佽浆涔夊瓧绗︾殑瀛楃涓诧紝渚嬪enum銆乨ouble銆丅igInteger杞崲鐨凷tring - * - * @param quote 鏄惁鍐欏叆鍙屽紩鍙 - * @param value String鍊 - */ - @Override - public void writeLatin1To(final boolean quote, final String value) { - char[] chs = Utility.charArray(value); - writeTo(quote, chs, 0, chs.length); - } - - @Override - public void writeInt(int value) { - writeLatin1To(false, String.valueOf(value)); - } - - @Override - public void writeLong(long value) { - writeLatin1To(false, String.valueOf(value)); - } - - @Override - public void writeString(String value) { - if (value == null) { - writeNull(); - return; - } - final char[] chs = Utility.charArray(value); - int len = 0; - for (char ch : chs) { - switch (ch) { - case '\n': len += 2; - break; - case '\r': len += 2; - break; - case '\t': len += 2; - break; - case '\\': len += 2; - break; - case '"': len += 2; - break; - default: len++; - break; - } - } - if (len == chs.length) { - writeTo(true, chs, 0, len); - return; - } - StringBuilder sb = new StringBuilder(len); - for (char ch : chs) { - switch (ch) { - case '\n': sb.append("\\n"); - break; - case '\r': sb.append("\\r"); - break; - case '\t': sb.append("\\t"); - break; - case '\\': sb.append("\\\\"); - break; - case '"': sb.append("\\\""); - break; - default: sb.append(ch); - break; - } - } - char[] cs = Utility.charArray(sb); - writeTo(true, cs, 0, sb.length()); - } -} +/* + * 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.convert.json; + +import java.io.*; +import java.nio.*; +import java.nio.charset.*; +import org.redkale.convert.*; +import org.redkale.util.*; + +/** + * + * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +class JsonStreamWriter extends JsonByteBufferWriter { + + private OutputStream out; + + protected JsonStreamWriter(boolean tiny, OutputStream out) { + this(tiny, null, out); + } + + protected JsonStreamWriter(boolean tiny, Charset charset, OutputStream out) { + super(tiny, charset, null); + this.out = out; + } + + @Override + protected boolean recycle() { + super.recycle(); + this.out = null; + return false; + } + + @Override + public void writeTo(final char ch) { + if (ch > Byte.MAX_VALUE) throw new ConvertException("writeTo char(int.value = " + (int) ch + ") must be less 127"); + try { + out.write((byte) ch); + } catch (IOException e) { + throw new ConvertException(e); + } + } + + @Override + public void writeTo(final char[] chs, final int start, final int len) { + writeTo(false, chs, start, len); + } + + private void writeTo(final boolean quote, final char[] chs, final int start, final int len) { + try { + if (quote) out.write('"'); + if (charset == null) { //UTF-8 + final int limit = start + len; + for (int i = start; i < limit; i++) { + char c = chs[i]; + if (c < 0x80) { + out.write((byte) c); + } else if (c < 0x800) { + out.write((byte) (0xc0 | (c >> 6))); + out.write((byte) (0x80 | (c & 0x3f))); + } else if (Character.isSurrogate(c)) { //杩炲彇涓や釜 + int uc = Character.toCodePoint(c, chs[i + 1]); + out.write((byte) (0xf0 | ((uc >> 18)))); + out.write((byte) (0x80 | ((uc >> 12) & 0x3f))); + out.write((byte) (0x80 | ((uc >> 6) & 0x3f))); + out.write((byte) (0x80 | (uc & 0x3f))); + i++; + } else { + out.write((byte) (0xe0 | ((c >> 12)))); + out.write((byte) (0x80 | ((c >> 6) & 0x3f))); + out.write((byte) (0x80 | (c & 0x3f))); + } + } + } else { + ByteBuffer bb = charset.encode(CharBuffer.wrap(chs, start, len)); + out.write(bb.array()); + } + if (quote) out.write('"'); + } catch (IOException e) { + throw new ConvertException(e); + } + } + + /** + * 娉ㄦ剰锛 璇tring鍊间笉鑳戒负null涓斾笉浼氳繘琛岃浆涔夛紝 鍙敤浜庝笉鍚渶瑕佽浆涔夊瓧绗︾殑瀛楃涓诧紝渚嬪enum銆乨ouble銆丅igInteger杞崲鐨凷tring + * + * @param quote 鏄惁鍐欏叆鍙屽紩鍙 + * @param value String鍊 + */ + @Override + public void writeLatin1To(final boolean quote, final String value) { + char[] chs = Utility.charArray(value); + writeTo(quote, chs, 0, chs.length); + } + + @Override + public void writeInt(int value) { + writeLatin1To(false, String.valueOf(value)); + } + + @Override + public void writeLong(long value) { + writeLatin1To(false, String.valueOf(value)); + } + + @Override + public void writeString(String value) { + if (value == null) { + writeNull(); + return; + } + final char[] chs = Utility.charArray(value); + int len = 0; + for (char ch : chs) { + switch (ch) { + case '\n': len += 2; + break; + case '\r': len += 2; + break; + case '\t': len += 2; + break; + case '\\': len += 2; + break; + case '"': len += 2; + break; + default: len++; + break; + } + } + if (len == chs.length) { + writeTo(true, chs, 0, len); + return; + } + StringBuilder sb = new StringBuilder(len); + for (char ch : chs) { + switch (ch) { + case '\n': sb.append("\\n"); + break; + case '\r': sb.append("\\r"); + break; + case '\t': sb.append("\\t"); + break; + case '\\': sb.append("\\\\"); + break; + case '"': sb.append("\\\""); + break; + default: sb.append(ch); + break; + } + } + char[] cs = Utility.charArray(sb); + writeTo(true, cs, 0, sb.length()); + } +} diff --git a/src/main/java/org/redkale/convert/json/JsonWriter.java b/src/main/java/org/redkale/convert/json/JsonWriter.java index 2ac76dbb7..96c150e97 100644 --- a/src/main/java/org/redkale/convert/json/JsonWriter.java +++ b/src/main/java/org/redkale/convert/json/JsonWriter.java @@ -1,256 +1,256 @@ -/* - * 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.convert.json; - -import java.lang.reflect.Type; -import org.redkale.convert.*; -import org.redkale.util.*; - -/** - * - * writeTo绯诲垪鐨勬柟娉曡緭鍑虹殑瀛楃涓嶈兘鍚壒娈婂瓧绗 - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public abstract class JsonWriter extends Writer { - - protected static final int defaultSize = Integer.getInteger("redkale.convert.json.writer.buffer.defsize", Integer.getInteger("redkale.convert.writer.buffer.defsize", 1024)); - - protected boolean tiny; - - @Override - public boolean tiny() { - return tiny; - } - - public JsonWriter tiny(boolean tiny) { - this.tiny = tiny; - return this; - } - - public boolean isExtFuncEmpty() { - return this.objExtFunc == null && this.objFieldFunc == null; - } - - //----------------------------------------------------------------------- - public abstract void writeTo(final char ch); //鍙兘鏄 0 - 127 鐨勫瓧绗 - - public abstract void writeTo(final char[] chs, final int start, final int len); //鍙兘鏄 0 - 127 鐨勫瓧绗 - - public abstract void writeTo(final byte ch); //鍙兘鏄 0 - 127 鐨勫瓧绗 - - public abstract void writeTo(final byte[] chs, final int start, final int len); //鍙兘鏄 0 - 127 鐨勫瓧绗 - - /** - * 娉ㄦ剰锛 璇tring鍊间笉鑳戒负null涓斾笉浼氳繘琛岃浆涔夛紝 鍙敤浜庝笉鍚渶瑕佽浆涔夊瓧绗︾殑瀛楃涓诧紝渚嬪enum銆乨ouble銆丅igInteger杞崲鐨凷tring - * - * @param quote 鏄惁鍔犲弻寮曞彿 - * @param value 闈瀗ull涓斾笉鍚渶瑕佽浆涔夌殑瀛楃鐨凷tring鍊 - */ - public abstract void writeLatin1To(final boolean quote, final String value); - - public abstract void writeFieldShortValue(final byte[] fieldBytes, final short value); - - public abstract void writeFieldIntValue(final byte[] fieldBytes, final int value); - - public abstract void writeFieldLongValue(final byte[] fieldBytes, final long value); - - public abstract void writeFieldLatin1Value(final byte[] fieldBytes, final String value); - - public abstract void writeLastFieldShortValue(final byte[] fieldBytes, final short value); - - public abstract void writeLastFieldIntValue(final byte[] fieldBytes, final int value); - - public abstract void writeLastFieldLongValue(final byte[] fieldBytes, final long value); - - public abstract void writeLastFieldLatin1Value(final byte[] fieldBytes, final String value); - - //firstFieldBytes 蹇呴』甯寮澶 - public abstract void writeObjectByOnlyOneLatin1FieldValue(final byte[] firstFieldBytes, final String value); - - //firstFieldBytes 蹇呴』甯寮澶, lastFieldBytes蹇呴』,寮澶 - public abstract void writeObjectByOnlyTwoIntFieldValue(final byte[] firstFieldBytes, final int value1, final byte[] lastFieldBytes, final int value2); - - @Override - public abstract void writeBoolean(boolean value); - - @Override - public abstract void writeInt(int value); - - @Override - public abstract void writeLong(long value); - - @Override - public abstract void writeString(String value); - - @Override //鍙璁窲sonBytesWriter閲嶅啓姝ゆ柟娉 - public void writeFieldName(EnMember member, String fieldName, Type fieldType, int fieldPos) { - if (this.comma) writeTo(','); - if (member != null) { - writeTo(member.getJsonFieldNameChars()); - } else { - writeLatin1To(true, fieldName); - writeTo(':'); - } - } - - @Override - public final void writeSmallString(String value) { - writeLatin1To(true, value); - } - - //---------------------------------------------------------------------------------------------- - public final void writeTo(final char... chs) { //鍙兘鏄 0 - 127 鐨勫瓧绗 - writeTo(chs, 0, chs.length); - } - - @Override - public final void writeByte(byte value) { - writeInt(value); - } - - public final void writeTo(final byte[] chs) { //鍙兘鏄 0 - 127 鐨勫瓧绗 - writeTo(chs, 0, chs.length); - } - - @Override - public final void writeByteArray(byte[] values) { - if (values == null) { - writeNull(); - return; - } - writeArrayB(values.length, null, null, values); - boolean flag = false; - for (byte v : values) { - if (flag) writeArrayMark(); - writeByte(v); - flag = true; - } - writeArrayE(); - } - - @Override - public final void writeChar(char value) { - writeInt(value); - } - - @Override - public final void writeShort(short value) { - writeInt(value); - } - - @Override - public final void writeFloat(float value) { - writeLatin1To(false, String.valueOf(value)); - } - - @Override - public final void writeDouble(double value) { - writeLatin1To(false, String.valueOf(value)); - } - - @Override - public final void writeWrapper(StringWrapper value) { - writeLatin1To(false, String.valueOf(value)); - } - - @Override - public final boolean needWriteClassName() { - return false; - } - - @Override - public final void writeClassName(String clazz) { - } - - @Override - public final int writeObjectB(Object obj) { - super.writeObjectB(obj); - writeTo('{'); - return -1; - } - - @Override - public final void writeObjectE(Object obj) { - writeTo('}'); - } - - @Override - public final void writeNull() { - writeTo('n', 'u', 'l', 'l'); - } - - @Override - public final int writeArrayB(int size, Encodeable arrayEncoder, Encodeable componentEncoder, Object obj) { - writeTo('['); - return -1; - } - - @Override - public final void writeArrayMark() { - writeTo(','); - } - - @Override - public final void writeArrayE() { - writeTo(']'); - } - - @Override - public final int writeMapB(int size, Encodeable keyEncoder, Encodeable valueEncoder, Object obj) { - writeTo('{'); - return -1; - } - - @Override - public final void writeMapMark() { - writeTo(':'); - } - - @Override - public final void writeMapE() { - writeTo('}'); - } - - final static char[] DigitTens = { - '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', - '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', - '2', '2', '2', '2', '2', '2', '2', '2', '2', '2', - '3', '3', '3', '3', '3', '3', '3', '3', '3', '3', - '4', '4', '4', '4', '4', '4', '4', '4', '4', '4', - '5', '5', '5', '5', '5', '5', '5', '5', '5', '5', - '6', '6', '6', '6', '6', '6', '6', '6', '6', '6', - '7', '7', '7', '7', '7', '7', '7', '7', '7', '7', - '8', '8', '8', '8', '8', '8', '8', '8', '8', '8', - '9', '9', '9', '9', '9', '9', '9', '9', '9', '9' - }; - - final static char[] DigitOnes = { - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' - }; - - final static char[] digits = { - '0', '1', '2', '3', '4', '5', - '6', '7', '8', '9', 'a', 'b', - 'c', 'd', 'e', 'f', 'g', 'h', - 'i', 'j', 'k', 'l', 'm', 'n', - 'o', 'p', 'q', 'r', 's', 't', - 'u', 'v', 'w', 'x', 'y', 'z' - }; - - final static int[] sizeTable = {9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999, Integer.MAX_VALUE}; -} +/* + * 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.convert.json; + +import java.lang.reflect.Type; +import org.redkale.convert.*; +import org.redkale.util.*; + +/** + * + * writeTo绯诲垪鐨勬柟娉曡緭鍑虹殑瀛楃涓嶈兘鍚壒娈婂瓧绗 + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public abstract class JsonWriter extends Writer { + + protected static final int defaultSize = Integer.getInteger("redkale.convert.json.writer.buffer.defsize", Integer.getInteger("redkale.convert.writer.buffer.defsize", 1024)); + + protected boolean tiny; + + @Override + public boolean tiny() { + return tiny; + } + + public JsonWriter tiny(boolean tiny) { + this.tiny = tiny; + return this; + } + + public boolean isExtFuncEmpty() { + return this.objExtFunc == null && this.objFieldFunc == null; + } + + //----------------------------------------------------------------------- + public abstract void writeTo(final char ch); //鍙兘鏄 0 - 127 鐨勫瓧绗 + + public abstract void writeTo(final char[] chs, final int start, final int len); //鍙兘鏄 0 - 127 鐨勫瓧绗 + + public abstract void writeTo(final byte ch); //鍙兘鏄 0 - 127 鐨勫瓧绗 + + public abstract void writeTo(final byte[] chs, final int start, final int len); //鍙兘鏄 0 - 127 鐨勫瓧绗 + + /** + * 娉ㄦ剰锛 璇tring鍊间笉鑳戒负null涓斾笉浼氳繘琛岃浆涔夛紝 鍙敤浜庝笉鍚渶瑕佽浆涔夊瓧绗︾殑瀛楃涓诧紝渚嬪enum銆乨ouble銆丅igInteger杞崲鐨凷tring + * + * @param quote 鏄惁鍔犲弻寮曞彿 + * @param value 闈瀗ull涓斾笉鍚渶瑕佽浆涔夌殑瀛楃鐨凷tring鍊 + */ + public abstract void writeLatin1To(final boolean quote, final String value); + + public abstract void writeFieldShortValue(final byte[] fieldBytes, final short value); + + public abstract void writeFieldIntValue(final byte[] fieldBytes, final int value); + + public abstract void writeFieldLongValue(final byte[] fieldBytes, final long value); + + public abstract void writeFieldLatin1Value(final byte[] fieldBytes, final String value); + + public abstract void writeLastFieldShortValue(final byte[] fieldBytes, final short value); + + public abstract void writeLastFieldIntValue(final byte[] fieldBytes, final int value); + + public abstract void writeLastFieldLongValue(final byte[] fieldBytes, final long value); + + public abstract void writeLastFieldLatin1Value(final byte[] fieldBytes, final String value); + + //firstFieldBytes 蹇呴』甯寮澶 + public abstract void writeObjectByOnlyOneLatin1FieldValue(final byte[] firstFieldBytes, final String value); + + //firstFieldBytes 蹇呴』甯寮澶, lastFieldBytes蹇呴』,寮澶 + public abstract void writeObjectByOnlyTwoIntFieldValue(final byte[] firstFieldBytes, final int value1, final byte[] lastFieldBytes, final int value2); + + @Override + public abstract void writeBoolean(boolean value); + + @Override + public abstract void writeInt(int value); + + @Override + public abstract void writeLong(long value); + + @Override + public abstract void writeString(String value); + + @Override //鍙璁窲sonBytesWriter閲嶅啓姝ゆ柟娉 + public void writeFieldName(EnMember member, String fieldName, Type fieldType, int fieldPos) { + if (this.comma) writeTo(','); + if (member != null) { + writeTo(member.getJsonFieldNameChars()); + } else { + writeLatin1To(true, fieldName); + writeTo(':'); + } + } + + @Override + public final void writeSmallString(String value) { + writeLatin1To(true, value); + } + + //---------------------------------------------------------------------------------------------- + public final void writeTo(final char... chs) { //鍙兘鏄 0 - 127 鐨勫瓧绗 + writeTo(chs, 0, chs.length); + } + + @Override + public final void writeByte(byte value) { + writeInt(value); + } + + public final void writeTo(final byte[] chs) { //鍙兘鏄 0 - 127 鐨勫瓧绗 + writeTo(chs, 0, chs.length); + } + + @Override + public final void writeByteArray(byte[] values) { + if (values == null) { + writeNull(); + return; + } + writeArrayB(values.length, null, null, values); + boolean flag = false; + for (byte v : values) { + if (flag) writeArrayMark(); + writeByte(v); + flag = true; + } + writeArrayE(); + } + + @Override + public final void writeChar(char value) { + writeInt(value); + } + + @Override + public final void writeShort(short value) { + writeInt(value); + } + + @Override + public final void writeFloat(float value) { + writeLatin1To(false, String.valueOf(value)); + } + + @Override + public final void writeDouble(double value) { + writeLatin1To(false, String.valueOf(value)); + } + + @Override + public final void writeWrapper(StringWrapper value) { + writeLatin1To(false, String.valueOf(value)); + } + + @Override + public final boolean needWriteClassName() { + return false; + } + + @Override + public final void writeClassName(String clazz) { + } + + @Override + public final int writeObjectB(Object obj) { + super.writeObjectB(obj); + writeTo('{'); + return -1; + } + + @Override + public final void writeObjectE(Object obj) { + writeTo('}'); + } + + @Override + public final void writeNull() { + writeTo('n', 'u', 'l', 'l'); + } + + @Override + public final int writeArrayB(int size, Encodeable arrayEncoder, Encodeable componentEncoder, Object obj) { + writeTo('['); + return -1; + } + + @Override + public final void writeArrayMark() { + writeTo(','); + } + + @Override + public final void writeArrayE() { + writeTo(']'); + } + + @Override + public final int writeMapB(int size, Encodeable keyEncoder, Encodeable valueEncoder, Object obj) { + writeTo('{'); + return -1; + } + + @Override + public final void writeMapMark() { + writeTo(':'); + } + + @Override + public final void writeMapE() { + writeTo('}'); + } + + final static char[] DigitTens = { + '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', + '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', + '2', '2', '2', '2', '2', '2', '2', '2', '2', '2', + '3', '3', '3', '3', '3', '3', '3', '3', '3', '3', + '4', '4', '4', '4', '4', '4', '4', '4', '4', '4', + '5', '5', '5', '5', '5', '5', '5', '5', '5', '5', + '6', '6', '6', '6', '6', '6', '6', '6', '6', '6', + '7', '7', '7', '7', '7', '7', '7', '7', '7', '7', + '8', '8', '8', '8', '8', '8', '8', '8', '8', '8', + '9', '9', '9', '9', '9', '9', '9', '9', '9', '9' + }; + + final static char[] DigitOnes = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' + }; + + final static char[] digits = { + '0', '1', '2', '3', '4', '5', + '6', '7', '8', '9', 'a', 'b', + 'c', 'd', 'e', 'f', 'g', 'h', + 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', + 'u', 'v', 'w', 'x', 'y', 'z' + }; + + final static int[] sizeTable = {9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999, Integer.MAX_VALUE}; +} diff --git a/src/main/java/org/redkale/convert/json/package-info.java b/src/main/java/org/redkale/convert/json/package-info.java index 2f27455b3..7e181f13b 100644 --- a/src/main/java/org/redkale/convert/json/package-info.java +++ b/src/main/java/org/redkale/convert/json/package-info.java @@ -1,4 +1,4 @@ -/** - * 鎻愪緵JSON鐨勫簭鍒楀寲鍜屽弽瑙f瀽鍔熻兘 - */ -package org.redkale.convert.json; +/** + * 鎻愪緵JSON鐨勫簭鍒楀寲鍜屽弽瑙f瀽鍔熻兘 + */ +package org.redkale.convert.json; diff --git a/src/main/java/org/redkale/convert/package-info.java b/src/main/java/org/redkale/convert/package-info.java index 2835d5ae3..72764d0e0 100644 --- a/src/main/java/org/redkale/convert/package-info.java +++ b/src/main/java/org/redkale/convert/package-info.java @@ -1,4 +1,4 @@ -/** - * 鎻愪緵鏁版嵁鐨勫簭鍒楀寲鍜屽弽瑙f瀽鍔熻兘 - */ -package org.redkale.convert; +/** + * 鎻愪緵鏁版嵁鐨勫簭鍒楀寲鍜屽弽瑙f瀽鍔熻兘 + */ +package org.redkale.convert; diff --git a/src/main/java/org/redkale/mq/HttpMessageClient.java b/src/main/java/org/redkale/mq/HttpMessageClient.java index 2a931ae5e..81a7c4b19 100644 --- a/src/main/java/org/redkale/mq/HttpMessageClient.java +++ b/src/main/java/org/redkale/mq/HttpMessageClient.java @@ -1,199 +1,199 @@ -/* - * 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.mq; - -import java.io.Serializable; -import java.lang.reflect.Type; -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.atomic.AtomicLong; -import java.util.logging.*; -import org.redkale.convert.json.JsonConvert; -import org.redkale.net.http.*; -import static org.redkale.mq.MessageRecord.CTYPE_HTTP_REQUEST; - -/** - * 涓嶄緷璧朚essageRecord鍒欏彲鍏煎RPC鏂瑰紡 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * - * @since 2.1.0 - */ -public class HttpMessageClient extends MessageClient { - - protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); - - protected HttpMessageClient(MessageAgent messageAgent) { - super(messageAgent); - if (messageAgent != null) { // //RPC鏂瑰紡涓嬫棤messageAgent - this.respTopic = messageAgent.generateHttpRespTopic(); - } - } - - //鏍煎紡: http.req.user - public String generateHttpReqTopic(String module) { - return MessageAgent.generateHttpReqTopic(module); - } - - //鏍煎紡: http.req.user-n10 - public String generateHttpReqTopic(String module, String resname) { - return MessageAgent.generateHttpReqTopic(module, resname); - } - - public String generateHttpReqTopic(HttpSimpleRequest request, String path) { - String module = request.getRequestURI(); - if (path != null && !path.isEmpty() && module.startsWith(path)) module = module.substring(path.length()); - module = module.substring(1); //鍘绘帀/ - module = module.substring(0, module.indexOf('/')); - Map headers = request.getHeaders(); - String resname = headers == null ? "" : headers.getOrDefault(Rest.REST_HEADER_RESOURCE_NAME, ""); - return MessageAgent.generateHttpReqTopic(module, resname); - } - - public final void produceMessage(HttpSimpleRequest request) { - produceMessage(generateHttpReqTopic(request, null), 0, null, request, null); - } - - public final void produceMessage(HttpSimpleRequest request, AtomicLong counter) { - produceMessage(generateHttpReqTopic(request, null), 0, null, request, counter); - } - - public final void produceMessage(Serializable userid, HttpSimpleRequest request) { - produceMessage(generateHttpReqTopic(request, null), userid, null, request, null); - } - - public final void produceMessage(Serializable userid, String groupid, HttpSimpleRequest request) { - produceMessage(generateHttpReqTopic(request, null), userid, groupid, request, null); - } - - public final void produceMessage(Serializable userid, String groupid, HttpSimpleRequest request, AtomicLong counter) { - produceMessage(generateHttpReqTopic(request, null), userid, groupid, request, counter); - } - - public final void produceMessage(String topic, HttpSimpleRequest request) { - produceMessage(topic, 0, null, request, null); - } - - public final void produceMessage(String topic, HttpSimpleRequest request, AtomicLong counter) { - produceMessage(topic, 0, null, request, counter); - } - - public final void produceMessage(String topic, Serializable userid, String groupid, HttpSimpleRequest request) { - produceMessage(topic, userid, groupid, request, null); - } - - public final void broadcastMessage(HttpSimpleRequest request) { - broadcastMessage(generateHttpReqTopic(request, null), 0, null, request, null); - } - - public final void broadcastMessage(HttpSimpleRequest request, AtomicLong counter) { - broadcastMessage(generateHttpReqTopic(request, null), 0, null, request, counter); - } - - public final void broadcastMessage(Serializable userid, HttpSimpleRequest request) { - broadcastMessage(generateHttpReqTopic(request, null), userid, null, request, null); - } - - public final void broadcastMessage(Serializable userid, String groupid, HttpSimpleRequest request) { - broadcastMessage(generateHttpReqTopic(request, null), userid, groupid, request, null); - } - - public final void broadcastMessage(Serializable userid, String groupid, HttpSimpleRequest request, AtomicLong counter) { - broadcastMessage(generateHttpReqTopic(request, null), userid, groupid, request, counter); - } - - public final void broadcastMessage(String topic, HttpSimpleRequest request) { - broadcastMessage(topic, 0, null, request, null); - } - - public final void broadcastMessage(String topic, HttpSimpleRequest request, AtomicLong counter) { - broadcastMessage(topic, 0, null, request, counter); - } - - public final void broadcastMessage(String topic, Serializable userid, String groupid, HttpSimpleRequest request) { - broadcastMessage(topic, userid, groupid, request, null); - } - - public CompletableFuture sendMessage(HttpSimpleRequest request, Type type) { - return sendMessage(generateHttpReqTopic(request, null), 0, null, request, null).thenApply((HttpResult httbs) -> { - if (httbs == null || httbs.getResult() == null) return null; - return JsonConvert.root().convertFrom(type, httbs.getResult()); - }); - } - - public CompletableFuture sendMessage(Serializable userid, HttpSimpleRequest request, Type type) { - return sendMessage(generateHttpReqTopic(request, null), userid, null, request, null).thenApply((HttpResult httbs) -> { - if (httbs == null || httbs.getResult() == null) return null; - return JsonConvert.root().convertFrom(type, httbs.getResult()); - }); - } - - public CompletableFuture sendMessage(Serializable userid, String groupid, HttpSimpleRequest request, Type type) { - return sendMessage(generateHttpReqTopic(request, null), userid, groupid, request, null).thenApply((HttpResult httbs) -> { - if (httbs == null || httbs.getResult() == null) return null; - return JsonConvert.root().convertFrom(type, httbs.getResult()); - }); - } - - public final CompletableFuture> sendMessage(HttpSimpleRequest request) { - return sendMessage(generateHttpReqTopic(request, null), 0, null, request, null); - } - - public final CompletableFuture> sendMessage(HttpSimpleRequest request, AtomicLong counter) { - return sendMessage(generateHttpReqTopic(request, null), 0, null, request, counter); - } - - public final CompletableFuture> sendMessage(Serializable userid, HttpSimpleRequest request) { - return sendMessage(generateHttpReqTopic(request, null), userid, null, request, null); - } - - public final CompletableFuture> sendMessage(Serializable userid, String groupid, HttpSimpleRequest request) { - return sendMessage(generateHttpReqTopic(request, null), userid, groupid, request, null); - } - - public final CompletableFuture> sendMessage(Serializable userid, String groupid, HttpSimpleRequest request, AtomicLong counter) { - return sendMessage(generateHttpReqTopic(request, null), userid, groupid, request, counter); - } - - public final CompletableFuture> sendMessage(String topic, HttpSimpleRequest request) { - return sendMessage(topic, 0, null, request, null); - } - - public final CompletableFuture> sendMessage(String topic, HttpSimpleRequest request, AtomicLong counter) { - return sendMessage(topic, 0, null, request, counter); - } - - public final CompletableFuture> sendMessage(String topic, Serializable userid, String groupid, HttpSimpleRequest request) { - return sendMessage(topic, userid, null, request, (AtomicLong) null); - } - - public CompletableFuture> sendMessage(String topic, Serializable userid, String groupid, HttpSimpleRequest request, AtomicLong counter) { - MessageRecord message = createMessageRecord(CTYPE_HTTP_REQUEST, topic, null, HttpSimpleRequestCoder.getInstance().encode(request)); - message.userid(userid).groupid(groupid); - //if (finest) logger.log(Level.FINEST, "HttpMessageClient.sendMessage: " + message); - return sendMessage(message, true, counter).thenApply(r -> r.decodeContent(HttpResultCoder.getInstance())); - } - - public void broadcastMessage(String topic, Serializable userid, String groupid, HttpSimpleRequest request, AtomicLong counter) { - MessageRecord message = createMessageRecord(CTYPE_HTTP_REQUEST, topic, null, HttpSimpleRequestCoder.getInstance().encode(request)); - message.userid(userid).groupid(groupid); - sendMessage(message, false, counter); - } - - public void produceMessage(String topic, Serializable userid, String groupid, HttpSimpleRequest request, AtomicLong counter) { - MessageRecord message = createMessageRecord(CTYPE_HTTP_REQUEST, topic, null, HttpSimpleRequestCoder.getInstance().encode(request)); - message.userid(userid).groupid(groupid); - sendMessage(message, false, counter); - } - - @Override - protected MessageProducers getProducer() { - return messageAgent.getHttpProducer(); - } -} +/* + * 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.mq; + +import java.io.Serializable; +import java.lang.reflect.Type; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicLong; +import java.util.logging.*; +import org.redkale.convert.json.JsonConvert; +import org.redkale.net.http.*; +import static org.redkale.mq.MessageRecord.CTYPE_HTTP_REQUEST; + +/** + * 涓嶄緷璧朚essageRecord鍒欏彲鍏煎RPC鏂瑰紡 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.1.0 + */ +public class HttpMessageClient extends MessageClient { + + protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); + + protected HttpMessageClient(MessageAgent messageAgent) { + super(messageAgent); + if (messageAgent != null) { // //RPC鏂瑰紡涓嬫棤messageAgent + this.respTopic = messageAgent.generateHttpRespTopic(); + } + } + + //鏍煎紡: http.req.user + public String generateHttpReqTopic(String module) { + return MessageAgent.generateHttpReqTopic(module); + } + + //鏍煎紡: http.req.user-n10 + public String generateHttpReqTopic(String module, String resname) { + return MessageAgent.generateHttpReqTopic(module, resname); + } + + public String generateHttpReqTopic(HttpSimpleRequest request, String path) { + String module = request.getRequestURI(); + if (path != null && !path.isEmpty() && module.startsWith(path)) module = module.substring(path.length()); + module = module.substring(1); //鍘绘帀/ + module = module.substring(0, module.indexOf('/')); + Map headers = request.getHeaders(); + String resname = headers == null ? "" : headers.getOrDefault(Rest.REST_HEADER_RESOURCE_NAME, ""); + return MessageAgent.generateHttpReqTopic(module, resname); + } + + public final void produceMessage(HttpSimpleRequest request) { + produceMessage(generateHttpReqTopic(request, null), 0, null, request, null); + } + + public final void produceMessage(HttpSimpleRequest request, AtomicLong counter) { + produceMessage(generateHttpReqTopic(request, null), 0, null, request, counter); + } + + public final void produceMessage(Serializable userid, HttpSimpleRequest request) { + produceMessage(generateHttpReqTopic(request, null), userid, null, request, null); + } + + public final void produceMessage(Serializable userid, String groupid, HttpSimpleRequest request) { + produceMessage(generateHttpReqTopic(request, null), userid, groupid, request, null); + } + + public final void produceMessage(Serializable userid, String groupid, HttpSimpleRequest request, AtomicLong counter) { + produceMessage(generateHttpReqTopic(request, null), userid, groupid, request, counter); + } + + public final void produceMessage(String topic, HttpSimpleRequest request) { + produceMessage(topic, 0, null, request, null); + } + + public final void produceMessage(String topic, HttpSimpleRequest request, AtomicLong counter) { + produceMessage(topic, 0, null, request, counter); + } + + public final void produceMessage(String topic, Serializable userid, String groupid, HttpSimpleRequest request) { + produceMessage(topic, userid, groupid, request, null); + } + + public final void broadcastMessage(HttpSimpleRequest request) { + broadcastMessage(generateHttpReqTopic(request, null), 0, null, request, null); + } + + public final void broadcastMessage(HttpSimpleRequest request, AtomicLong counter) { + broadcastMessage(generateHttpReqTopic(request, null), 0, null, request, counter); + } + + public final void broadcastMessage(Serializable userid, HttpSimpleRequest request) { + broadcastMessage(generateHttpReqTopic(request, null), userid, null, request, null); + } + + public final void broadcastMessage(Serializable userid, String groupid, HttpSimpleRequest request) { + broadcastMessage(generateHttpReqTopic(request, null), userid, groupid, request, null); + } + + public final void broadcastMessage(Serializable userid, String groupid, HttpSimpleRequest request, AtomicLong counter) { + broadcastMessage(generateHttpReqTopic(request, null), userid, groupid, request, counter); + } + + public final void broadcastMessage(String topic, HttpSimpleRequest request) { + broadcastMessage(topic, 0, null, request, null); + } + + public final void broadcastMessage(String topic, HttpSimpleRequest request, AtomicLong counter) { + broadcastMessage(topic, 0, null, request, counter); + } + + public final void broadcastMessage(String topic, Serializable userid, String groupid, HttpSimpleRequest request) { + broadcastMessage(topic, userid, groupid, request, null); + } + + public CompletableFuture sendMessage(HttpSimpleRequest request, Type type) { + return sendMessage(generateHttpReqTopic(request, null), 0, null, request, null).thenApply((HttpResult httbs) -> { + if (httbs == null || httbs.getResult() == null) return null; + return JsonConvert.root().convertFrom(type, httbs.getResult()); + }); + } + + public CompletableFuture sendMessage(Serializable userid, HttpSimpleRequest request, Type type) { + return sendMessage(generateHttpReqTopic(request, null), userid, null, request, null).thenApply((HttpResult httbs) -> { + if (httbs == null || httbs.getResult() == null) return null; + return JsonConvert.root().convertFrom(type, httbs.getResult()); + }); + } + + public CompletableFuture sendMessage(Serializable userid, String groupid, HttpSimpleRequest request, Type type) { + return sendMessage(generateHttpReqTopic(request, null), userid, groupid, request, null).thenApply((HttpResult httbs) -> { + if (httbs == null || httbs.getResult() == null) return null; + return JsonConvert.root().convertFrom(type, httbs.getResult()); + }); + } + + public final CompletableFuture> sendMessage(HttpSimpleRequest request) { + return sendMessage(generateHttpReqTopic(request, null), 0, null, request, null); + } + + public final CompletableFuture> sendMessage(HttpSimpleRequest request, AtomicLong counter) { + return sendMessage(generateHttpReqTopic(request, null), 0, null, request, counter); + } + + public final CompletableFuture> sendMessage(Serializable userid, HttpSimpleRequest request) { + return sendMessage(generateHttpReqTopic(request, null), userid, null, request, null); + } + + public final CompletableFuture> sendMessage(Serializable userid, String groupid, HttpSimpleRequest request) { + return sendMessage(generateHttpReqTopic(request, null), userid, groupid, request, null); + } + + public final CompletableFuture> sendMessage(Serializable userid, String groupid, HttpSimpleRequest request, AtomicLong counter) { + return sendMessage(generateHttpReqTopic(request, null), userid, groupid, request, counter); + } + + public final CompletableFuture> sendMessage(String topic, HttpSimpleRequest request) { + return sendMessage(topic, 0, null, request, null); + } + + public final CompletableFuture> sendMessage(String topic, HttpSimpleRequest request, AtomicLong counter) { + return sendMessage(topic, 0, null, request, counter); + } + + public final CompletableFuture> sendMessage(String topic, Serializable userid, String groupid, HttpSimpleRequest request) { + return sendMessage(topic, userid, null, request, (AtomicLong) null); + } + + public CompletableFuture> sendMessage(String topic, Serializable userid, String groupid, HttpSimpleRequest request, AtomicLong counter) { + MessageRecord message = createMessageRecord(CTYPE_HTTP_REQUEST, topic, null, HttpSimpleRequestCoder.getInstance().encode(request)); + message.userid(userid).groupid(groupid); + //if (finest) logger.log(Level.FINEST, "HttpMessageClient.sendMessage: " + message); + return sendMessage(message, true, counter).thenApply(r -> r.decodeContent(HttpResultCoder.getInstance())); + } + + public void broadcastMessage(String topic, Serializable userid, String groupid, HttpSimpleRequest request, AtomicLong counter) { + MessageRecord message = createMessageRecord(CTYPE_HTTP_REQUEST, topic, null, HttpSimpleRequestCoder.getInstance().encode(request)); + message.userid(userid).groupid(groupid); + sendMessage(message, false, counter); + } + + public void produceMessage(String topic, Serializable userid, String groupid, HttpSimpleRequest request, AtomicLong counter) { + MessageRecord message = createMessageRecord(CTYPE_HTTP_REQUEST, topic, null, HttpSimpleRequestCoder.getInstance().encode(request)); + message.userid(userid).groupid(groupid); + sendMessage(message, false, counter); + } + + @Override + protected MessageProducers getProducer() { + return messageAgent.getHttpProducer(); + } +} diff --git a/src/main/java/org/redkale/mq/HttpMessageClusterClient.java b/src/main/java/org/redkale/mq/HttpMessageClusterClient.java index 9e1d5a7a9..d87bbc5ff 100644 --- a/src/main/java/org/redkale/mq/HttpMessageClusterClient.java +++ b/src/main/java/org/redkale/mq/HttpMessageClusterClient.java @@ -1,276 +1,276 @@ -/* - * 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.mq; - -import java.io.Serializable; -import java.net.*; -import java.nio.charset.StandardCharsets; -import java.util.*; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.atomic.*; -import java.util.logging.Level; -import javax.annotation.Resource; -import org.redkale.cluster.ClusterAgent; -import org.redkale.net.http.*; -import org.redkale.util.Utility; - -/** - * 娌℃湁閰嶇疆MQ鐨勬儏鍐典笅渚濊禆ClusterAgent瀹炵幇鐨勯粯璁ttpMessageClient瀹炰緥 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * - * @since 2.1.0 - */ -public class HttpMessageClusterClient extends HttpMessageClient { - - //jdk.internal.net.http.common.Utils.DISALLOWED_HEADERS_SET - private static final Set DISALLOWED_HEADERS_SET = Utility.ofSet("connection", "content-length", - "date", "expect", "from", "host", "origin", "referer", "upgrade", "via", "warning"); - - protected ClusterAgent clusterAgent; - - @Resource(name = "cluster.httpClient") - protected HttpClient httpClient; - - //protected java.net.http.HttpClient httpClient; - public HttpMessageClusterClient(ClusterAgent clusterAgent) { - super(null); - Objects.requireNonNull(clusterAgent); - this.clusterAgent = clusterAgent; - //this.httpClient = java.net.http.HttpClient.newHttpClient(); - } - - @Override - public CompletableFuture> sendMessage(String topic, Serializable userid, String groupid, HttpSimpleRequest request, AtomicLong counter) { - return httpAsync(userid, request); - } - - @Override - public void produceMessage(String topic, Serializable userid, String groupid, HttpSimpleRequest request, AtomicLong counter) { - httpAsync(userid, request); - } - - @Override - public void broadcastMessage(String topic, Serializable userid, String groupid, HttpSimpleRequest request, AtomicLong counter) { - mqtpAsync(userid, request); - } - - private CompletableFuture> mqtpAsync(Serializable userid, HttpSimpleRequest req) { - final boolean finest = logger.isLoggable(Level.FINEST); - String module = req.getRequestURI(); - module = module.substring(1); //鍘绘帀/ - module = module.substring(0, module.indexOf('/')); - Map headers = req.getHeaders(); - String resname = headers == null ? "" : headers.getOrDefault(Rest.REST_HEADER_RESOURCE_NAME, ""); - return clusterAgent.queryMqtpAddress("mqtp", module, resname).thenCompose(addrmap -> { - if (addrmap == null || addrmap.isEmpty()) return new HttpResult().status(404).toAnyFuture(); - final Map clientHeaders = new LinkedHashMap<>(); - byte[] clientBody = null; - if (req.isRpc()) clientHeaders.put(Rest.REST_HEADER_RPC_NAME, "true"); - if (req.isFrombody()) clientHeaders.put(Rest.REST_HEADER_PARAM_FROM_BODY, "true"); - if (req.getReqConvertType() != null) clientHeaders.put(Rest.REST_HEADER_REQ_CONVERT_TYPE, req.getReqConvertType().toString()); - if (req.getRespConvertType() != null) clientHeaders.put(Rest.REST_HEADER_RESP_CONVERT_TYPE, req.getRespConvertType().toString()); - if (userid != null) clientHeaders.put(Rest.REST_HEADER_CURRUSERID_NAME, "" + userid); - if (headers != null) headers.forEach((n, v) -> { - if (!DISALLOWED_HEADERS_SET.contains(n.toLowerCase())) clientHeaders.put(n, v); - }); - clientHeaders.put("Content-Type", "x-www-form-urlencoded"); - if (req.getBody() != null && req.getBody().length > 0) { - String paramstr = req.getParametersToString(); - if (paramstr != null) { - if (req.getRequestURI().indexOf('?') > 0) { - req.setRequestURI(req.getRequestURI() + "&" + paramstr); - } else { - req.setRequestURI(req.getRequestURI() + "?" + paramstr); - } - } - clientBody = req.getBody(); - } else { - String paramstr = req.getParametersToString(); - if (paramstr != null) clientBody = paramstr.getBytes(StandardCharsets.UTF_8); - } - List futures = new ArrayList<>(); - for (Map.Entry> en : addrmap.entrySet()) { - String realmodule = en.getKey(); - Collection addrs = en.getValue(); - if (addrs == null || addrs.isEmpty()) continue; - String suburi = req.getRequestURI(); - suburi = suburi.substring(1); //璺宠繃 / - suburi = "/" + realmodule + suburi.substring(suburi.indexOf('/')); - futures.add(forEachCollectionFuture(finest, userid, req, (req.getPath() != null && !req.getPath().isEmpty() ? req.getPath() : "") + suburi, clientHeaders, clientBody, addrs.iterator())); - } - if (futures.isEmpty()) return CompletableFuture.completedFuture(null); - return CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()])).thenApply(v -> null); - }); - } - - private CompletableFuture> httpAsync(Serializable userid, HttpSimpleRequest req) { - final boolean finest = logger.isLoggable(Level.FINEST); - String module = req.getRequestURI(); - module = module.substring(1); //鍘绘帀/ - module = module.substring(0, module.indexOf('/')); - Map headers = req.getHeaders(); - String resname = headers == null ? "" : headers.getOrDefault(Rest.REST_HEADER_RESOURCE_NAME, ""); - return clusterAgent.queryHttpAddress("http", module, resname).thenCompose(addrs -> { - if (addrs == null || addrs.isEmpty()) return new HttpResult().status(404).toAnyFuture(); - final Map clientHeaders = new LinkedHashMap<>(); - byte[] clientBody = null; - if (req.isRpc()) clientHeaders.put(Rest.REST_HEADER_RPC_NAME, "true"); - if (req.isFrombody()) clientHeaders.put(Rest.REST_HEADER_PARAM_FROM_BODY, "true"); - if (req.getReqConvertType() != null) clientHeaders.put(Rest.REST_HEADER_REQ_CONVERT_TYPE, req.getReqConvertType().toString()); - if (req.getRespConvertType() != null) clientHeaders.put(Rest.REST_HEADER_RESP_CONVERT_TYPE, req.getRespConvertType().toString()); - if (userid != null) clientHeaders.put(Rest.REST_HEADER_CURRUSERID_NAME, "" + userid); - if (headers != null) headers.forEach((n, v) -> { - if (!DISALLOWED_HEADERS_SET.contains(n.toLowerCase())) clientHeaders.put(n, v); - }); - clientHeaders.put("Content-Type", "x-www-form-urlencoded"); - if (req.getBody() != null && req.getBody().length > 0) { - String paramstr = req.getParametersToString(); - if (paramstr != null) { - if (req.getRequestURI().indexOf('?') > 0) { - req.setRequestURI(req.getRequestURI() + "&" + paramstr); - } else { - req.setRequestURI(req.getRequestURI() + "?" + paramstr); - } - } - clientBody = req.getBody(); - } else { - String paramstr = req.getParametersToString(); - if (paramstr != null) clientBody = paramstr.getBytes(StandardCharsets.UTF_8); - } - return forEachCollectionFuture(finest, userid, req, (req.getPath() != null && !req.getPath().isEmpty() ? req.getPath() : "") + req.getRequestURI(), clientHeaders, clientBody, addrs.iterator()); - }); - } - - private CompletableFuture> forEachCollectionFuture(boolean finest, Serializable userid, HttpSimpleRequest req, String requesturi, final Map clientHeaders, byte[] clientBody, Iterator it) { - if (!it.hasNext()) return CompletableFuture.completedFuture(null); - InetSocketAddress addr = it.next(); - String url = "http://" + addr.getHostString() + ":" + addr.getPort() + requesturi; - return httpClient.postAsync(url, clientHeaders, clientBody); - } - -// private CompletableFuture> mqtpAsync(Serializable userid, HttpSimpleRequest req) { -// final boolean finest = logger.isLoggable(Level.FINEST); -// String module = req.getRequestURI(); -// module = module.substring(1); //鍘绘帀/ -// module = module.substring(0, module.indexOf('/')); -// Map headers = req.getHeaders(); -// String resname = headers == null ? "" : headers.getOrDefault(Rest.REST_HEADER_RESOURCE_NAME, ""); -// return clusterAgent.queryMqtpAddress("mqtp", module, resname).thenCompose(addrmap -> { -// if (addrmap == null || addrmap.isEmpty()) return new HttpResult().status(404).toAnyFuture(); -// java.net.http.HttpRequest.Builder builder = java.net.http.HttpRequest.newBuilder().timeout(Duration.ofMillis(30000)); -// if (req.isRpc()) builder.header(Rest.REST_HEADER_RPC_NAME, "true"); -// if (req.isFrombody()) builder.header(Rest.REST_HEADER_PARAM_FROM_BODY, "true"); -// if (req.getReqConvertType() != null) builder.header(Rest.REST_HEADER_REQ_CONVERT_TYPE, req.getReqConvertType().toString()); -// if (req.getRespConvertType() != null) builder.header(Rest.REST_HEADER_RESP_CONVERT_TYPE, req.getRespConvertType().toString()); -// if (userid != 0) builder.header(Rest.REST_HEADER_CURRUSERID_NAME, "" + userid); -// if (headers != null) headers.forEach((n, v) -> { -// if (!DISALLOWED_HEADERS_SET.contains(n.toLowerCase())) builder.header(n, v); -// }); -// builder.header("Content-Type", "x-www-form-urlencoded"); -// if (req.getBody() != null && req.getBody().length > 0) { -// String paramstr = req.getParametersToString(); -// if (paramstr != null) { -// if (req.getRequestURI().indexOf('?') > 0) { -// req.setRequestURI(req.getRequestURI() + "&" + paramstr); -// } else { -// req.setRequestURI(req.getRequestURI() + "?" + paramstr); -// } -// } -// builder.POST(java.net.http.HttpRequest.BodyPublishers.ofByteArray(req.getBody())); -// } else { -// String paramstr = req.getParametersToString(); -// if (paramstr != null) builder.POST(java.net.http.HttpRequest.BodyPublishers.ofString(paramstr)); -// } -// List futures = new ArrayList<>(); -// for (Map.Entry> en : addrmap.entrySet()) { -// String realmodule = en.getKey(); -// Collection addrs = en.getValue(); -// if (addrs == null || addrs.isEmpty()) continue; -// String suburi = req.getRequestURI(); -// suburi = suburi.substring(1); //璺宠繃 / -// suburi = "/" + realmodule + suburi.substring(suburi.indexOf('/')); -// futures.add(forEachCollectionFuture(finest, userid, req, (req.getPath() != null && !req.getPath().isEmpty() ? req.getPath() : "") + suburi, builder, addrs.iterator())); -// } -// if (futures.isEmpty()) return CompletableFuture.completedFuture(null); -// return CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()])).thenApply(v -> null); -// }); -// } -// -// private CompletableFuture> httpAsync(Serializable userid, HttpSimpleRequest req) { -// final boolean finest = logger.isLoggable(Level.FINEST); -// String module = req.getRequestURI(); -// module = module.substring(1); //鍘绘帀/ -// module = module.substring(0, module.indexOf('/')); -// Map headers = req.getHeaders(); -// String resname = headers == null ? "" : headers.getOrDefault(Rest.REST_HEADER_RESOURCE_NAME, ""); -// return clusterAgent.queryHttpAddress("http", module, resname).thenCompose(addrs -> { -// if (addrs == null || addrs.isEmpty()) return new HttpResult().status(404).toAnyFuture(); -// java.net.http.HttpRequest.Builder builder = java.net.http.HttpRequest.newBuilder().timeout(Duration.ofMillis(30000)); -// if (req.isRpc()) builder.header(Rest.REST_HEADER_RPC_NAME, "true"); -// if (req.isFrombody()) builder.header(Rest.REST_HEADER_PARAM_FROM_BODY, "true"); -// if (req.getReqConvertType() != null) builder.header(Rest.REST_HEADER_REQ_CONVERT_TYPE, req.getReqConvertType().toString()); -// if (req.getRespConvertType() != null) builder.header(Rest.REST_HEADER_RESP_CONVERT_TYPE, req.getRespConvertType().toString()); -// if (userid != 0) builder.header(Rest.REST_HEADER_CURRUSERID_NAME, "" + userid); -// if (headers != null) headers.forEach((n, v) -> { -// if (!DISALLOWED_HEADERS_SET.contains(n.toLowerCase())) builder.header(n, v); -// }); -// builder.header("Content-Type", "x-www-form-urlencoded"); -// if (req.getBody() != null && req.getBody().length > 0) { -// String paramstr = req.getParametersToString(); -// if (paramstr != null) { -// if (req.getRequestURI().indexOf('?') > 0) { -// req.setRequestURI(req.getRequestURI() + "&" + paramstr); -// } else { -// req.setRequestURI(req.getRequestURI() + "?" + paramstr); -// } -// } -// builder.POST(java.net.http.HttpRequest.BodyPublishers.ofByteArray(req.getBody())); -// } else { -// String paramstr = req.getParametersToString(); -// if (paramstr != null) builder.POST(java.net.http.HttpRequest.BodyPublishers.ofString(paramstr)); -// } -// return forEachCollectionFuture(finest, userid, req, (req.getPath() != null && !req.getPath().isEmpty() ? req.getPath() : "") + req.getRequestURI(), builder, addrs.iterator()); -// }); -// } -// -// private CompletableFuture> forEachCollectionFuture(boolean finest, Serializable userid, HttpSimpleRequest req, String requesturi, java.net.http.HttpRequest.Builder builder, Iterator it) { -// if (!it.hasNext()) return CompletableFuture.completedFuture(null); -// InetSocketAddress addr = it.next(); -// String url = "http://" + addr.getHostString() + ":" + addr.getPort() + requesturi; -// return httpClient.sendAsync(builder.copy().uri(URI.create(url)).build(), java.net.http.HttpResponse.BodyHandlers.ofByteArray()).thenCompose(resp -> { -// if (resp.statusCode() != 200) return forEachCollectionFuture(finest, userid, req, requesturi, builder, it); -// HttpResult rs = new HttpResult(); -// java.net.http.HttpHeaders hs = resp.headers(); -// if (hs != null) { -// Map> hm = hs.map(); -// if (hm != null) { -// for (Map.Entry> en : hm.entrySet()) { -// if ("date".equals(en.getKey()) || "content-type".equals(en.getKey()) -// || "server".equals(en.getKey()) || "connection".equals(en.getKey())) continue; -// List val = en.getValue(); -// if (val != null && val.size() == 1) { -// rs.header(en.getKey(), val.get(0)); -// } -// } -// } -// } -// rs.setResult(resp.body()); -// if (finest) { -// StringBuilder sb = new StringBuilder(); -// Map params = req.getParams(); -// if (params != null && !params.isEmpty()) { -// params.forEach((n, v) -> sb.append('&').append(n).append('=').append(v)); -// } -// logger.log(Level.FINEST, url + "?userid=" + userid + sb + ", result = " + new String(resp.body(), StandardCharsets.UTF_8)); -// } -// return CompletableFuture.completedFuture(rs); -// }); -// } -} +/* + * 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.mq; + +import java.io.Serializable; +import java.net.*; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.*; +import java.util.logging.Level; +import javax.annotation.Resource; +import org.redkale.cluster.ClusterAgent; +import org.redkale.net.http.*; +import org.redkale.util.Utility; + +/** + * 娌℃湁閰嶇疆MQ鐨勬儏鍐典笅渚濊禆ClusterAgent瀹炵幇鐨勯粯璁ttpMessageClient瀹炰緥 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.1.0 + */ +public class HttpMessageClusterClient extends HttpMessageClient { + + //jdk.internal.net.http.common.Utils.DISALLOWED_HEADERS_SET + private static final Set DISALLOWED_HEADERS_SET = Utility.ofSet("connection", "content-length", + "date", "expect", "from", "host", "origin", "referer", "upgrade", "via", "warning"); + + protected ClusterAgent clusterAgent; + + @Resource(name = "cluster.httpClient") + protected HttpClient httpClient; + + //protected java.net.http.HttpClient httpClient; + public HttpMessageClusterClient(ClusterAgent clusterAgent) { + super(null); + Objects.requireNonNull(clusterAgent); + this.clusterAgent = clusterAgent; + //this.httpClient = java.net.http.HttpClient.newHttpClient(); + } + + @Override + public CompletableFuture> sendMessage(String topic, Serializable userid, String groupid, HttpSimpleRequest request, AtomicLong counter) { + return httpAsync(userid, request); + } + + @Override + public void produceMessage(String topic, Serializable userid, String groupid, HttpSimpleRequest request, AtomicLong counter) { + httpAsync(userid, request); + } + + @Override + public void broadcastMessage(String topic, Serializable userid, String groupid, HttpSimpleRequest request, AtomicLong counter) { + mqtpAsync(userid, request); + } + + private CompletableFuture> mqtpAsync(Serializable userid, HttpSimpleRequest req) { + final boolean finest = logger.isLoggable(Level.FINEST); + String module = req.getRequestURI(); + module = module.substring(1); //鍘绘帀/ + module = module.substring(0, module.indexOf('/')); + Map headers = req.getHeaders(); + String resname = headers == null ? "" : headers.getOrDefault(Rest.REST_HEADER_RESOURCE_NAME, ""); + return clusterAgent.queryMqtpAddress("mqtp", module, resname).thenCompose(addrmap -> { + if (addrmap == null || addrmap.isEmpty()) return new HttpResult().status(404).toAnyFuture(); + final Map clientHeaders = new LinkedHashMap<>(); + byte[] clientBody = null; + if (req.isRpc()) clientHeaders.put(Rest.REST_HEADER_RPC_NAME, "true"); + if (req.isFrombody()) clientHeaders.put(Rest.REST_HEADER_PARAM_FROM_BODY, "true"); + if (req.getReqConvertType() != null) clientHeaders.put(Rest.REST_HEADER_REQ_CONVERT_TYPE, req.getReqConvertType().toString()); + if (req.getRespConvertType() != null) clientHeaders.put(Rest.REST_HEADER_RESP_CONVERT_TYPE, req.getRespConvertType().toString()); + if (userid != null) clientHeaders.put(Rest.REST_HEADER_CURRUSERID_NAME, "" + userid); + if (headers != null) headers.forEach((n, v) -> { + if (!DISALLOWED_HEADERS_SET.contains(n.toLowerCase())) clientHeaders.put(n, v); + }); + clientHeaders.put("Content-Type", "x-www-form-urlencoded"); + if (req.getBody() != null && req.getBody().length > 0) { + String paramstr = req.getParametersToString(); + if (paramstr != null) { + if (req.getRequestURI().indexOf('?') > 0) { + req.setRequestURI(req.getRequestURI() + "&" + paramstr); + } else { + req.setRequestURI(req.getRequestURI() + "?" + paramstr); + } + } + clientBody = req.getBody(); + } else { + String paramstr = req.getParametersToString(); + if (paramstr != null) clientBody = paramstr.getBytes(StandardCharsets.UTF_8); + } + List futures = new ArrayList<>(); + for (Map.Entry> en : addrmap.entrySet()) { + String realmodule = en.getKey(); + Collection addrs = en.getValue(); + if (addrs == null || addrs.isEmpty()) continue; + String suburi = req.getRequestURI(); + suburi = suburi.substring(1); //璺宠繃 / + suburi = "/" + realmodule + suburi.substring(suburi.indexOf('/')); + futures.add(forEachCollectionFuture(finest, userid, req, (req.getPath() != null && !req.getPath().isEmpty() ? req.getPath() : "") + suburi, clientHeaders, clientBody, addrs.iterator())); + } + if (futures.isEmpty()) return CompletableFuture.completedFuture(null); + return CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()])).thenApply(v -> null); + }); + } + + private CompletableFuture> httpAsync(Serializable userid, HttpSimpleRequest req) { + final boolean finest = logger.isLoggable(Level.FINEST); + String module = req.getRequestURI(); + module = module.substring(1); //鍘绘帀/ + module = module.substring(0, module.indexOf('/')); + Map headers = req.getHeaders(); + String resname = headers == null ? "" : headers.getOrDefault(Rest.REST_HEADER_RESOURCE_NAME, ""); + return clusterAgent.queryHttpAddress("http", module, resname).thenCompose(addrs -> { + if (addrs == null || addrs.isEmpty()) return new HttpResult().status(404).toAnyFuture(); + final Map clientHeaders = new LinkedHashMap<>(); + byte[] clientBody = null; + if (req.isRpc()) clientHeaders.put(Rest.REST_HEADER_RPC_NAME, "true"); + if (req.isFrombody()) clientHeaders.put(Rest.REST_HEADER_PARAM_FROM_BODY, "true"); + if (req.getReqConvertType() != null) clientHeaders.put(Rest.REST_HEADER_REQ_CONVERT_TYPE, req.getReqConvertType().toString()); + if (req.getRespConvertType() != null) clientHeaders.put(Rest.REST_HEADER_RESP_CONVERT_TYPE, req.getRespConvertType().toString()); + if (userid != null) clientHeaders.put(Rest.REST_HEADER_CURRUSERID_NAME, "" + userid); + if (headers != null) headers.forEach((n, v) -> { + if (!DISALLOWED_HEADERS_SET.contains(n.toLowerCase())) clientHeaders.put(n, v); + }); + clientHeaders.put("Content-Type", "x-www-form-urlencoded"); + if (req.getBody() != null && req.getBody().length > 0) { + String paramstr = req.getParametersToString(); + if (paramstr != null) { + if (req.getRequestURI().indexOf('?') > 0) { + req.setRequestURI(req.getRequestURI() + "&" + paramstr); + } else { + req.setRequestURI(req.getRequestURI() + "?" + paramstr); + } + } + clientBody = req.getBody(); + } else { + String paramstr = req.getParametersToString(); + if (paramstr != null) clientBody = paramstr.getBytes(StandardCharsets.UTF_8); + } + return forEachCollectionFuture(finest, userid, req, (req.getPath() != null && !req.getPath().isEmpty() ? req.getPath() : "") + req.getRequestURI(), clientHeaders, clientBody, addrs.iterator()); + }); + } + + private CompletableFuture> forEachCollectionFuture(boolean finest, Serializable userid, HttpSimpleRequest req, String requesturi, final Map clientHeaders, byte[] clientBody, Iterator it) { + if (!it.hasNext()) return CompletableFuture.completedFuture(null); + InetSocketAddress addr = it.next(); + String url = "http://" + addr.getHostString() + ":" + addr.getPort() + requesturi; + return httpClient.postAsync(url, clientHeaders, clientBody); + } + +// private CompletableFuture> mqtpAsync(Serializable userid, HttpSimpleRequest req) { +// final boolean finest = logger.isLoggable(Level.FINEST); +// String module = req.getRequestURI(); +// module = module.substring(1); //鍘绘帀/ +// module = module.substring(0, module.indexOf('/')); +// Map headers = req.getHeaders(); +// String resname = headers == null ? "" : headers.getOrDefault(Rest.REST_HEADER_RESOURCE_NAME, ""); +// return clusterAgent.queryMqtpAddress("mqtp", module, resname).thenCompose(addrmap -> { +// if (addrmap == null || addrmap.isEmpty()) return new HttpResult().status(404).toAnyFuture(); +// java.net.http.HttpRequest.Builder builder = java.net.http.HttpRequest.newBuilder().timeout(Duration.ofMillis(30000)); +// if (req.isRpc()) builder.header(Rest.REST_HEADER_RPC_NAME, "true"); +// if (req.isFrombody()) builder.header(Rest.REST_HEADER_PARAM_FROM_BODY, "true"); +// if (req.getReqConvertType() != null) builder.header(Rest.REST_HEADER_REQ_CONVERT_TYPE, req.getReqConvertType().toString()); +// if (req.getRespConvertType() != null) builder.header(Rest.REST_HEADER_RESP_CONVERT_TYPE, req.getRespConvertType().toString()); +// if (userid != 0) builder.header(Rest.REST_HEADER_CURRUSERID_NAME, "" + userid); +// if (headers != null) headers.forEach((n, v) -> { +// if (!DISALLOWED_HEADERS_SET.contains(n.toLowerCase())) builder.header(n, v); +// }); +// builder.header("Content-Type", "x-www-form-urlencoded"); +// if (req.getBody() != null && req.getBody().length > 0) { +// String paramstr = req.getParametersToString(); +// if (paramstr != null) { +// if (req.getRequestURI().indexOf('?') > 0) { +// req.setRequestURI(req.getRequestURI() + "&" + paramstr); +// } else { +// req.setRequestURI(req.getRequestURI() + "?" + paramstr); +// } +// } +// builder.POST(java.net.http.HttpRequest.BodyPublishers.ofByteArray(req.getBody())); +// } else { +// String paramstr = req.getParametersToString(); +// if (paramstr != null) builder.POST(java.net.http.HttpRequest.BodyPublishers.ofString(paramstr)); +// } +// List futures = new ArrayList<>(); +// for (Map.Entry> en : addrmap.entrySet()) { +// String realmodule = en.getKey(); +// Collection addrs = en.getValue(); +// if (addrs == null || addrs.isEmpty()) continue; +// String suburi = req.getRequestURI(); +// suburi = suburi.substring(1); //璺宠繃 / +// suburi = "/" + realmodule + suburi.substring(suburi.indexOf('/')); +// futures.add(forEachCollectionFuture(finest, userid, req, (req.getPath() != null && !req.getPath().isEmpty() ? req.getPath() : "") + suburi, builder, addrs.iterator())); +// } +// if (futures.isEmpty()) return CompletableFuture.completedFuture(null); +// return CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()])).thenApply(v -> null); +// }); +// } +// +// private CompletableFuture> httpAsync(Serializable userid, HttpSimpleRequest req) { +// final boolean finest = logger.isLoggable(Level.FINEST); +// String module = req.getRequestURI(); +// module = module.substring(1); //鍘绘帀/ +// module = module.substring(0, module.indexOf('/')); +// Map headers = req.getHeaders(); +// String resname = headers == null ? "" : headers.getOrDefault(Rest.REST_HEADER_RESOURCE_NAME, ""); +// return clusterAgent.queryHttpAddress("http", module, resname).thenCompose(addrs -> { +// if (addrs == null || addrs.isEmpty()) return new HttpResult().status(404).toAnyFuture(); +// java.net.http.HttpRequest.Builder builder = java.net.http.HttpRequest.newBuilder().timeout(Duration.ofMillis(30000)); +// if (req.isRpc()) builder.header(Rest.REST_HEADER_RPC_NAME, "true"); +// if (req.isFrombody()) builder.header(Rest.REST_HEADER_PARAM_FROM_BODY, "true"); +// if (req.getReqConvertType() != null) builder.header(Rest.REST_HEADER_REQ_CONVERT_TYPE, req.getReqConvertType().toString()); +// if (req.getRespConvertType() != null) builder.header(Rest.REST_HEADER_RESP_CONVERT_TYPE, req.getRespConvertType().toString()); +// if (userid != 0) builder.header(Rest.REST_HEADER_CURRUSERID_NAME, "" + userid); +// if (headers != null) headers.forEach((n, v) -> { +// if (!DISALLOWED_HEADERS_SET.contains(n.toLowerCase())) builder.header(n, v); +// }); +// builder.header("Content-Type", "x-www-form-urlencoded"); +// if (req.getBody() != null && req.getBody().length > 0) { +// String paramstr = req.getParametersToString(); +// if (paramstr != null) { +// if (req.getRequestURI().indexOf('?') > 0) { +// req.setRequestURI(req.getRequestURI() + "&" + paramstr); +// } else { +// req.setRequestURI(req.getRequestURI() + "?" + paramstr); +// } +// } +// builder.POST(java.net.http.HttpRequest.BodyPublishers.ofByteArray(req.getBody())); +// } else { +// String paramstr = req.getParametersToString(); +// if (paramstr != null) builder.POST(java.net.http.HttpRequest.BodyPublishers.ofString(paramstr)); +// } +// return forEachCollectionFuture(finest, userid, req, (req.getPath() != null && !req.getPath().isEmpty() ? req.getPath() : "") + req.getRequestURI(), builder, addrs.iterator()); +// }); +// } +// +// private CompletableFuture> forEachCollectionFuture(boolean finest, Serializable userid, HttpSimpleRequest req, String requesturi, java.net.http.HttpRequest.Builder builder, Iterator it) { +// if (!it.hasNext()) return CompletableFuture.completedFuture(null); +// InetSocketAddress addr = it.next(); +// String url = "http://" + addr.getHostString() + ":" + addr.getPort() + requesturi; +// return httpClient.sendAsync(builder.copy().uri(URI.create(url)).build(), java.net.http.HttpResponse.BodyHandlers.ofByteArray()).thenCompose(resp -> { +// if (resp.statusCode() != 200) return forEachCollectionFuture(finest, userid, req, requesturi, builder, it); +// HttpResult rs = new HttpResult(); +// java.net.http.HttpHeaders hs = resp.headers(); +// if (hs != null) { +// Map> hm = hs.map(); +// if (hm != null) { +// for (Map.Entry> en : hm.entrySet()) { +// if ("date".equals(en.getKey()) || "content-type".equals(en.getKey()) +// || "server".equals(en.getKey()) || "connection".equals(en.getKey())) continue; +// List val = en.getValue(); +// if (val != null && val.size() == 1) { +// rs.header(en.getKey(), val.get(0)); +// } +// } +// } +// } +// rs.setResult(resp.body()); +// if (finest) { +// StringBuilder sb = new StringBuilder(); +// Map params = req.getParams(); +// if (params != null && !params.isEmpty()) { +// params.forEach((n, v) -> sb.append('&').append(n).append('=').append(v)); +// } +// logger.log(Level.FINEST, url + "?userid=" + userid + sb + ", result = " + new String(resp.body(), StandardCharsets.UTF_8)); +// } +// return CompletableFuture.completedFuture(rs); +// }); +// } +} diff --git a/src/main/java/org/redkale/mq/HttpMessageLocalClient.java b/src/main/java/org/redkale/mq/HttpMessageLocalClient.java index 6ec446909..10afd1fea 100644 --- a/src/main/java/org/redkale/mq/HttpMessageLocalClient.java +++ b/src/main/java/org/redkale/mq/HttpMessageLocalClient.java @@ -1,273 +1,273 @@ -/* - * 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.mq; - -import java.io.Serializable; -import java.lang.reflect.Type; -import java.nio.ByteBuffer; -import java.util.*; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.atomic.AtomicLong; -import java.util.logging.Level; -import org.redkale.boot.*; -import org.redkale.convert.*; -import org.redkale.convert.json.JsonConvert; -import org.redkale.net.http.*; - -/** - * 娌℃湁閰嶇疆MQ涓斾篃娌℃湁ClusterAgent鐨勬儏鍐典笅瀹炵幇鐨勯粯璁ttpMessageClient瀹炰緥 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * - * @since 2.4.0 - */ -public class HttpMessageLocalClient extends HttpMessageClient { - - protected final Application application; - - protected final String resourceName; - - protected HttpServer server; - - public HttpMessageLocalClient(Application application, String resourceName) { - super(null); - this.application = application; - this.resourceName = resourceName; - } - - private HttpServer httpServer() { - if (this.server == null) { - NodeHttpServer nodeHttpServer = null; - List nodeServers = application.getNodeServers(); - for (NodeServer n : nodeServers) { - if (n.getClass() == NodeHttpServer.class && Objects.equals(resourceName, ((NodeHttpServer) n).getHttpServer().getName())) { - nodeHttpServer = (NodeHttpServer) n; - break; - } - } - if (nodeHttpServer == null) { - for (NodeServer n : nodeServers) { - if (n.getClass() == NodeHttpServer.class) { - nodeHttpServer = (NodeHttpServer) n; - break; - } - } - } - this.server = nodeHttpServer.getServer(); - } - return this.server; - } - - protected HttpContext context() { - return httpServer().getContext(); - } - - protected HttpPrepareServlet prepareServlet() { - return (HttpPrepareServlet) httpServer().getPrepareServlet(); - } - - @Override - public CompletableFuture sendMessage(HttpSimpleRequest request, Type type) { - HttpPrepareServlet ps = prepareServlet(); - String topic = generateHttpReqTopic(request, request.getPath()); - HttpServlet servlet = ps.findServletByTopic(topic); - CompletableFuture future = new CompletableFuture(); - if (servlet == null) { - future.completeExceptionally(new RuntimeException("404 Not Found " + topic)); - return future; - } - HttpRequest req = new HttpMessageLocalRequest(context(), request); - HttpResponse resp = new HttpMessageLocalResponse(req, future); - try { - servlet.execute(req, resp); - } catch (Exception e) { - future.completeExceptionally(e); - } - return future; - } - - @Override - public CompletableFuture sendMessage(Serializable userid, HttpSimpleRequest request, Type type) { - HttpPrepareServlet ps = prepareServlet(); - String topic = generateHttpReqTopic(request, request.getPath()); - HttpServlet servlet = ps.findServletByTopic(topic); - CompletableFuture future = new CompletableFuture(); - if (servlet == null) { - future.completeExceptionally(new RuntimeException("404 Not Found " + topic)); - return future; - } - HttpRequest req = new HttpMessageLocalRequest(context(), request); - HttpResponse resp = new HttpMessageLocalResponse(req, future); - try { - servlet.execute(req, resp); - } catch (Exception e) { - future.completeExceptionally(e); - } - return future; - } - - @Override - public CompletableFuture sendMessage(Serializable userid, String groupid, HttpSimpleRequest request, Type type) { - HttpPrepareServlet ps = prepareServlet(); - String topic = generateHttpReqTopic(request, request.getPath()); - HttpServlet servlet = ps.findServletByTopic(topic); - CompletableFuture future = new CompletableFuture(); - if (servlet == null) { - future.completeExceptionally(new RuntimeException("404 Not Found " + topic)); - return future; - } - HttpRequest req = new HttpMessageLocalRequest(context(), request); - HttpResponse resp = new HttpMessageLocalResponse(req, future); - try { - servlet.execute(req, resp); - } catch (Exception e) { - future.completeExceptionally(e); - } - return future; - } - - @Override - public CompletableFuture> sendMessage(String topic, Serializable userid, String groupid, HttpSimpleRequest request, AtomicLong counter) { - HttpPrepareServlet ps = prepareServlet(); - HttpServlet servlet = ps.findServletByTopic(topic); - if (servlet == null) return CompletableFuture.completedFuture(new HttpResult().status(404)); - HttpRequest req = new HttpMessageLocalRequest(context(), request); - CompletableFuture future = new CompletableFuture(); - HttpResponse resp = new HttpMessageLocalResponse(req, future); - try { - servlet.execute(req, resp); - } catch (Exception e) { - future.completeExceptionally(e); - } - return future.thenApply(rs -> { - if (rs == null) return new HttpResult(); - if (rs instanceof HttpResult) { - Object result = ((HttpResult) rs).getResult(); - if (result == null || result instanceof byte[]) return (HttpResult) rs; - return new HttpResult(JsonConvert.root().convertToBytes(result)); - } - return new HttpResult(JsonConvert.root().convertToBytes(rs)); - }); - } - - @Override - public void produceMessage(String topic, Serializable userid, String groupid, HttpSimpleRequest request, AtomicLong counter) { - HttpPrepareServlet ps = prepareServlet(); - HttpServlet servlet = ps.findServletByTopic(topic); - if (servlet == null) return; - HttpRequest req = new HttpMessageLocalRequest(context(), request); - HttpResponse resp = new HttpMessageLocalResponse(req, null); - try { - servlet.execute(req, resp); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - @Override - public void broadcastMessage(String topic, Serializable userid, String groupid, HttpSimpleRequest request, AtomicLong counter) { - HttpPrepareServlet ps = prepareServlet(); - HttpRequest req = new HttpMessageLocalRequest(context(), request); - HttpResponse resp = new HttpMessageLocalResponse(req, null); - ps.filterServletsByMmcTopic(topic).forEach(s -> { - try { - s.execute(req, resp); - } catch (Exception e) { - logger.log(Level.SEVERE, request + " execute " + s + " error", e); - } - }); - } - - public static class HttpMessageLocalRequest extends HttpRequest { - - public HttpMessageLocalRequest(HttpContext context, HttpSimpleRequest req) { - super(context, req); - } - } - - public static class HttpMessageLocalResponse extends HttpResponse { - - private CompletableFuture future; - - public HttpMessageLocalResponse(HttpRequest req, CompletableFuture future) { - super(req.getContext(), req, null); - this.future = future; - } - - @Override - public void finish(String obj) { - if (future == null) return; - future.complete(obj == null ? "" : obj); - } - - @Override - public void finish404() { - finish(404, null); - } - - @Override - public void finish(int status, String msg) { - if (future == null) return; - if (status == 0 || status == 200) { - future.complete(msg == null ? "" : msg); - } else { - future.complete(new HttpResult(msg == null ? "" : msg).status(status)); - } - } - - @Override - public void finish(final Convert convert, Type valueType, HttpResult result) { - if (future == null) return; - if (convert != null) result.convert(convert); - future.complete(result); - } - - @Override - public void finish(boolean kill, final byte[] bs, int offset, int length) { - if (future == null) return; - if (offset == 0 && bs.length == length) { - future.complete(bs); - } else { - future.complete(Arrays.copyOfRange(bs, offset, offset + length)); - } - } - - @Override - public void finish(boolean kill, final String contentType, final byte[] bs, int offset, int length) { - if (future == null) return; - byte[] rs = (offset == 0 && bs.length == length) ? bs : Arrays.copyOfRange(bs, offset, offset + length); - future.complete(rs); - } - - @Override - public void finish(boolean kill, ByteBuffer buffer) { - if (future == null) return; - byte[] bs = new byte[buffer.remaining()]; - buffer.get(bs); - future.complete(bs); - } - - @Override - public void finish(boolean kill, ByteBuffer... buffers) { - if (future == null) return; - int size = 0; - for (ByteBuffer buf : buffers) { - size += buf.remaining(); - } - byte[] bs = new byte[size]; - int index = 0; - for (ByteBuffer buf : buffers) { - int r = buf.remaining(); - buf.get(bs, index, r); - index += r; - } - future.complete(bs); - } - } -} +/* + * 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.mq; + +import java.io.Serializable; +import java.lang.reflect.Type; +import java.nio.ByteBuffer; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicLong; +import java.util.logging.Level; +import org.redkale.boot.*; +import org.redkale.convert.*; +import org.redkale.convert.json.JsonConvert; +import org.redkale.net.http.*; + +/** + * 娌℃湁閰嶇疆MQ涓斾篃娌℃湁ClusterAgent鐨勬儏鍐典笅瀹炵幇鐨勯粯璁ttpMessageClient瀹炰緥 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.4.0 + */ +public class HttpMessageLocalClient extends HttpMessageClient { + + protected final Application application; + + protected final String resourceName; + + protected HttpServer server; + + public HttpMessageLocalClient(Application application, String resourceName) { + super(null); + this.application = application; + this.resourceName = resourceName; + } + + private HttpServer httpServer() { + if (this.server == null) { + NodeHttpServer nodeHttpServer = null; + List nodeServers = application.getNodeServers(); + for (NodeServer n : nodeServers) { + if (n.getClass() == NodeHttpServer.class && Objects.equals(resourceName, ((NodeHttpServer) n).getHttpServer().getName())) { + nodeHttpServer = (NodeHttpServer) n; + break; + } + } + if (nodeHttpServer == null) { + for (NodeServer n : nodeServers) { + if (n.getClass() == NodeHttpServer.class) { + nodeHttpServer = (NodeHttpServer) n; + break; + } + } + } + this.server = nodeHttpServer.getServer(); + } + return this.server; + } + + protected HttpContext context() { + return httpServer().getContext(); + } + + protected HttpPrepareServlet prepareServlet() { + return (HttpPrepareServlet) httpServer().getPrepareServlet(); + } + + @Override + public CompletableFuture sendMessage(HttpSimpleRequest request, Type type) { + HttpPrepareServlet ps = prepareServlet(); + String topic = generateHttpReqTopic(request, request.getPath()); + HttpServlet servlet = ps.findServletByTopic(topic); + CompletableFuture future = new CompletableFuture(); + if (servlet == null) { + future.completeExceptionally(new RuntimeException("404 Not Found " + topic)); + return future; + } + HttpRequest req = new HttpMessageLocalRequest(context(), request); + HttpResponse resp = new HttpMessageLocalResponse(req, future); + try { + servlet.execute(req, resp); + } catch (Exception e) { + future.completeExceptionally(e); + } + return future; + } + + @Override + public CompletableFuture sendMessage(Serializable userid, HttpSimpleRequest request, Type type) { + HttpPrepareServlet ps = prepareServlet(); + String topic = generateHttpReqTopic(request, request.getPath()); + HttpServlet servlet = ps.findServletByTopic(topic); + CompletableFuture future = new CompletableFuture(); + if (servlet == null) { + future.completeExceptionally(new RuntimeException("404 Not Found " + topic)); + return future; + } + HttpRequest req = new HttpMessageLocalRequest(context(), request); + HttpResponse resp = new HttpMessageLocalResponse(req, future); + try { + servlet.execute(req, resp); + } catch (Exception e) { + future.completeExceptionally(e); + } + return future; + } + + @Override + public CompletableFuture sendMessage(Serializable userid, String groupid, HttpSimpleRequest request, Type type) { + HttpPrepareServlet ps = prepareServlet(); + String topic = generateHttpReqTopic(request, request.getPath()); + HttpServlet servlet = ps.findServletByTopic(topic); + CompletableFuture future = new CompletableFuture(); + if (servlet == null) { + future.completeExceptionally(new RuntimeException("404 Not Found " + topic)); + return future; + } + HttpRequest req = new HttpMessageLocalRequest(context(), request); + HttpResponse resp = new HttpMessageLocalResponse(req, future); + try { + servlet.execute(req, resp); + } catch (Exception e) { + future.completeExceptionally(e); + } + return future; + } + + @Override + public CompletableFuture> sendMessage(String topic, Serializable userid, String groupid, HttpSimpleRequest request, AtomicLong counter) { + HttpPrepareServlet ps = prepareServlet(); + HttpServlet servlet = ps.findServletByTopic(topic); + if (servlet == null) return CompletableFuture.completedFuture(new HttpResult().status(404)); + HttpRequest req = new HttpMessageLocalRequest(context(), request); + CompletableFuture future = new CompletableFuture(); + HttpResponse resp = new HttpMessageLocalResponse(req, future); + try { + servlet.execute(req, resp); + } catch (Exception e) { + future.completeExceptionally(e); + } + return future.thenApply(rs -> { + if (rs == null) return new HttpResult(); + if (rs instanceof HttpResult) { + Object result = ((HttpResult) rs).getResult(); + if (result == null || result instanceof byte[]) return (HttpResult) rs; + return new HttpResult(JsonConvert.root().convertToBytes(result)); + } + return new HttpResult(JsonConvert.root().convertToBytes(rs)); + }); + } + + @Override + public void produceMessage(String topic, Serializable userid, String groupid, HttpSimpleRequest request, AtomicLong counter) { + HttpPrepareServlet ps = prepareServlet(); + HttpServlet servlet = ps.findServletByTopic(topic); + if (servlet == null) return; + HttpRequest req = new HttpMessageLocalRequest(context(), request); + HttpResponse resp = new HttpMessageLocalResponse(req, null); + try { + servlet.execute(req, resp); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public void broadcastMessage(String topic, Serializable userid, String groupid, HttpSimpleRequest request, AtomicLong counter) { + HttpPrepareServlet ps = prepareServlet(); + HttpRequest req = new HttpMessageLocalRequest(context(), request); + HttpResponse resp = new HttpMessageLocalResponse(req, null); + ps.filterServletsByMmcTopic(topic).forEach(s -> { + try { + s.execute(req, resp); + } catch (Exception e) { + logger.log(Level.SEVERE, request + " execute " + s + " error", e); + } + }); + } + + public static class HttpMessageLocalRequest extends HttpRequest { + + public HttpMessageLocalRequest(HttpContext context, HttpSimpleRequest req) { + super(context, req); + } + } + + public static class HttpMessageLocalResponse extends HttpResponse { + + private CompletableFuture future; + + public HttpMessageLocalResponse(HttpRequest req, CompletableFuture future) { + super(req.getContext(), req, null); + this.future = future; + } + + @Override + public void finish(String obj) { + if (future == null) return; + future.complete(obj == null ? "" : obj); + } + + @Override + public void finish404() { + finish(404, null); + } + + @Override + public void finish(int status, String msg) { + if (future == null) return; + if (status == 0 || status == 200) { + future.complete(msg == null ? "" : msg); + } else { + future.complete(new HttpResult(msg == null ? "" : msg).status(status)); + } + } + + @Override + public void finish(final Convert convert, Type valueType, HttpResult result) { + if (future == null) return; + if (convert != null) result.convert(convert); + future.complete(result); + } + + @Override + public void finish(boolean kill, final byte[] bs, int offset, int length) { + if (future == null) return; + if (offset == 0 && bs.length == length) { + future.complete(bs); + } else { + future.complete(Arrays.copyOfRange(bs, offset, offset + length)); + } + } + + @Override + public void finish(boolean kill, final String contentType, final byte[] bs, int offset, int length) { + if (future == null) return; + byte[] rs = (offset == 0 && bs.length == length) ? bs : Arrays.copyOfRange(bs, offset, offset + length); + future.complete(rs); + } + + @Override + public void finish(boolean kill, ByteBuffer buffer) { + if (future == null) return; + byte[] bs = new byte[buffer.remaining()]; + buffer.get(bs); + future.complete(bs); + } + + @Override + public void finish(boolean kill, ByteBuffer... buffers) { + if (future == null) return; + int size = 0; + for (ByteBuffer buf : buffers) { + size += buf.remaining(); + } + byte[] bs = new byte[size]; + int index = 0; + for (ByteBuffer buf : buffers) { + int r = buf.remaining(); + buf.get(bs, index, r); + index += r; + } + future.complete(bs); + } + } +} diff --git a/src/main/java/org/redkale/mq/HttpMessageProcessor.java b/src/main/java/org/redkale/mq/HttpMessageProcessor.java index 544f39c1b..54154a0cd 100644 --- a/src/main/java/org/redkale/mq/HttpMessageProcessor.java +++ b/src/main/java/org/redkale/mq/HttpMessageProcessor.java @@ -1,156 +1,156 @@ -/* - * 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.mq; - -import java.util.concurrent.*; -import java.util.function.*; -import java.util.logging.*; -import org.redkale.boot.NodeHttpServer; -import org.redkale.net.http.*; -import org.redkale.service.Service; -import org.redkale.util.*; - -/** - * 涓涓猄ervice瀵瑰簲涓涓狹essageProcessor - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * - * @since 2.1.0 - */ -public class HttpMessageProcessor implements MessageProcessor { - - protected final boolean finest; - - protected final boolean finer; - - protected final boolean fine; - - protected final Logger logger; - - protected HttpMessageClient messageClient; - - protected final MessageProducers producers; - - protected final NodeHttpServer server; - - protected final Service service; - - protected final HttpServlet servlet; - - protected final boolean multiconsumer; - - protected final String restmodule; // 鍓嶅悗鏈/, 渚嬪: /user/ - - protected final String multimodule; // 鍓嶅悗鏈/, 渚嬪: /userstat/ - - protected ThreadLocal> respPoolThreadLocal; - - protected final Supplier respSupplier; - - protected final Consumer respConsumer; - - protected CountDownLatch cdl; - - protected long starttime; - - protected final Runnable innerCallback = () -> { - if (cdl != null) cdl.countDown(); - }; - - public HttpMessageProcessor(Logger logger, HttpMessageClient messageClient, MessageProducers producers, NodeHttpServer server, Service service, HttpServlet servlet) { - this.logger = logger; - this.finest = logger.isLoggable(Level.FINEST); - this.finer = logger.isLoggable(Level.FINER); - this.fine = logger.isLoggable(Level.FINE); - this.messageClient = messageClient; - this.producers = producers; - this.server = server; - this.service = service; - this.servlet = servlet; - MessageMultiConsumer mmc = service.getClass().getAnnotation(MessageMultiConsumer.class); - this.multiconsumer = mmc != null; - this.restmodule = "/" + Rest.getRestModule(service) + "/"; - this.multimodule = mmc != null ? ("/" + mmc.module() + "/") : null; - this.respSupplier = () -> respPoolThreadLocal.get().get(); - this.respConsumer = resp -> respPoolThreadLocal.get().accept(resp); - this.respPoolThreadLocal = ThreadLocal.withInitial(() -> ObjectPool.createUnsafePool(Utility.cpus(), - ps -> new HttpMessageResponse(server.getHttpServer().getContext(), messageClient, respSupplier, respConsumer), HttpMessageResponse::prepare, HttpMessageResponse::recycle)); - } - - @Override - public void begin(final int size, long starttime) { - this.starttime = starttime; - this.cdl = new CountDownLatch(size); - } - - @Override - public void process(final MessageRecord message, final Runnable callback) { - execute(message, innerCallback); - } - - private void execute(final MessageRecord message, final Runnable callback) { - HttpMessageRequest request = null; - try { - long now = System.currentTimeMillis(); - long cha = now - message.createtime; - long e = now - starttime; - if (multiconsumer) message.setResptopic(null); //涓嶅璁告湁鍝嶅簲 - - HttpMessageResponse response = respSupplier.get(); - request = response.request(); - response.prepare(message, callback, producers.getProducer(message)); - if (multiconsumer) request.setRequestURI(request.getRequestURI().replaceFirst(this.multimodule, this.restmodule)); - - server.getHttpServer().getContext().execute(servlet, request, response); - long o = System.currentTimeMillis() - now; - if ((cha > 1000 || e > 100 || o > 1000) && fine) { - logger.log(Level.FINE, "HttpMessageProcessor.process (mqs.delays = " + cha + " ms, mqs.blocks = " + e + " ms, mqs.executes = " + o + " ms) message: " + message); - } else if ((cha > 50 || e > 10 || o > 50) && finer) { - logger.log(Level.FINER, "HttpMessageProcessor.process (mq.delays = " + cha + " ms, mq.blocks = " + e + " ms, mq.executes = " + o + " ms) message: " + message); - } else if (finest) { - logger.log(Level.FINEST, "HttpMessageProcessor.process (mq.delay = " + cha + " ms, mq.block = " + e + " ms, mq.execute = " + o + " ms) message: " + message); - } - } catch (Throwable ex) { - if (message.getResptopic() != null && !message.getResptopic().isEmpty()) { - HttpMessageResponse.finishHttpResult(finest, request == null ? null : request.getRespConvert(), - null, message, callback, messageClient, producers.getProducer(message), message.getResptopic(), new HttpResult().status(500)); - } - logger.log(Level.SEVERE, HttpMessageProcessor.class.getSimpleName() + " process error, message=" + message, ex instanceof CompletionException ? ((CompletionException) ex).getCause() : ex); - } - } - - @Override - public void commit() { - if (this.cdl != null) { - try { - this.cdl.await(30, TimeUnit.SECONDS); - } catch (Exception ex) { - logger.log(Level.SEVERE, HttpMessageProcessor.class.getSimpleName() + " commit error, restmodule=" + this.restmodule, ex); - } - this.cdl = null; - } - } - - public MessageProducers getProducer() { - return producers; - } - - public NodeHttpServer getServer() { - return server; - } - - public Service getService() { - return service; - } - - public HttpServlet getServlet() { - return servlet; - } - -} +/* + * 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.mq; + +import java.util.concurrent.*; +import java.util.function.*; +import java.util.logging.*; +import org.redkale.boot.NodeHttpServer; +import org.redkale.net.http.*; +import org.redkale.service.Service; +import org.redkale.util.*; + +/** + * 涓涓猄ervice瀵瑰簲涓涓狹essageProcessor + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.1.0 + */ +public class HttpMessageProcessor implements MessageProcessor { + + protected final boolean finest; + + protected final boolean finer; + + protected final boolean fine; + + protected final Logger logger; + + protected HttpMessageClient messageClient; + + protected final MessageProducers producers; + + protected final NodeHttpServer server; + + protected final Service service; + + protected final HttpServlet servlet; + + protected final boolean multiconsumer; + + protected final String restmodule; // 鍓嶅悗鏈/, 渚嬪: /user/ + + protected final String multimodule; // 鍓嶅悗鏈/, 渚嬪: /userstat/ + + protected ThreadLocal> respPoolThreadLocal; + + protected final Supplier respSupplier; + + protected final Consumer respConsumer; + + protected CountDownLatch cdl; + + protected long starttime; + + protected final Runnable innerCallback = () -> { + if (cdl != null) cdl.countDown(); + }; + + public HttpMessageProcessor(Logger logger, HttpMessageClient messageClient, MessageProducers producers, NodeHttpServer server, Service service, HttpServlet servlet) { + this.logger = logger; + this.finest = logger.isLoggable(Level.FINEST); + this.finer = logger.isLoggable(Level.FINER); + this.fine = logger.isLoggable(Level.FINE); + this.messageClient = messageClient; + this.producers = producers; + this.server = server; + this.service = service; + this.servlet = servlet; + MessageMultiConsumer mmc = service.getClass().getAnnotation(MessageMultiConsumer.class); + this.multiconsumer = mmc != null; + this.restmodule = "/" + Rest.getRestModule(service) + "/"; + this.multimodule = mmc != null ? ("/" + mmc.module() + "/") : null; + this.respSupplier = () -> respPoolThreadLocal.get().get(); + this.respConsumer = resp -> respPoolThreadLocal.get().accept(resp); + this.respPoolThreadLocal = ThreadLocal.withInitial(() -> ObjectPool.createUnsafePool(Utility.cpus(), + ps -> new HttpMessageResponse(server.getHttpServer().getContext(), messageClient, respSupplier, respConsumer), HttpMessageResponse::prepare, HttpMessageResponse::recycle)); + } + + @Override + public void begin(final int size, long starttime) { + this.starttime = starttime; + this.cdl = new CountDownLatch(size); + } + + @Override + public void process(final MessageRecord message, final Runnable callback) { + execute(message, innerCallback); + } + + private void execute(final MessageRecord message, final Runnable callback) { + HttpMessageRequest request = null; + try { + long now = System.currentTimeMillis(); + long cha = now - message.createtime; + long e = now - starttime; + if (multiconsumer) message.setResptopic(null); //涓嶅璁告湁鍝嶅簲 + + HttpMessageResponse response = respSupplier.get(); + request = response.request(); + response.prepare(message, callback, producers.getProducer(message)); + if (multiconsumer) request.setRequestURI(request.getRequestURI().replaceFirst(this.multimodule, this.restmodule)); + + server.getHttpServer().getContext().execute(servlet, request, response); + long o = System.currentTimeMillis() - now; + if ((cha > 1000 || e > 100 || o > 1000) && fine) { + logger.log(Level.FINE, "HttpMessageProcessor.process (mqs.delays = " + cha + " ms, mqs.blocks = " + e + " ms, mqs.executes = " + o + " ms) message: " + message); + } else if ((cha > 50 || e > 10 || o > 50) && finer) { + logger.log(Level.FINER, "HttpMessageProcessor.process (mq.delays = " + cha + " ms, mq.blocks = " + e + " ms, mq.executes = " + o + " ms) message: " + message); + } else if (finest) { + logger.log(Level.FINEST, "HttpMessageProcessor.process (mq.delay = " + cha + " ms, mq.block = " + e + " ms, mq.execute = " + o + " ms) message: " + message); + } + } catch (Throwable ex) { + if (message.getResptopic() != null && !message.getResptopic().isEmpty()) { + HttpMessageResponse.finishHttpResult(finest, request == null ? null : request.getRespConvert(), + null, message, callback, messageClient, producers.getProducer(message), message.getResptopic(), new HttpResult().status(500)); + } + logger.log(Level.SEVERE, HttpMessageProcessor.class.getSimpleName() + " process error, message=" + message, ex instanceof CompletionException ? ((CompletionException) ex).getCause() : ex); + } + } + + @Override + public void commit() { + if (this.cdl != null) { + try { + this.cdl.await(30, TimeUnit.SECONDS); + } catch (Exception ex) { + logger.log(Level.SEVERE, HttpMessageProcessor.class.getSimpleName() + " commit error, restmodule=" + this.restmodule, ex); + } + this.cdl = null; + } + } + + public MessageProducers getProducer() { + return producers; + } + + public NodeHttpServer getServer() { + return server; + } + + public Service getService() { + return service; + } + + public HttpServlet getServlet() { + return servlet; + } + +} diff --git a/src/main/java/org/redkale/mq/HttpMessageRequest.java b/src/main/java/org/redkale/mq/HttpMessageRequest.java index df890155c..1c42942bd 100644 --- a/src/main/java/org/redkale/mq/HttpMessageRequest.java +++ b/src/main/java/org/redkale/mq/HttpMessageRequest.java @@ -1,57 +1,57 @@ -/* - * 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.mq; - -import org.redkale.convert.Convert; -import org.redkale.net.http.*; - -/** - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * - * @since 2.1.0 - */ -public class HttpMessageRequest extends HttpRequest { - - protected MessageRecord message; - - public HttpMessageRequest(HttpContext context) { - super(context, (HttpSimpleRequest) null); - } - - protected HttpMessageRequest prepare(MessageRecord message) { - super.initSimpleRequest(message.decodeContent(HttpSimpleRequestCoder.getInstance()), false); - this.message = message; - this.hashid = this.message.hash(); - this.currentUserid = message.getUserid(); - this.createtime = System.currentTimeMillis(); - return this; - } - - public void setRequestURI(String uri) { - this.requestURI = uri; - } - - @Override - public Convert getRespConvert() { - return this.respConvert; - } - - @Override - protected void prepare() { - super.prepare(); - this.keepAlive = false; - } - - @Override - protected void recycle() { - super.recycle(); - this.message = null; - } -} +/* + * 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.mq; + +import org.redkale.convert.Convert; +import org.redkale.net.http.*; + +/** + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.1.0 + */ +public class HttpMessageRequest extends HttpRequest { + + protected MessageRecord message; + + public HttpMessageRequest(HttpContext context) { + super(context, (HttpSimpleRequest) null); + } + + protected HttpMessageRequest prepare(MessageRecord message) { + super.initSimpleRequest(message.decodeContent(HttpSimpleRequestCoder.getInstance()), false); + this.message = message; + this.hashid = this.message.hash(); + this.currentUserid = message.getUserid(); + this.createtime = System.currentTimeMillis(); + return this; + } + + public void setRequestURI(String uri) { + this.requestURI = uri; + } + + @Override + public Convert getRespConvert() { + return this.respConvert; + } + + @Override + protected void prepare() { + super.prepare(); + this.keepAlive = false; + } + + @Override + protected void recycle() { + super.recycle(); + this.message = null; + } +} diff --git a/src/main/java/org/redkale/mq/HttpMessageResponse.java b/src/main/java/org/redkale/mq/HttpMessageResponse.java index 9fc21eae3..260797175 100644 --- a/src/main/java/org/redkale/mq/HttpMessageResponse.java +++ b/src/main/java/org/redkale/mq/HttpMessageResponse.java @@ -1,203 +1,203 @@ -/* - * 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.mq; - -import java.lang.reflect.Type; -import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.function.*; -import java.util.logging.Level; -import org.redkale.convert.*; -import org.redkale.net.http.*; -import org.redkale.service.RetResult; -import static org.redkale.mq.MessageRecord.CTYPE_HTTP_RESULT; -import org.redkale.net.Response; - -/** - * - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * - * @since 2.1.0 - */ -public class HttpMessageResponse extends HttpResponse { - - protected final HttpMessageClient messageClient; - - protected MessageRecord message; - - protected MessageProducer producer; - - protected boolean finest; - - protected Runnable callback; - - public HttpMessageResponse(HttpContext context, HttpMessageClient messageClient, final Supplier respSupplier, final Consumer respConsumer) { - super(context, new HttpMessageRequest(context), null); - this.responseSupplier = (Supplier) respSupplier; - this.responseConsumer = (Consumer) respConsumer; - this.messageClient = messageClient; - } - -// public HttpMessageResponse(HttpContext context, HttpMessageRequest request, Runnable callback, -// HttpResponseConfig config, HttpMessageClient messageClient, MessageProducer producer) { -// super(context, request, config); -// this.message = request.message; -// this.callback = callback; -// this.messageClient = messageClient; -// this.producer = producer; -// this.finest = producer.logger.isLoggable(Level.FINEST); -// } - public void prepare(MessageRecord message, Runnable callback, MessageProducer producer) { - ((HttpMessageRequest) request).prepare(message); - this.message = message; - this.callback = callback; - this.producer = producer; - this.finest = producer.logger.isLoggable(Level.FINEST); - } - - public HttpMessageRequest request() { - return (HttpMessageRequest) request; - } - - public void finishHttpResult(Type type, HttpResult result) { - finishHttpResult(this.finest, ((HttpMessageRequest) this.request).getRespConvert(), type, this.message, this.callback, this.messageClient, this.producer, message.getResptopic(), result); - } - - public static void finishHttpResult(boolean finest, Convert respConvert, Type type, MessageRecord msg, Runnable callback, MessageClient messageClient, MessageProducer producer, String resptopic, HttpResult result) { - if (callback != null) callback.run(); - if (resptopic == null || resptopic.isEmpty()) return; - if (result.getResult() instanceof RetResult) { - RetResult ret = (RetResult) result.getResult(); - //蹇呴』瑕佸鍏etcode锛 寮鍙戣呭彲浠ユ棤闇鍙嶅簭鍒楀寲ret渚垮彲纭畾鎿嶄綔鏄惁杩斿洖鎴愬姛 - if (!ret.isSuccess()) result.header("retcode", String.valueOf(ret.getRetcode())); - } - if (result.convert() == null && respConvert != null) result.convert(respConvert); - if (finest) { - Object innerrs = result.getResult(); - if (innerrs instanceof byte[]) innerrs = new String((byte[]) innerrs, StandardCharsets.UTF_8); - producer.logger.log(Level.FINEST, "HttpMessageResponse.finishHttpResult seqid=" + msg.getSeqid() + ", content: " + innerrs + ", status: " + result.getStatus() + ", headers: " + result.getHeaders()); - } - byte[] content = HttpResultCoder.getInstance().encode(result); - producer.apply(messageClient.createMessageRecord(msg.getSeqid(), CTYPE_HTTP_RESULT, resptopic, null, content)); - } - - @Override - protected void prepare() { - super.prepare(); - } - - @Override - protected boolean recycle() { - Supplier respSupplier = this.responseSupplier; - Consumer respConsumer = this.responseConsumer; - boolean rs = super.recycle(); - this.responseSupplier = respSupplier; - this.responseConsumer = respConsumer; - this.message = null; - this.producer = null; - this.callback = null; - this.finest = false; - return rs; - } - - @Override - public void finish(String obj) { - if (message.isEmptyResptopic()) { - if (callback != null) callback.run(); - return; - } - finishHttpResult(String.class, new HttpResult(obj == null ? "" : obj)); - } - - @Override - public void finish404() { - finish(404, null); - } - - @Override - public void finish(int status, String msg) { - if (status > 400) { - producer.logger.log(Level.WARNING, "HttpMessageResponse.finish status: " + status + ", uri: " + this.request.getRequestURI() + ", message: " + this.message); - } else if (finest) { - producer.logger.log(Level.FINEST, "HttpMessageResponse.finish status: " + status); - } - if (this.message.isEmptyResptopic()) { - if (callback != null) callback.run(); - return; - } - finishHttpResult(String.class, new HttpResult(msg == null ? "" : msg).status(status)); - } - - @Override - public void finish(final Convert convert, Type type, HttpResult result) { - if (message.isEmptyResptopic()) { - if (callback != null) callback.run(); - return; - } - if (convert != null) result.convert(convert); - finishHttpResult(type, result); - } - - @Override - public void finish(boolean kill, final byte[] bs, int offset, int length) { - if (message.isEmptyResptopic()) { - if (callback != null) callback.run(); - return; - } - if (offset == 0 && bs.length == length) { - finishHttpResult(null, new HttpResult(bs)); - } else { - finishHttpResult(null, new HttpResult(Arrays.copyOfRange(bs, offset, offset + length))); - } - } - - @Override - public void finish(boolean kill, final String contentType, final byte[] bs, int offset, int length) { - if (message.isEmptyResptopic()) { - if (callback != null) callback.run(); - return; - } - byte[] rs = (offset == 0 && bs.length == length) ? bs : Arrays.copyOfRange(bs, offset, offset + length); - finishHttpResult(null, new HttpResult(rs).contentType(contentType)); - } - - @Override - public void finish(boolean kill, ByteBuffer buffer) { - if (message.isEmptyResptopic()) { - if (callback != null) callback.run(); - return; - } - byte[] bs = new byte[buffer.remaining()]; - buffer.get(bs); - finishHttpResult(null, new HttpResult(bs)); - } - - @Override - public void finish(boolean kill, ByteBuffer... buffers) { - if (message.isEmptyResptopic()) { - if (callback != null) callback.run(); - return; - } - int size = 0; - for (ByteBuffer buf : buffers) { - size += buf.remaining(); - } - byte[] bs = new byte[size]; - int index = 0; - for (ByteBuffer buf : buffers) { - int r = buf.remaining(); - buf.get(bs, index, r); - index += r; - } - finishHttpResult(null, new HttpResult(bs)); - } - -} +/* + * 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.mq; + +import java.lang.reflect.Type; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.function.*; +import java.util.logging.Level; +import org.redkale.convert.*; +import org.redkale.net.http.*; +import org.redkale.service.RetResult; +import static org.redkale.mq.MessageRecord.CTYPE_HTTP_RESULT; +import org.redkale.net.Response; + +/** + * + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.1.0 + */ +public class HttpMessageResponse extends HttpResponse { + + protected final HttpMessageClient messageClient; + + protected MessageRecord message; + + protected MessageProducer producer; + + protected boolean finest; + + protected Runnable callback; + + public HttpMessageResponse(HttpContext context, HttpMessageClient messageClient, final Supplier respSupplier, final Consumer respConsumer) { + super(context, new HttpMessageRequest(context), null); + this.responseSupplier = (Supplier) respSupplier; + this.responseConsumer = (Consumer) respConsumer; + this.messageClient = messageClient; + } + +// public HttpMessageResponse(HttpContext context, HttpMessageRequest request, Runnable callback, +// HttpResponseConfig config, HttpMessageClient messageClient, MessageProducer producer) { +// super(context, request, config); +// this.message = request.message; +// this.callback = callback; +// this.messageClient = messageClient; +// this.producer = producer; +// this.finest = producer.logger.isLoggable(Level.FINEST); +// } + public void prepare(MessageRecord message, Runnable callback, MessageProducer producer) { + ((HttpMessageRequest) request).prepare(message); + this.message = message; + this.callback = callback; + this.producer = producer; + this.finest = producer.logger.isLoggable(Level.FINEST); + } + + public HttpMessageRequest request() { + return (HttpMessageRequest) request; + } + + public void finishHttpResult(Type type, HttpResult result) { + finishHttpResult(this.finest, ((HttpMessageRequest) this.request).getRespConvert(), type, this.message, this.callback, this.messageClient, this.producer, message.getResptopic(), result); + } + + public static void finishHttpResult(boolean finest, Convert respConvert, Type type, MessageRecord msg, Runnable callback, MessageClient messageClient, MessageProducer producer, String resptopic, HttpResult result) { + if (callback != null) callback.run(); + if (resptopic == null || resptopic.isEmpty()) return; + if (result.getResult() instanceof RetResult) { + RetResult ret = (RetResult) result.getResult(); + //蹇呴』瑕佸鍏etcode锛 寮鍙戣呭彲浠ユ棤闇鍙嶅簭鍒楀寲ret渚垮彲纭畾鎿嶄綔鏄惁杩斿洖鎴愬姛 + if (!ret.isSuccess()) result.header("retcode", String.valueOf(ret.getRetcode())); + } + if (result.convert() == null && respConvert != null) result.convert(respConvert); + if (finest) { + Object innerrs = result.getResult(); + if (innerrs instanceof byte[]) innerrs = new String((byte[]) innerrs, StandardCharsets.UTF_8); + producer.logger.log(Level.FINEST, "HttpMessageResponse.finishHttpResult seqid=" + msg.getSeqid() + ", content: " + innerrs + ", status: " + result.getStatus() + ", headers: " + result.getHeaders()); + } + byte[] content = HttpResultCoder.getInstance().encode(result); + producer.apply(messageClient.createMessageRecord(msg.getSeqid(), CTYPE_HTTP_RESULT, resptopic, null, content)); + } + + @Override + protected void prepare() { + super.prepare(); + } + + @Override + protected boolean recycle() { + Supplier respSupplier = this.responseSupplier; + Consumer respConsumer = this.responseConsumer; + boolean rs = super.recycle(); + this.responseSupplier = respSupplier; + this.responseConsumer = respConsumer; + this.message = null; + this.producer = null; + this.callback = null; + this.finest = false; + return rs; + } + + @Override + public void finish(String obj) { + if (message.isEmptyResptopic()) { + if (callback != null) callback.run(); + return; + } + finishHttpResult(String.class, new HttpResult(obj == null ? "" : obj)); + } + + @Override + public void finish404() { + finish(404, null); + } + + @Override + public void finish(int status, String msg) { + if (status > 400) { + producer.logger.log(Level.WARNING, "HttpMessageResponse.finish status: " + status + ", uri: " + this.request.getRequestURI() + ", message: " + this.message); + } else if (finest) { + producer.logger.log(Level.FINEST, "HttpMessageResponse.finish status: " + status); + } + if (this.message.isEmptyResptopic()) { + if (callback != null) callback.run(); + return; + } + finishHttpResult(String.class, new HttpResult(msg == null ? "" : msg).status(status)); + } + + @Override + public void finish(final Convert convert, Type type, HttpResult result) { + if (message.isEmptyResptopic()) { + if (callback != null) callback.run(); + return; + } + if (convert != null) result.convert(convert); + finishHttpResult(type, result); + } + + @Override + public void finish(boolean kill, final byte[] bs, int offset, int length) { + if (message.isEmptyResptopic()) { + if (callback != null) callback.run(); + return; + } + if (offset == 0 && bs.length == length) { + finishHttpResult(null, new HttpResult(bs)); + } else { + finishHttpResult(null, new HttpResult(Arrays.copyOfRange(bs, offset, offset + length))); + } + } + + @Override + public void finish(boolean kill, final String contentType, final byte[] bs, int offset, int length) { + if (message.isEmptyResptopic()) { + if (callback != null) callback.run(); + return; + } + byte[] rs = (offset == 0 && bs.length == length) ? bs : Arrays.copyOfRange(bs, offset, offset + length); + finishHttpResult(null, new HttpResult(rs).contentType(contentType)); + } + + @Override + public void finish(boolean kill, ByteBuffer buffer) { + if (message.isEmptyResptopic()) { + if (callback != null) callback.run(); + return; + } + byte[] bs = new byte[buffer.remaining()]; + buffer.get(bs); + finishHttpResult(null, new HttpResult(bs)); + } + + @Override + public void finish(boolean kill, ByteBuffer... buffers) { + if (message.isEmptyResptopic()) { + if (callback != null) callback.run(); + return; + } + int size = 0; + for (ByteBuffer buf : buffers) { + size += buf.remaining(); + } + byte[] bs = new byte[size]; + int index = 0; + for (ByteBuffer buf : buffers) { + int r = buf.remaining(); + buf.get(bs, index, r); + index += r; + } + finishHttpResult(null, new HttpResult(bs)); + } + +} diff --git a/src/main/java/org/redkale/mq/HttpResultCoder.java b/src/main/java/org/redkale/mq/HttpResultCoder.java index eb4a1221f..a6464b5b9 100644 --- a/src/main/java/org/redkale/mq/HttpResultCoder.java +++ b/src/main/java/org/redkale/mq/HttpResultCoder.java @@ -1,132 +1,132 @@ -/* - * 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.mq; - -import java.net.HttpCookie; -import java.nio.ByteBuffer; -import java.util.*; -import java.util.concurrent.atomic.AtomicInteger; -import org.redkale.convert.*; -import org.redkale.convert.json.JsonConvert; -import static org.redkale.mq.MessageCoder.*; -import org.redkale.net.http.HttpResult; -import org.redkale.util.Utility; - -/** - * HttpResult鐨凪essageCoder瀹炵幇 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * - * @since 2.1.0 - */ -public class HttpResultCoder implements MessageCoder { - - private static final HttpResultCoder instance = new HttpResultCoder(); - - public static HttpResultCoder getInstance() { - return instance; - } - - @Override - public byte[] encode(HttpResult data) { - if (data == null) return null; - byte[] contentType = MessageCoder.getBytes(data.getContentType()); - byte[] headers = MessageCoder.getBytes(data.getHeaders()); - byte[] cookies = getBytes(data.getCookies()); - byte[] content; - if (data.getResult() == null) { - content = new byte[0]; //"" - } else if (data.getResult() instanceof byte[]) { - content = (byte[]) data.getResult(); - } else if (data.getResult() instanceof CharSequence) { - content = MessageCoder.getBytes(data.getResult().toString()); - } else { - Convert cc = data.convert(); - if (cc == null) cc = JsonConvert.root(); - content = cc.convertToBytes(data.getResult()); - } - int count = 4 + 2 + contentType.length + headers.length + cookies.length + 4 + (content == null ? 0 : content.length); - final byte[] bs = new byte[count]; - ByteBuffer buffer = ByteBuffer.wrap(bs); - buffer.putInt(data.getStatus()); - buffer.putChar((char) contentType.length); - if (contentType.length > 0) buffer.put(contentType); - buffer.put(headers); - buffer.put(cookies); - if (content == null || content.length == 0) { - buffer.putInt(0); - } else { - buffer.putInt(content.length); - buffer.put(content); - } - return bs; - } - - @Override - public HttpResult decode(byte[] data) { - if (data == null) return null; - ByteBuffer buffer = ByteBuffer.wrap(data); - HttpResult result = new HttpResult(); - result.setStatus(buffer.getInt()); - result.setContentType(MessageCoder.getShortString(buffer)); - result.setHeaders(MessageCoder.getMap(buffer)); - result.setCookies(getCookieList(buffer)); - int len = buffer.getInt(); - if (len > 0) { - byte[] bs = new byte[len]; - buffer.get(bs); - result.setResult(bs); - } - return result; - } - - public static byte[] getBytes(final List list) { - if (list == null || list.isEmpty()) return new byte[2]; - final AtomicInteger len = new AtomicInteger(2); - list.forEach(cookie -> { - len.addAndGet(2 + (cookie.getName() == null ? 0 : Utility.encodeUTF8Length(cookie.getName()))); - len.addAndGet(2 + (cookie.getValue() == null ? 0 : Utility.encodeUTF8Length(cookie.getValue()))); - len.addAndGet(2 + (cookie.getDomain() == null ? 0 : Utility.encodeUTF8Length(cookie.getDomain()))); - len.addAndGet(2 + (cookie.getPath() == null ? 0 : Utility.encodeUTF8Length(cookie.getPath()))); - len.addAndGet(2 + (cookie.getPortlist() == null ? 0 : Utility.encodeUTF8Length(cookie.getPortlist()))); - len.addAndGet(8 + 1 + 1); //maxage Secure HttpOnly - }); - final byte[] bs = new byte[len.get()]; - final ByteBuffer buffer = ByteBuffer.wrap(bs); - buffer.putChar((char) list.size()); - list.forEach(cookie -> { - putShortString(buffer, cookie.getName()); - putShortString(buffer, cookie.getValue()); - putShortString(buffer, cookie.getDomain()); - putShortString(buffer, cookie.getPath()); - putShortString(buffer, cookie.getPortlist()); - buffer.putLong(cookie.getMaxAge()); - buffer.put(cookie.getSecure() ? (byte) 1 : (byte) 0); - buffer.put(cookie.isHttpOnly() ? (byte) 1 : (byte) 0); - }); - return bs; - } - - public static List getCookieList(ByteBuffer buffer) { - int len = buffer.getChar(); - if (len == 0) return null; - final List list = new ArrayList<>(len); - for (int i = 0; i < len; i++) { - HttpCookie cookie = new HttpCookie(getShortString(buffer), getShortString(buffer)); - cookie.setDomain(getShortString(buffer)); - cookie.setPath(getShortString(buffer)); - cookie.setPortlist(getShortString(buffer)); - cookie.setMaxAge(buffer.getLong()); - cookie.setSecure(buffer.get() == 1); - cookie.setHttpOnly(buffer.get() == 1); - list.add(cookie); - } - return list; - } -} +/* + * 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.mq; + +import java.net.HttpCookie; +import java.nio.ByteBuffer; +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; +import org.redkale.convert.*; +import org.redkale.convert.json.JsonConvert; +import static org.redkale.mq.MessageCoder.*; +import org.redkale.net.http.HttpResult; +import org.redkale.util.Utility; + +/** + * HttpResult鐨凪essageCoder瀹炵幇 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.1.0 + */ +public class HttpResultCoder implements MessageCoder { + + private static final HttpResultCoder instance = new HttpResultCoder(); + + public static HttpResultCoder getInstance() { + return instance; + } + + @Override + public byte[] encode(HttpResult data) { + if (data == null) return null; + byte[] contentType = MessageCoder.getBytes(data.getContentType()); + byte[] headers = MessageCoder.getBytes(data.getHeaders()); + byte[] cookies = getBytes(data.getCookies()); + byte[] content; + if (data.getResult() == null) { + content = new byte[0]; //"" + } else if (data.getResult() instanceof byte[]) { + content = (byte[]) data.getResult(); + } else if (data.getResult() instanceof CharSequence) { + content = MessageCoder.getBytes(data.getResult().toString()); + } else { + Convert cc = data.convert(); + if (cc == null) cc = JsonConvert.root(); + content = cc.convertToBytes(data.getResult()); + } + int count = 4 + 2 + contentType.length + headers.length + cookies.length + 4 + (content == null ? 0 : content.length); + final byte[] bs = new byte[count]; + ByteBuffer buffer = ByteBuffer.wrap(bs); + buffer.putInt(data.getStatus()); + buffer.putChar((char) contentType.length); + if (contentType.length > 0) buffer.put(contentType); + buffer.put(headers); + buffer.put(cookies); + if (content == null || content.length == 0) { + buffer.putInt(0); + } else { + buffer.putInt(content.length); + buffer.put(content); + } + return bs; + } + + @Override + public HttpResult decode(byte[] data) { + if (data == null) return null; + ByteBuffer buffer = ByteBuffer.wrap(data); + HttpResult result = new HttpResult(); + result.setStatus(buffer.getInt()); + result.setContentType(MessageCoder.getShortString(buffer)); + result.setHeaders(MessageCoder.getMap(buffer)); + result.setCookies(getCookieList(buffer)); + int len = buffer.getInt(); + if (len > 0) { + byte[] bs = new byte[len]; + buffer.get(bs); + result.setResult(bs); + } + return result; + } + + public static byte[] getBytes(final List list) { + if (list == null || list.isEmpty()) return new byte[2]; + final AtomicInteger len = new AtomicInteger(2); + list.forEach(cookie -> { + len.addAndGet(2 + (cookie.getName() == null ? 0 : Utility.encodeUTF8Length(cookie.getName()))); + len.addAndGet(2 + (cookie.getValue() == null ? 0 : Utility.encodeUTF8Length(cookie.getValue()))); + len.addAndGet(2 + (cookie.getDomain() == null ? 0 : Utility.encodeUTF8Length(cookie.getDomain()))); + len.addAndGet(2 + (cookie.getPath() == null ? 0 : Utility.encodeUTF8Length(cookie.getPath()))); + len.addAndGet(2 + (cookie.getPortlist() == null ? 0 : Utility.encodeUTF8Length(cookie.getPortlist()))); + len.addAndGet(8 + 1 + 1); //maxage Secure HttpOnly + }); + final byte[] bs = new byte[len.get()]; + final ByteBuffer buffer = ByteBuffer.wrap(bs); + buffer.putChar((char) list.size()); + list.forEach(cookie -> { + putShortString(buffer, cookie.getName()); + putShortString(buffer, cookie.getValue()); + putShortString(buffer, cookie.getDomain()); + putShortString(buffer, cookie.getPath()); + putShortString(buffer, cookie.getPortlist()); + buffer.putLong(cookie.getMaxAge()); + buffer.put(cookie.getSecure() ? (byte) 1 : (byte) 0); + buffer.put(cookie.isHttpOnly() ? (byte) 1 : (byte) 0); + }); + return bs; + } + + public static List getCookieList(ByteBuffer buffer) { + int len = buffer.getChar(); + if (len == 0) return null; + final List list = new ArrayList<>(len); + for (int i = 0; i < len; i++) { + HttpCookie cookie = new HttpCookie(getShortString(buffer), getShortString(buffer)); + cookie.setDomain(getShortString(buffer)); + cookie.setPath(getShortString(buffer)); + cookie.setPortlist(getShortString(buffer)); + cookie.setMaxAge(buffer.getLong()); + cookie.setSecure(buffer.get() == 1); + cookie.setHttpOnly(buffer.get() == 1); + list.add(cookie); + } + return list; + } +} diff --git a/src/main/java/org/redkale/mq/HttpSimpleRequestCoder.java b/src/main/java/org/redkale/mq/HttpSimpleRequestCoder.java index 0cbde34b6..661c4ac3e 100644 --- a/src/main/java/org/redkale/mq/HttpSimpleRequestCoder.java +++ b/src/main/java/org/redkale/mq/HttpSimpleRequestCoder.java @@ -1,117 +1,117 @@ -/* - * 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.mq; - -import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; -import org.redkale.convert.ConvertType; -import org.redkale.net.http.HttpSimpleRequest; - -/** - * HttpSimpleRequest鐨凪essageCoder瀹炵幇 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * - * @since 2.1.0 - */ -public class HttpSimpleRequestCoder implements MessageCoder { - - private static final HttpSimpleRequestCoder instance = new HttpSimpleRequestCoder(); - - public static HttpSimpleRequestCoder getInstance() { - return instance; - } - - @Override - public byte[] encode(HttpSimpleRequest data) { - byte[] requestURI = MessageCoder.getBytes(data.getRequestURI()); //long-string - byte[] path = MessageCoder.getBytes(data.getPath()); //short-string - byte[] remoteAddr = MessageCoder.getBytes(data.getRemoteAddr());//short-string - byte[] sessionid = MessageCoder.getBytes(data.getSessionid());//short-string - byte[] contentType = MessageCoder.getBytes(data.getContentType());//short-string - byte[] headers = MessageCoder.getBytes(data.getHeaders()); - byte[] params = MessageCoder.getBytes(data.getParams()); - byte[] body = MessageCoder.getBytes(data.getBody()); - byte[] userid = MessageCoder.encodeUserid(data.getCurrentUserid()); - int count = 1 //rpc - + 1 //frombody - + 4 //hashid - + 4 //reqConvertType - + 4 //respConvertType - + 4 + requestURI.length - + 2 + path.length - + 2 + remoteAddr.length - + 2 + sessionid.length - + 2 + contentType.length - + 2 + userid.length - + headers.length + params.length - + 4 + body.length; - byte[] bs = new byte[count]; - ByteBuffer buffer = ByteBuffer.wrap(bs); - buffer.put((byte) (data.isRpc() ? 'T' : 'F')); - buffer.put((byte) (data.isFrombody() ? 'T' : 'F')); - buffer.putInt(data.getHashid()); - buffer.putInt(data.getReqConvertType() == null ? 0 : data.getReqConvertType().getValue()); - buffer.putInt(data.getRespConvertType() == null ? 0 : data.getRespConvertType().getValue()); - buffer.putInt(requestURI.length); - if (requestURI.length > 0) buffer.put(requestURI); - buffer.putChar((char) path.length); - if (path.length > 0) buffer.put(path); - buffer.putChar((char) remoteAddr.length); - if (remoteAddr.length > 0) buffer.put(remoteAddr); - buffer.putChar((char) sessionid.length); - if (sessionid.length > 0) buffer.put(sessionid); - buffer.putChar((char) contentType.length); - if (contentType.length > 0) buffer.put(contentType); - buffer.putChar((char) userid.length); - if (userid.length > 0) buffer.put(userid); - buffer.put(headers); - buffer.put(params); - buffer.putInt(body.length); - if (body.length > 0) buffer.put(body); - return bs; - } - - @Override - public HttpSimpleRequest decode(byte[] data) { - if (data == null) return null; - ByteBuffer buffer = ByteBuffer.wrap(data); - HttpSimpleRequest req = new HttpSimpleRequest(); - req.setRpc(buffer.get() == 'T'); - req.setFrombody(buffer.get() == 'T'); - req.setHashid(buffer.getInt()); - int reqformat = buffer.getInt(); - int respformat = buffer.getInt(); - if (reqformat != 0) req.setReqConvertType(ConvertType.find(reqformat)); - if (respformat != 0) req.setRespConvertType(ConvertType.find(respformat)); - req.setRequestURI(MessageCoder.getLongString(buffer)); - req.setPath(MessageCoder.getShortString(buffer)); - req.setRemoteAddr(MessageCoder.getShortString(buffer)); - req.setSessionid(MessageCoder.getShortString(buffer)); - req.setContentType(MessageCoder.getShortString(buffer)); - req.setCurrentUserid(MessageCoder.decodeUserid(buffer)); - req.setHeaders(MessageCoder.getMap(buffer)); - req.setParams(MessageCoder.getMap(buffer)); - int len = buffer.getInt(); - if (len > 0) { - byte[] bs = new byte[len]; - buffer.get(bs); - req.setBody(bs); - } - return req; - } - - protected static String getString(ByteBuffer buffer) { - int len = buffer.getInt(); - if (len == 0) return null; - byte[] bs = new byte[len]; - buffer.get(bs); - return new String(bs, StandardCharsets.UTF_8); - } -} +/* + * 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.mq; + +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import org.redkale.convert.ConvertType; +import org.redkale.net.http.HttpSimpleRequest; + +/** + * HttpSimpleRequest鐨凪essageCoder瀹炵幇 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.1.0 + */ +public class HttpSimpleRequestCoder implements MessageCoder { + + private static final HttpSimpleRequestCoder instance = new HttpSimpleRequestCoder(); + + public static HttpSimpleRequestCoder getInstance() { + return instance; + } + + @Override + public byte[] encode(HttpSimpleRequest data) { + byte[] requestURI = MessageCoder.getBytes(data.getRequestURI()); //long-string + byte[] path = MessageCoder.getBytes(data.getPath()); //short-string + byte[] remoteAddr = MessageCoder.getBytes(data.getRemoteAddr());//short-string + byte[] sessionid = MessageCoder.getBytes(data.getSessionid());//short-string + byte[] contentType = MessageCoder.getBytes(data.getContentType());//short-string + byte[] headers = MessageCoder.getBytes(data.getHeaders()); + byte[] params = MessageCoder.getBytes(data.getParams()); + byte[] body = MessageCoder.getBytes(data.getBody()); + byte[] userid = MessageCoder.encodeUserid(data.getCurrentUserid()); + int count = 1 //rpc + + 1 //frombody + + 4 //hashid + + 4 //reqConvertType + + 4 //respConvertType + + 4 + requestURI.length + + 2 + path.length + + 2 + remoteAddr.length + + 2 + sessionid.length + + 2 + contentType.length + + 2 + userid.length + + headers.length + params.length + + 4 + body.length; + byte[] bs = new byte[count]; + ByteBuffer buffer = ByteBuffer.wrap(bs); + buffer.put((byte) (data.isRpc() ? 'T' : 'F')); + buffer.put((byte) (data.isFrombody() ? 'T' : 'F')); + buffer.putInt(data.getHashid()); + buffer.putInt(data.getReqConvertType() == null ? 0 : data.getReqConvertType().getValue()); + buffer.putInt(data.getRespConvertType() == null ? 0 : data.getRespConvertType().getValue()); + buffer.putInt(requestURI.length); + if (requestURI.length > 0) buffer.put(requestURI); + buffer.putChar((char) path.length); + if (path.length > 0) buffer.put(path); + buffer.putChar((char) remoteAddr.length); + if (remoteAddr.length > 0) buffer.put(remoteAddr); + buffer.putChar((char) sessionid.length); + if (sessionid.length > 0) buffer.put(sessionid); + buffer.putChar((char) contentType.length); + if (contentType.length > 0) buffer.put(contentType); + buffer.putChar((char) userid.length); + if (userid.length > 0) buffer.put(userid); + buffer.put(headers); + buffer.put(params); + buffer.putInt(body.length); + if (body.length > 0) buffer.put(body); + return bs; + } + + @Override + public HttpSimpleRequest decode(byte[] data) { + if (data == null) return null; + ByteBuffer buffer = ByteBuffer.wrap(data); + HttpSimpleRequest req = new HttpSimpleRequest(); + req.setRpc(buffer.get() == 'T'); + req.setFrombody(buffer.get() == 'T'); + req.setHashid(buffer.getInt()); + int reqformat = buffer.getInt(); + int respformat = buffer.getInt(); + if (reqformat != 0) req.setReqConvertType(ConvertType.find(reqformat)); + if (respformat != 0) req.setRespConvertType(ConvertType.find(respformat)); + req.setRequestURI(MessageCoder.getLongString(buffer)); + req.setPath(MessageCoder.getShortString(buffer)); + req.setRemoteAddr(MessageCoder.getShortString(buffer)); + req.setSessionid(MessageCoder.getShortString(buffer)); + req.setContentType(MessageCoder.getShortString(buffer)); + req.setCurrentUserid(MessageCoder.decodeUserid(buffer)); + req.setHeaders(MessageCoder.getMap(buffer)); + req.setParams(MessageCoder.getMap(buffer)); + int len = buffer.getInt(); + if (len > 0) { + byte[] bs = new byte[len]; + buffer.get(bs); + req.setBody(bs); + } + return req; + } + + protected static String getString(ByteBuffer buffer) { + int len = buffer.getInt(); + if (len == 0) return null; + byte[] bs = new byte[len]; + buffer.get(bs); + return new String(bs, StandardCharsets.UTF_8); + } +} diff --git a/src/main/java/org/redkale/mq/MessageAgent.java b/src/main/java/org/redkale/mq/MessageAgent.java index 3b6251c56..b18b8a166 100644 --- a/src/main/java/org/redkale/mq/MessageAgent.java +++ b/src/main/java/org/redkale/mq/MessageAgent.java @@ -1,318 +1,318 @@ -/* - * 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.mq; - -import java.util.*; -import java.util.concurrent.*; -import java.util.concurrent.atomic.AtomicLong; -import java.util.logging.Logger; -import java.util.stream.Collectors; -import javax.annotation.Resource; -import org.redkale.boot.*; -import static org.redkale.boot.Application.RESNAME_APP_NODEID; -import org.redkale.net.Servlet; -import org.redkale.net.http.*; -import org.redkale.net.sncp.*; -import org.redkale.service.*; -import org.redkale.util.*; - -/** - * MQ绠$悊鍣 - * - * - * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * - * @since 2.1.0 - */ -public abstract class MessageAgent { - - protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); - - @Resource(name = RESNAME_APP_NODEID) - protected int nodeid; - - protected String name; - - protected AnyValue config; - - protected MessageProducers httpProducer; - - protected MessageProducers sncpProducer; - - protected final Object httpProducerLock = new Object(); - - protected final Object sncpProducerLock = new Object(); - - protected final AtomicLong msgSeqno = new AtomicLong(System.nanoTime()); - - protected HttpMessageClient httpMessageClient; - - protected SncpMessageClient sncpMessageClient; - - protected ScheduledThreadPoolExecutor timeoutExecutor; - - protected int producerCount = 1; - - //鏈湴Service娑堟伅鎺ユ敹澶勭悊鍣紝 key:consumer - protected HashMap messageNodes = new LinkedHashMap<>(); - - public void init(AnyValue config) { - this.name = checkName(config.getValue("name", "")); - this.httpMessageClient = new HttpMessageClient(this); - this.sncpMessageClient = new SncpMessageClient(this); - this.producerCount = config.getIntValue("producers", Utility.cpus()); - // application (it doesn't execute completion handlers). - this.timeoutExecutor = (ScheduledThreadPoolExecutor) Executors.newScheduledThreadPool(1, (Runnable r) -> { - Thread t = new Thread(r); - t.setName("Redkale-MessageAgent-Timeout-Thread"); - t.setDaemon(true); - return t; - }); - this.timeoutExecutor.setRemoveOnCancelPolicy(true); - } - - public CompletableFuture> start() { - final LinkedHashMap map = new LinkedHashMap<>(); - final List futures = new ArrayList<>(); - this.messageNodes.values().forEach(node -> { - long s = System.currentTimeMillis(); - futures.add(node.consumer.startup().whenComplete((r, t) -> map.put(node.consumer.consumerid, System.currentTimeMillis() - s))); - }); - return CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()])).thenApply(r -> map); - } - - //Application.shutdown 鍦ㄦ墽琛宻erver.shutdown涔嬪墠鎵ц - public CompletableFuture stop() { - List futures = new ArrayList<>(); - this.messageNodes.values().forEach(node -> { - futures.add(node.consumer.shutdown()); - }); - return CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()])); - } - - //Application.shutdown 鍦ㄦ墍鏈塻erver.shutdown鎵ц鍚庢墽琛 - public void destroy(AnyValue config) { - this.httpMessageClient.close().join(); - this.sncpMessageClient.close().join(); - if (this.timeoutExecutor != null) this.timeoutExecutor.shutdown(); - if (this.sncpProducer != null) this.sncpProducer.shutdown().join(); - if (this.httpProducer != null) this.httpProducer.shutdown().join(); - } - - protected List getAllMessageConsumer() { - List consumers = new ArrayList<>(); - MessageConsumer one = this.httpMessageClient == null ? null : this.httpMessageClient.respConsumer; - if (one != null) consumers.add(one); - one = this.sncpMessageClient == null ? null : this.sncpMessageClient.respConsumer; - if (one != null) consumers.add(one); - consumers.addAll(messageNodes.values().stream().map(mcn -> mcn.consumer).collect(Collectors.toList())); - return consumers; - } - - protected List getAllMessageProducer() { - List producers = new ArrayList<>(); - if (this.httpProducer != null) producers.addAll(Utility.ofList(this.httpProducer.producers)); - if (this.sncpProducer != null) producers.addAll(Utility.ofList(this.sncpProducer.producers)); - MessageProducers one = this.httpMessageClient == null ? null : this.httpMessageClient.getProducer(); - if (one != null) producers.addAll(Utility.ofList(one.producers)); - one = this.sncpMessageClient == null ? null : this.sncpMessageClient.getProducer(); - if (one != null) producers.addAll(Utility.ofList(one.producers)); - return producers; - } - - public Logger getLogger() { - return logger; - } - - public String getName() { - return name; - } - - public AnyValue getConfig() { - return config; - } - - public void setConfig(AnyValue config) { - this.config = config; - } - - public HttpMessageClient getHttpMessageClient() { - return httpMessageClient; - } - - public SncpMessageClient getSncpMessageClient() { - return sncpMessageClient; - } - - protected String checkName(String name) { //涓嶈兘鍚壒娈婂瓧绗 - if (name.isEmpty()) return name; - if (name.charAt(0) >= '0' && name.charAt(0) <= '9') throw new RuntimeException("name only 0-9 a-z A-Z _ cannot begin 0-9"); - for (char ch : name.toCharArray()) { - if (!((ch >= '0' && ch <= '9') || ch == '_' || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))) { //涓嶈兘鍚壒娈婂瓧绗 - throw new RuntimeException("name only 0-9 a-z A-Z _ cannot begin 0-9"); - } - } - return name; - } - - //鑾峰彇鎸囧畾topic鐨勭敓浜у鐞嗗櫒 - public MessageProducers getSncpProducer() { - if (this.sncpProducer == null) { - synchronized (sncpProducerLock) { - if (this.sncpProducer == null) { - MessageProducer[] producers = new MessageProducer[producerCount]; - for (int i = 0; i < producers.length; i++) { - MessageProducer producer = createProducer("SncpProducer"); - producer.startup().join(); - producers[i] = producer; - } - this.sncpProducer = new MessageProducers(producers); - } - } - } - return this.sncpProducer; - } - - public MessageProducers getHttpProducer() { - if (this.httpProducer == null) { - synchronized (httpProducerLock) { - if (this.httpProducer == null) { - MessageProducer[] producers = new MessageProducer[producerCount]; - for (int i = 0; i < producers.length; i++) { - MessageProducer producer = createProducer("HttpProducer"); - producer.startup().join(); - producers[i] = producer; - } - this.httpProducer = new MessageProducers(producers); - } - } - } - return this.httpProducer; - } - - //鍒涘缓鎸囧畾topic鐨勭敓浜у鐞嗗櫒 - protected abstract MessageProducer createProducer(String name); - - //鍒涘缓topic锛屽鏋滃凡瀛樺湪鍒欒烦杩 - public abstract boolean createTopic(String... topics); - - //鍒犻櫎topic锛屽鏋滀笉瀛樺湪鍒欒烦杩 - public abstract boolean deleteTopic(String... topics); - - //鏌ヨ鎵鏈塼opic - public abstract List queryTopic(); - - //ServiceLoader鏃跺垽鏂厤缃槸鍚︾鍚堝綋鍓嶅疄鐜扮被 - public abstract boolean acceptsConf(AnyValue config); - - //鍒涘缓鎸囧畾topic鐨勬秷璐瑰鐞嗗櫒 - public abstract MessageConsumer createConsumer(String[] topics, String group, MessageProcessor processor); - - public final synchronized void putService(NodeHttpServer ns, Service service, HttpServlet servlet) { - AutoLoad al = service.getClass().getAnnotation(AutoLoad.class); - if (al != null && !al.value() && service.getClass().getAnnotation(Local.class) != null) return; - { //鏍囪@RestService(name = " ") 闇瑕佽烦杩囷紝 涓鑸綔涓烘ā鏉垮紩鎿 - RestService rest = service.getClass().getAnnotation(RestService.class); - if (rest != null && !rest.name().isEmpty() && rest.name().trim().isEmpty()) return; - } - String[] topics = generateHttpReqTopics(service); - String consumerid = generateHttpConsumerid(topics, service); - if (messageNodes.containsKey(consumerid)) throw new RuntimeException("consumerid(" + consumerid + ") is repeat"); - HttpMessageProcessor processor = new HttpMessageProcessor(this.logger, httpMessageClient, getHttpProducer(), ns, service, servlet); - this.messageNodes.put(consumerid, new MessageConsumerNode(ns, service, servlet, processor, createConsumer(topics, consumerid, processor))); - } - - public final synchronized void putService(NodeSncpServer ns, Service service, SncpServlet servlet) { - AutoLoad al = service.getClass().getAnnotation(AutoLoad.class); - if (al != null && !al.value() && service.getClass().getAnnotation(Local.class) != null) return; - String topic = generateSncpReqTopic(service); - String consumerid = generateSncpConsumerid(topic, service); - if (messageNodes.containsKey(consumerid)) throw new RuntimeException("consumerid(" + consumerid + ") is repeat"); - SncpMessageProcessor processor = new SncpMessageProcessor(this.logger, sncpMessageClient, getSncpProducer(), ns, service, servlet); - this.messageNodes.put(consumerid, new MessageConsumerNode(ns, service, servlet, processor, createConsumer(new String[]{topic}, consumerid, processor))); - } - - //鏍煎紡: sncp.req.user - public final String generateSncpReqTopic(Service service) { - if (service instanceof WebSocketNode) { - String resname = Sncp.getResourceName(service); - return "sncp.req.ws" + (resname.isEmpty() ? "" : ("-" + resname)) + ".node" + nodeid; - } - String resname = Sncp.getResourceName(service); - return "sncp.req." + Sncp.getResourceType(service).getSimpleName().replaceAll("Service.*$", "").toLowerCase() + (resname.isEmpty() ? "" : ("-" + resname)); - } - - //鏍煎紡: consumer-sncp.req.user 涓嶆彁渚涘閮ㄤ娇鐢 - protected final String generateSncpConsumerid(String topic, Service service) { - return "consumer-" + topic; - } - - //鏍煎紡: http.req.user - public static String generateHttpReqTopic(String module) { - return "http.req." + module.toLowerCase(); - } - - //鏍煎紡: http.req.user - public static String generateHttpReqTopic(String module, String resname) { - return "http.req." + module.toLowerCase() + (resname == null || resname.isEmpty() ? "" : ("-" + resname)); - } - - //鏍煎紡: sncp.resp.node10 - protected String generateSncpRespTopic() { - return "sncp.resp.node" + nodeid; - } - - //鏍煎紡: http.resp.node10 - protected String generateHttpRespTopic() { - return "http.resp.node" + nodeid; - } - - //鏍煎紡: http.req.user - protected String[] generateHttpReqTopics(Service service) { - String resname = Sncp.getResourceName(service); - String module = Rest.getRestModule(service).toLowerCase(); - MessageMultiConsumer mmc = service.getClass().getAnnotation(MessageMultiConsumer.class); - if (mmc != null) return new String[]{generateHttpReqTopic(mmc.module()) + (resname.isEmpty() ? "" : ("-" + resname))}; - return new String[]{"http.req." + module + (resname.isEmpty() ? "" : ("-" + resname))}; - } - - //鏍煎紡: consumer-http.req.user - protected String generateHttpConsumerid(String[] topics, Service service) { - String resname = Sncp.getResourceName(service); - String key = Rest.getRestModule(service).toLowerCase(); - return "consumer-http.req." + key + (resname.isEmpty() ? "" : ("-" + resname)); - - } - - //鏍煎紡: xxxx.resp.node10 - protected String generateRespTopic(String protocol) { - return protocol + ".resp.node" + nodeid; - } - - protected static class MessageConsumerNode { - - public final NodeServer server; - - public final Service service; - - public final Servlet servlet; - - public final MessageProcessor processor; - - public final MessageConsumer consumer; - - public MessageConsumerNode(NodeServer server, Service service, Servlet servlet, MessageProcessor processor, MessageConsumer consumer) { - this.server = server; - this.service = service; - this.servlet = servlet; - this.processor = processor; - this.consumer = consumer; - } - - } -} +/* + * 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.mq; + +import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicLong; +import java.util.logging.Logger; +import java.util.stream.Collectors; +import javax.annotation.Resource; +import org.redkale.boot.*; +import static org.redkale.boot.Application.RESNAME_APP_NODEID; +import org.redkale.net.Servlet; +import org.redkale.net.http.*; +import org.redkale.net.sncp.*; +import org.redkale.service.*; +import org.redkale.util.*; + +/** + * MQ绠$悊鍣 + * + * + * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.1.0 + */ +public abstract class MessageAgent { + + protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); + + @Resource(name = RESNAME_APP_NODEID) + protected int nodeid; + + protected String name; + + protected AnyValue config; + + protected MessageProducers httpProducer; + + protected MessageProducers sncpProducer; + + protected final Object httpProducerLock = new Object(); + + protected final Object sncpProducerLock = new Object(); + + protected final AtomicLong msgSeqno = new AtomicLong(System.nanoTime()); + + protected HttpMessageClient httpMessageClient; + + protected SncpMessageClient sncpMessageClient; + + protected ScheduledThreadPoolExecutor timeoutExecutor; + + protected int producerCount = 1; + + //鏈湴Service娑堟伅鎺ユ敹澶勭悊鍣紝 key:consumer + protected HashMap messageNodes = new LinkedHashMap<>(); + + public void init(AnyValue config) { + this.name = checkName(config.getValue("name", "")); + this.httpMessageClient = new HttpMessageClient(this); + this.sncpMessageClient = new SncpMessageClient(this); + this.producerCount = config.getIntValue("producers", Utility.cpus()); + // application (it doesn't execute completion handlers). + this.timeoutExecutor = (ScheduledThreadPoolExecutor) Executors.newScheduledThreadPool(1, (Runnable r) -> { + Thread t = new Thread(r); + t.setName("Redkale-MessageAgent-Timeout-Thread"); + t.setDaemon(true); + return t; + }); + this.timeoutExecutor.setRemoveOnCancelPolicy(true); + } + + public CompletableFuture> start() { + final LinkedHashMap map = new LinkedHashMap<>(); + final List futures = new ArrayList<>(); + this.messageNodes.values().forEach(node -> { + long s = System.currentTimeMillis(); + futures.add(node.consumer.startup().whenComplete((r, t) -> map.put(node.consumer.consumerid, System.currentTimeMillis() - s))); + }); + return CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()])).thenApply(r -> map); + } + + //Application.shutdown 鍦ㄦ墽琛宻erver.shutdown涔嬪墠鎵ц + public CompletableFuture stop() { + List futures = new ArrayList<>(); + this.messageNodes.values().forEach(node -> { + futures.add(node.consumer.shutdown()); + }); + return CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()])); + } + + //Application.shutdown 鍦ㄦ墍鏈塻erver.shutdown鎵ц鍚庢墽琛 + public void destroy(AnyValue config) { + this.httpMessageClient.close().join(); + this.sncpMessageClient.close().join(); + if (this.timeoutExecutor != null) this.timeoutExecutor.shutdown(); + if (this.sncpProducer != null) this.sncpProducer.shutdown().join(); + if (this.httpProducer != null) this.httpProducer.shutdown().join(); + } + + protected List getAllMessageConsumer() { + List consumers = new ArrayList<>(); + MessageConsumer one = this.httpMessageClient == null ? null : this.httpMessageClient.respConsumer; + if (one != null) consumers.add(one); + one = this.sncpMessageClient == null ? null : this.sncpMessageClient.respConsumer; + if (one != null) consumers.add(one); + consumers.addAll(messageNodes.values().stream().map(mcn -> mcn.consumer).collect(Collectors.toList())); + return consumers; + } + + protected List getAllMessageProducer() { + List producers = new ArrayList<>(); + if (this.httpProducer != null) producers.addAll(Utility.ofList(this.httpProducer.producers)); + if (this.sncpProducer != null) producers.addAll(Utility.ofList(this.sncpProducer.producers)); + MessageProducers one = this.httpMessageClient == null ? null : this.httpMessageClient.getProducer(); + if (one != null) producers.addAll(Utility.ofList(one.producers)); + one = this.sncpMessageClient == null ? null : this.sncpMessageClient.getProducer(); + if (one != null) producers.addAll(Utility.ofList(one.producers)); + return producers; + } + + public Logger getLogger() { + return logger; + } + + public String getName() { + return name; + } + + public AnyValue getConfig() { + return config; + } + + public void setConfig(AnyValue config) { + this.config = config; + } + + public HttpMessageClient getHttpMessageClient() { + return httpMessageClient; + } + + public SncpMessageClient getSncpMessageClient() { + return sncpMessageClient; + } + + protected String checkName(String name) { //涓嶈兘鍚壒娈婂瓧绗 + if (name.isEmpty()) return name; + if (name.charAt(0) >= '0' && name.charAt(0) <= '9') throw new RuntimeException("name only 0-9 a-z A-Z _ cannot begin 0-9"); + for (char ch : name.toCharArray()) { + if (!((ch >= '0' && ch <= '9') || ch == '_' || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))) { //涓嶈兘鍚壒娈婂瓧绗 + throw new RuntimeException("name only 0-9 a-z A-Z _ cannot begin 0-9"); + } + } + return name; + } + + //鑾峰彇鎸囧畾topic鐨勭敓浜у鐞嗗櫒 + public MessageProducers getSncpProducer() { + if (this.sncpProducer == null) { + synchronized (sncpProducerLock) { + if (this.sncpProducer == null) { + MessageProducer[] producers = new MessageProducer[producerCount]; + for (int i = 0; i < producers.length; i++) { + MessageProducer producer = createProducer("SncpProducer"); + producer.startup().join(); + producers[i] = producer; + } + this.sncpProducer = new MessageProducers(producers); + } + } + } + return this.sncpProducer; + } + + public MessageProducers getHttpProducer() { + if (this.httpProducer == null) { + synchronized (httpProducerLock) { + if (this.httpProducer == null) { + MessageProducer[] producers = new MessageProducer[producerCount]; + for (int i = 0; i < producers.length; i++) { + MessageProducer producer = createProducer("HttpProducer"); + producer.startup().join(); + producers[i] = producer; + } + this.httpProducer = new MessageProducers(producers); + } + } + } + return this.httpProducer; + } + + //鍒涘缓鎸囧畾topic鐨勭敓浜у鐞嗗櫒 + protected abstract MessageProducer createProducer(String name); + + //鍒涘缓topic锛屽鏋滃凡瀛樺湪鍒欒烦杩 + public abstract boolean createTopic(String... topics); + + //鍒犻櫎topic锛屽鏋滀笉瀛樺湪鍒欒烦杩 + public abstract boolean deleteTopic(String... topics); + + //鏌ヨ鎵鏈塼opic + public abstract List queryTopic(); + + //ServiceLoader鏃跺垽鏂厤缃槸鍚︾鍚堝綋鍓嶅疄鐜扮被 + public abstract boolean acceptsConf(AnyValue config); + + //鍒涘缓鎸囧畾topic鐨勬秷璐瑰鐞嗗櫒 + public abstract MessageConsumer createConsumer(String[] topics, String group, MessageProcessor processor); + + public final synchronized void putService(NodeHttpServer ns, Service service, HttpServlet servlet) { + AutoLoad al = service.getClass().getAnnotation(AutoLoad.class); + if (al != null && !al.value() && service.getClass().getAnnotation(Local.class) != null) return; + { //鏍囪@RestService(name = " ") 闇瑕佽烦杩囷紝 涓鑸綔涓烘ā鏉垮紩鎿 + RestService rest = service.getClass().getAnnotation(RestService.class); + if (rest != null && !rest.name().isEmpty() && rest.name().trim().isEmpty()) return; + } + String[] topics = generateHttpReqTopics(service); + String consumerid = generateHttpConsumerid(topics, service); + if (messageNodes.containsKey(consumerid)) throw new RuntimeException("consumerid(" + consumerid + ") is repeat"); + HttpMessageProcessor processor = new HttpMessageProcessor(this.logger, httpMessageClient, getHttpProducer(), ns, service, servlet); + this.messageNodes.put(consumerid, new MessageConsumerNode(ns, service, servlet, processor, createConsumer(topics, consumerid, processor))); + } + + public final synchronized void putService(NodeSncpServer ns, Service service, SncpServlet servlet) { + AutoLoad al = service.getClass().getAnnotation(AutoLoad.class); + if (al != null && !al.value() && service.getClass().getAnnotation(Local.class) != null) return; + String topic = generateSncpReqTopic(service); + String consumerid = generateSncpConsumerid(topic, service); + if (messageNodes.containsKey(consumerid)) throw new RuntimeException("consumerid(" + consumerid + ") is repeat"); + SncpMessageProcessor processor = new SncpMessageProcessor(this.logger, sncpMessageClient, getSncpProducer(), ns, service, servlet); + this.messageNodes.put(consumerid, new MessageConsumerNode(ns, service, servlet, processor, createConsumer(new String[]{topic}, consumerid, processor))); + } + + //鏍煎紡: sncp.req.user + public final String generateSncpReqTopic(Service service) { + if (service instanceof WebSocketNode) { + String resname = Sncp.getResourceName(service); + return "sncp.req.ws" + (resname.isEmpty() ? "" : ("-" + resname)) + ".node" + nodeid; + } + String resname = Sncp.getResourceName(service); + return "sncp.req." + Sncp.getResourceType(service).getSimpleName().replaceAll("Service.*$", "").toLowerCase() + (resname.isEmpty() ? "" : ("-" + resname)); + } + + //鏍煎紡: consumer-sncp.req.user 涓嶆彁渚涘閮ㄤ娇鐢 + protected final String generateSncpConsumerid(String topic, Service service) { + return "consumer-" + topic; + } + + //鏍煎紡: http.req.user + public static String generateHttpReqTopic(String module) { + return "http.req." + module.toLowerCase(); + } + + //鏍煎紡: http.req.user + public static String generateHttpReqTopic(String module, String resname) { + return "http.req." + module.toLowerCase() + (resname == null || resname.isEmpty() ? "" : ("-" + resname)); + } + + //鏍煎紡: sncp.resp.node10 + protected String generateSncpRespTopic() { + return "sncp.resp.node" + nodeid; + } + + //鏍煎紡: http.resp.node10 + protected String generateHttpRespTopic() { + return "http.resp.node" + nodeid; + } + + //鏍煎紡: http.req.user + protected String[] generateHttpReqTopics(Service service) { + String resname = Sncp.getResourceName(service); + String module = Rest.getRestModule(service).toLowerCase(); + MessageMultiConsumer mmc = service.getClass().getAnnotation(MessageMultiConsumer.class); + if (mmc != null) return new String[]{generateHttpReqTopic(mmc.module()) + (resname.isEmpty() ? "" : ("-" + resname))}; + return new String[]{"http.req." + module + (resname.isEmpty() ? "" : ("-" + resname))}; + } + + //鏍煎紡: consumer-http.req.user + protected String generateHttpConsumerid(String[] topics, Service service) { + String resname = Sncp.getResourceName(service); + String key = Rest.getRestModule(service).toLowerCase(); + return "consumer-http.req." + key + (resname.isEmpty() ? "" : ("-" + resname)); + + } + + //鏍煎紡: xxxx.resp.node10 + protected String generateRespTopic(String protocol) { + return protocol + ".resp.node" + nodeid; + } + + protected static class MessageConsumerNode { + + public final NodeServer server; + + public final Service service; + + public final Servlet servlet; + + public final MessageProcessor processor; + + public final MessageConsumer consumer; + + public MessageConsumerNode(NodeServer server, Service service, Servlet servlet, MessageProcessor processor, MessageConsumer consumer) { + this.server = server; + this.service = service; + this.servlet = servlet; + this.processor = processor; + this.consumer = consumer; + } + + } +} diff --git a/src/main/java/org/redkale/mq/MessageAgentProvider.java b/src/main/java/org/redkale/mq/MessageAgentProvider.java index 91a8dd932..c05570ac8 100644 --- a/src/main/java/org/redkale/mq/MessageAgentProvider.java +++ b/src/main/java/org/redkale/mq/MessageAgentProvider.java @@ -1,25 +1,25 @@ -/* - * 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.mq; - -import org.redkale.util.AnyValue; - -/** - * 鑷畾涔夌殑MessageAgent鍔犺浇鍣 - * - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @since 2.5.0 - */ -public interface MessageAgentProvider { - - public boolean acceptsConf(AnyValue config); - - public Class agentClass(); -} +/* + * 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.mq; + +import org.redkale.util.AnyValue; + +/** + * 鑷畾涔夌殑MessageAgent鍔犺浇鍣 + * + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @since 2.5.0 + */ +public interface MessageAgentProvider { + + public boolean acceptsConf(AnyValue config); + + public Class agentClass(); +} diff --git a/src/main/java/org/redkale/mq/MessageClient.java b/src/main/java/org/redkale/mq/MessageClient.java index 22beb6e50..3f0d1bfd4 100644 --- a/src/main/java/org/redkale/mq/MessageClient.java +++ b/src/main/java/org/redkale/mq/MessageClient.java @@ -1,178 +1,178 @@ -/* - * 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.mq; - -import java.nio.charset.StandardCharsets; -import java.util.concurrent.*; -import java.util.concurrent.atomic.AtomicLong; -import java.util.logging.Level; -import org.redkale.convert.Convert; -import org.redkale.convert.json.JsonConvert; -import static org.redkale.mq.MessageRecord.*; -import org.redkale.net.http.*; - -/** - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * - * @since 2.1.0 - */ -public abstract class MessageClient { - - protected final ConcurrentHashMap respNodes = new ConcurrentHashMap<>(); - - protected final MessageAgent messageAgent; - - protected final AtomicLong msgSeqno; - - protected MessageConsumer respConsumer; - - protected String respTopic; - - protected String respConsumerid; - - protected boolean finest; - - protected boolean finer; - - protected boolean fine; - - private final String clazzName; - - protected MessageClient(MessageAgent messageAgent) { - this.messageAgent = messageAgent; - this.msgSeqno = messageAgent == null ? new AtomicLong() : messageAgent.msgSeqno; - this.finest = messageAgent == null ? false : messageAgent.logger.isLoggable(Level.FINEST); - this.finer = messageAgent == null ? false : messageAgent.logger.isLoggable(Level.FINER); - this.fine = messageAgent == null ? false : messageAgent.logger.isLoggable(Level.FINE); - this.clazzName = getClass().getSimpleName(); - } - - protected CompletableFuture close() { - if (this.respConsumer == null) return CompletableFuture.completedFuture(null); - return this.respConsumer.shutdown(); - } - - protected CompletableFuture sendMessage(final MessageRecord message, boolean needresp, AtomicLong counter) { - CompletableFuture future = new CompletableFuture<>(); - try { - if (this.respConsumer == null) { - synchronized (this) { - if (this.respConsumerid == null) this.respConsumerid = "consumer-" + this.respTopic; - if (this.respConsumer == null) { - MessageProcessor processor = (msg, callback) -> { - long now = System.currentTimeMillis(); - MessageRespFutureNode node = respNodes.remove(msg.getSeqid()); - if (node == null) { - messageAgent.logger.log(Level.WARNING, MessageClient.this.getClass().getSimpleName() + " process " + msg + " error锛 not found mqresp.futurenode"); - return; - } - if (node.scheduledFuture != null) node.scheduledFuture.cancel(true); - AtomicLong ncer = node.getCounter(); - if (ncer != null) ncer.decrementAndGet(); - node.future.complete(msg); - long cha = now - msg.createtime; - if (cha > 1000 && fine) { - messageAgent.logger.log(Level.FINE, clazzName + ".MessageRespFutureNode.process (mqs.delays = " + cha + "ms, mqs.counters = " + ncer + ") mqresp.msg: " + formatRespMessage(msg)); - } else if (cha > 50 && finer) { - messageAgent.logger.log(Level.FINER, clazzName + ".MessageRespFutureNode.process (mq.delays = " + cha + "ms, mq.counters = " + ncer + ") mqresp.msg: " + formatRespMessage(msg)); - } else if (finest) { - messageAgent.logger.log(Level.FINEST, clazzName + ".MessageRespFutureNode.process (mq.delay = " + cha + "ms, mq.counter = " + ncer + ") mqresp.msg: " + formatRespMessage(msg)); - } - }; - MessageConsumer one = messageAgent.createConsumer(new String[]{respTopic}, respConsumerid, processor); - one.startup().join(); - this.respConsumer = one; - } - } - } - if (needresp && (message.getResptopic() == null || message.getResptopic().isEmpty())) { - message.setResptopic(respTopic); - } - if (counter != null) counter.incrementAndGet(); - getProducer().apply(message); - if (needresp) { - MessageRespFutureNode node = new MessageRespFutureNode(messageAgent.logger, message, respNodes, counter, future); - respNodes.put(message.getSeqid(), node); - ScheduledThreadPoolExecutor executor = messageAgent.timeoutExecutor; - if (executor != null) { - node.scheduledFuture = executor.schedule(node, 30, TimeUnit.SECONDS); - } - } else { - future.complete(null); - } - } catch (Exception ex) { - future.completeExceptionally(ex); - } finally { - return future; - } - } - - protected MessageRecord formatRespMessage(MessageRecord message) { - return message; - } - - protected abstract MessageProducers getProducer(); - - public MessageRecord createMessageRecord(String resptopic, String content) { - return new MessageRecord(msgSeqno.incrementAndGet(), CTYPE_STRING, 1, 0, System.currentTimeMillis(), 0, null, null, resptopic, content == null ? null : content.getBytes(StandardCharsets.UTF_8)); - } - - public MessageRecord createMessageRecord(String topic, String resptopic, String content) { - return new MessageRecord(msgSeqno.incrementAndGet(), CTYPE_STRING, 1, 0, System.currentTimeMillis(), 0, null, topic, resptopic, content == null ? null : content.getBytes(StandardCharsets.UTF_8)); - } - - public MessageRecord createMessageRecord(int userid, String topic, String resptopic, String content) { - return new MessageRecord(msgSeqno.incrementAndGet(), CTYPE_STRING, 1, 0, System.currentTimeMillis(), userid, null, topic, resptopic, content == null ? null : content.getBytes(StandardCharsets.UTF_8)); - } - - public MessageRecord createMessageRecord(String topic, String resptopic, Convert convert, Object bean) { - return new MessageRecord(msgSeqno.incrementAndGet(), ctype(convert, bean), 1, 0, System.currentTimeMillis(), 0, null, topic, resptopic, convert.convertToBytes(bean)); - } - - public MessageRecord createMessageRecord(int userid, String topic, String resptopic, Convert convert, Object bean) { - return new MessageRecord(msgSeqno.incrementAndGet(), ctype(convert, bean), 1, 0, System.currentTimeMillis(), userid, null, topic, resptopic, convert.convertToBytes(bean)); - } - - public MessageRecord createMessageRecord(int userid, String groupid, String topic, String resptopic, Convert convert, Object bean) { - return new MessageRecord(msgSeqno.incrementAndGet(), ctype(convert, bean), 1, 0, System.currentTimeMillis(), userid, groupid, topic, resptopic, convert.convertToBytes(bean)); - } - - public MessageRecord createMessageRecord(int flag, int userid, String groupid, String topic, String resptopic, Convert convert, Object bean) { - return new MessageRecord(msgSeqno.incrementAndGet(), ctype(convert, bean), 1, flag, System.currentTimeMillis(), userid, groupid, topic, resptopic, convert.convertToBytes(bean)); - } - - public MessageRecord createMessageRecord(String topic, String resptopic, byte[] content) { - return new MessageRecord(msgSeqno.incrementAndGet(), (byte) 0, topic, resptopic, content); - } - - public MessageRecord createMessageRecord(long seqid, String topic, String resptopic, byte[] content) { - return new MessageRecord(seqid, (byte) 0, topic, resptopic, content); - } - - protected MessageRecord createMessageRecord(byte ctype, String topic, String resptopic, byte[] content) { - return new MessageRecord(msgSeqno.incrementAndGet(), ctype, topic, resptopic, content); - } - - protected MessageRecord createMessageRecord(long seqid, byte ctype, String topic, String resptopic, byte[] content) { - return new MessageRecord(seqid, ctype, topic, resptopic, content); - } - - private byte ctype(Convert convert, Object bean) { - byte ctype = 0; - if (convert instanceof JsonConvert) { - if (bean instanceof HttpSimpleRequest) { - ctype = CTYPE_HTTP_REQUEST; - } else if (bean instanceof HttpResult) { - ctype = CTYPE_HTTP_RESULT; - } - } - return ctype; - } -} +/* + * 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.mq; + +import java.nio.charset.StandardCharsets; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicLong; +import java.util.logging.Level; +import org.redkale.convert.Convert; +import org.redkale.convert.json.JsonConvert; +import static org.redkale.mq.MessageRecord.*; +import org.redkale.net.http.*; + +/** + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.1.0 + */ +public abstract class MessageClient { + + protected final ConcurrentHashMap respNodes = new ConcurrentHashMap<>(); + + protected final MessageAgent messageAgent; + + protected final AtomicLong msgSeqno; + + protected MessageConsumer respConsumer; + + protected String respTopic; + + protected String respConsumerid; + + protected boolean finest; + + protected boolean finer; + + protected boolean fine; + + private final String clazzName; + + protected MessageClient(MessageAgent messageAgent) { + this.messageAgent = messageAgent; + this.msgSeqno = messageAgent == null ? new AtomicLong() : messageAgent.msgSeqno; + this.finest = messageAgent == null ? false : messageAgent.logger.isLoggable(Level.FINEST); + this.finer = messageAgent == null ? false : messageAgent.logger.isLoggable(Level.FINER); + this.fine = messageAgent == null ? false : messageAgent.logger.isLoggable(Level.FINE); + this.clazzName = getClass().getSimpleName(); + } + + protected CompletableFuture close() { + if (this.respConsumer == null) return CompletableFuture.completedFuture(null); + return this.respConsumer.shutdown(); + } + + protected CompletableFuture sendMessage(final MessageRecord message, boolean needresp, AtomicLong counter) { + CompletableFuture future = new CompletableFuture<>(); + try { + if (this.respConsumer == null) { + synchronized (this) { + if (this.respConsumerid == null) this.respConsumerid = "consumer-" + this.respTopic; + if (this.respConsumer == null) { + MessageProcessor processor = (msg, callback) -> { + long now = System.currentTimeMillis(); + MessageRespFutureNode node = respNodes.remove(msg.getSeqid()); + if (node == null) { + messageAgent.logger.log(Level.WARNING, MessageClient.this.getClass().getSimpleName() + " process " + msg + " error锛 not found mqresp.futurenode"); + return; + } + if (node.scheduledFuture != null) node.scheduledFuture.cancel(true); + AtomicLong ncer = node.getCounter(); + if (ncer != null) ncer.decrementAndGet(); + node.future.complete(msg); + long cha = now - msg.createtime; + if (cha > 1000 && fine) { + messageAgent.logger.log(Level.FINE, clazzName + ".MessageRespFutureNode.process (mqs.delays = " + cha + "ms, mqs.counters = " + ncer + ") mqresp.msg: " + formatRespMessage(msg)); + } else if (cha > 50 && finer) { + messageAgent.logger.log(Level.FINER, clazzName + ".MessageRespFutureNode.process (mq.delays = " + cha + "ms, mq.counters = " + ncer + ") mqresp.msg: " + formatRespMessage(msg)); + } else if (finest) { + messageAgent.logger.log(Level.FINEST, clazzName + ".MessageRespFutureNode.process (mq.delay = " + cha + "ms, mq.counter = " + ncer + ") mqresp.msg: " + formatRespMessage(msg)); + } + }; + MessageConsumer one = messageAgent.createConsumer(new String[]{respTopic}, respConsumerid, processor); + one.startup().join(); + this.respConsumer = one; + } + } + } + if (needresp && (message.getResptopic() == null || message.getResptopic().isEmpty())) { + message.setResptopic(respTopic); + } + if (counter != null) counter.incrementAndGet(); + getProducer().apply(message); + if (needresp) { + MessageRespFutureNode node = new MessageRespFutureNode(messageAgent.logger, message, respNodes, counter, future); + respNodes.put(message.getSeqid(), node); + ScheduledThreadPoolExecutor executor = messageAgent.timeoutExecutor; + if (executor != null) { + node.scheduledFuture = executor.schedule(node, 30, TimeUnit.SECONDS); + } + } else { + future.complete(null); + } + } catch (Exception ex) { + future.completeExceptionally(ex); + } finally { + return future; + } + } + + protected MessageRecord formatRespMessage(MessageRecord message) { + return message; + } + + protected abstract MessageProducers getProducer(); + + public MessageRecord createMessageRecord(String resptopic, String content) { + return new MessageRecord(msgSeqno.incrementAndGet(), CTYPE_STRING, 1, 0, System.currentTimeMillis(), 0, null, null, resptopic, content == null ? null : content.getBytes(StandardCharsets.UTF_8)); + } + + public MessageRecord createMessageRecord(String topic, String resptopic, String content) { + return new MessageRecord(msgSeqno.incrementAndGet(), CTYPE_STRING, 1, 0, System.currentTimeMillis(), 0, null, topic, resptopic, content == null ? null : content.getBytes(StandardCharsets.UTF_8)); + } + + public MessageRecord createMessageRecord(int userid, String topic, String resptopic, String content) { + return new MessageRecord(msgSeqno.incrementAndGet(), CTYPE_STRING, 1, 0, System.currentTimeMillis(), userid, null, topic, resptopic, content == null ? null : content.getBytes(StandardCharsets.UTF_8)); + } + + public MessageRecord createMessageRecord(String topic, String resptopic, Convert convert, Object bean) { + return new MessageRecord(msgSeqno.incrementAndGet(), ctype(convert, bean), 1, 0, System.currentTimeMillis(), 0, null, topic, resptopic, convert.convertToBytes(bean)); + } + + public MessageRecord createMessageRecord(int userid, String topic, String resptopic, Convert convert, Object bean) { + return new MessageRecord(msgSeqno.incrementAndGet(), ctype(convert, bean), 1, 0, System.currentTimeMillis(), userid, null, topic, resptopic, convert.convertToBytes(bean)); + } + + public MessageRecord createMessageRecord(int userid, String groupid, String topic, String resptopic, Convert convert, Object bean) { + return new MessageRecord(msgSeqno.incrementAndGet(), ctype(convert, bean), 1, 0, System.currentTimeMillis(), userid, groupid, topic, resptopic, convert.convertToBytes(bean)); + } + + public MessageRecord createMessageRecord(int flag, int userid, String groupid, String topic, String resptopic, Convert convert, Object bean) { + return new MessageRecord(msgSeqno.incrementAndGet(), ctype(convert, bean), 1, flag, System.currentTimeMillis(), userid, groupid, topic, resptopic, convert.convertToBytes(bean)); + } + + public MessageRecord createMessageRecord(String topic, String resptopic, byte[] content) { + return new MessageRecord(msgSeqno.incrementAndGet(), (byte) 0, topic, resptopic, content); + } + + public MessageRecord createMessageRecord(long seqid, String topic, String resptopic, byte[] content) { + return new MessageRecord(seqid, (byte) 0, topic, resptopic, content); + } + + protected MessageRecord createMessageRecord(byte ctype, String topic, String resptopic, byte[] content) { + return new MessageRecord(msgSeqno.incrementAndGet(), ctype, topic, resptopic, content); + } + + protected MessageRecord createMessageRecord(long seqid, byte ctype, String topic, String resptopic, byte[] content) { + return new MessageRecord(seqid, ctype, topic, resptopic, content); + } + + private byte ctype(Convert convert, Object bean) { + byte ctype = 0; + if (convert instanceof JsonConvert) { + if (bean instanceof HttpSimpleRequest) { + ctype = CTYPE_HTTP_REQUEST; + } else if (bean instanceof HttpResult) { + ctype = CTYPE_HTTP_RESULT; + } + } + return ctype; + } +} diff --git a/src/main/java/org/redkale/mq/MessageCoder.java b/src/main/java/org/redkale/mq/MessageCoder.java index 965a8111c..7f34e65aa 100644 --- a/src/main/java/org/redkale/mq/MessageCoder.java +++ b/src/main/java/org/redkale/mq/MessageCoder.java @@ -1,136 +1,136 @@ -/* - * 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.mq; - -import java.io.Serializable; -import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; -import java.util.*; -import java.util.concurrent.atomic.AtomicInteger; -import org.redkale.util.Utility; - -/** - * 灏哅essageRecord.content鍐呭鍔犺В瀵 - * - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * - * @since 2.1.0 - * - * @param 娉涘瀷 - */ -public interface MessageCoder { - - //缂栫爜 - public byte[] encode(T data); - - //瑙g爜 - public T decode(byte[] data); - - //type: 1:string, 2:int, 3:long - public static byte[] encodeUserid(Serializable value) { - if (value == null) return MessageRecord.EMPTY_BYTES; - if (value instanceof Integer) { - int val = (Integer) value; - return new byte[]{(byte) 2, (byte) (val >> 24 & 0xFF), (byte) (val >> 16 & 0xFF), (byte) (val >> 8 & 0xFF), (byte) (val & 0xFF)}; - } else if (value instanceof Long) { - long val = (Long) value; - return new byte[]{(byte) 3, (byte) (val >> 56 & 0xFF), (byte) (val >> 48 & 0xFF), (byte) (val >> 40 & 0xFF), - (byte) (val >> 32 & 0xFF), (byte) (val >> 24 & 0xFF), (byte) (val >> 16 & 0xFF), (byte) (val >> 8 & 0xFF), (byte) (val & 0xFF)}; - } - String str = value.toString(); - if (str.isEmpty()) return MessageRecord.EMPTY_BYTES; - return Utility.append(new byte[]{(byte) 1}, str.getBytes(StandardCharsets.UTF_8)); - } - - //type: 1:string, 2:int, 3:long - public static Serializable decodeUserid(ByteBuffer buffer) { - int len = buffer.getChar(); - if (len == 0) return null; - byte type = buffer.get(); - if (type == 2) return buffer.getInt(); - if (type == 3) return buffer.getLong(); - byte[] bs = new byte[len - 1]; - buffer.get(bs); - return new String(bs, StandardCharsets.UTF_8); - } - - public static byte[] getBytes(byte[] value) { - if (value == null) return MessageRecord.EMPTY_BYTES; - return value; - } - - public static byte[] getBytes(String value) { - if (value == null || value.isEmpty()) return MessageRecord.EMPTY_BYTES; - return value.getBytes(StandardCharsets.UTF_8); - } - - public static byte[] getBytes(final Map map) { - if (map == null || map.isEmpty()) return new byte[2]; - final AtomicInteger len = new AtomicInteger(2); - map.forEach((key, value) -> { - len.addAndGet(2 + (key == null ? 0 : Utility.encodeUTF8Length(key))); - len.addAndGet(4 + (value == null ? 0 : Utility.encodeUTF8Length(value))); - }); - final byte[] bs = new byte[len.get()]; - final ByteBuffer buffer = ByteBuffer.wrap(bs); - buffer.putChar((char) map.size()); - map.forEach((key, value) -> { - putShortString(buffer, key); - putLongString(buffer, value); - }); - return bs; - } - - public static void putLongString(ByteBuffer buffer, String value) { - if (value == null || value.isEmpty()) { - buffer.putInt(0); - } else { - byte[] bs = value.getBytes(StandardCharsets.UTF_8); - buffer.putInt(bs.length); - buffer.put(bs); - } - } - - public static String getLongString(ByteBuffer buffer) { - int len = buffer.getInt(); - if (len == 0) return null; - byte[] bs = new byte[len]; - buffer.get(bs); - return new String(bs, StandardCharsets.UTF_8); - } - - public static void putShortString(ByteBuffer buffer, String value) { - if (value == null || value.isEmpty()) { - buffer.putChar((char) 0); - } else { - byte[] bs = value.getBytes(StandardCharsets.UTF_8); - buffer.putChar((char) bs.length); - buffer.put(bs); - } - } - - public static String getShortString(ByteBuffer buffer) { - int len = buffer.getChar(); - if (len == 0) return null; - byte[] bs = new byte[len]; - buffer.get(bs); - return new String(bs, StandardCharsets.UTF_8); - } - - public static Map getMap(ByteBuffer buffer) { - int len = buffer.getChar(); - if (len == 0) return null; - Map map = new HashMap<>(len); - for (int i = 0; i < len; i++) { - map.put(getShortString(buffer), getLongString(buffer)); - } - return map; - } -} +/* + * 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.mq; + +import java.io.Serializable; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; +import org.redkale.util.Utility; + +/** + * 灏哅essageRecord.content鍐呭鍔犺В瀵 + * + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.1.0 + * + * @param 娉涘瀷 + */ +public interface MessageCoder { + + //缂栫爜 + public byte[] encode(T data); + + //瑙g爜 + public T decode(byte[] data); + + //type: 1:string, 2:int, 3:long + public static byte[] encodeUserid(Serializable value) { + if (value == null) return MessageRecord.EMPTY_BYTES; + if (value instanceof Integer) { + int val = (Integer) value; + return new byte[]{(byte) 2, (byte) (val >> 24 & 0xFF), (byte) (val >> 16 & 0xFF), (byte) (val >> 8 & 0xFF), (byte) (val & 0xFF)}; + } else if (value instanceof Long) { + long val = (Long) value; + return new byte[]{(byte) 3, (byte) (val >> 56 & 0xFF), (byte) (val >> 48 & 0xFF), (byte) (val >> 40 & 0xFF), + (byte) (val >> 32 & 0xFF), (byte) (val >> 24 & 0xFF), (byte) (val >> 16 & 0xFF), (byte) (val >> 8 & 0xFF), (byte) (val & 0xFF)}; + } + String str = value.toString(); + if (str.isEmpty()) return MessageRecord.EMPTY_BYTES; + return Utility.append(new byte[]{(byte) 1}, str.getBytes(StandardCharsets.UTF_8)); + } + + //type: 1:string, 2:int, 3:long + public static Serializable decodeUserid(ByteBuffer buffer) { + int len = buffer.getChar(); + if (len == 0) return null; + byte type = buffer.get(); + if (type == 2) return buffer.getInt(); + if (type == 3) return buffer.getLong(); + byte[] bs = new byte[len - 1]; + buffer.get(bs); + return new String(bs, StandardCharsets.UTF_8); + } + + public static byte[] getBytes(byte[] value) { + if (value == null) return MessageRecord.EMPTY_BYTES; + return value; + } + + public static byte[] getBytes(String value) { + if (value == null || value.isEmpty()) return MessageRecord.EMPTY_BYTES; + return value.getBytes(StandardCharsets.UTF_8); + } + + public static byte[] getBytes(final Map map) { + if (map == null || map.isEmpty()) return new byte[2]; + final AtomicInteger len = new AtomicInteger(2); + map.forEach((key, value) -> { + len.addAndGet(2 + (key == null ? 0 : Utility.encodeUTF8Length(key))); + len.addAndGet(4 + (value == null ? 0 : Utility.encodeUTF8Length(value))); + }); + final byte[] bs = new byte[len.get()]; + final ByteBuffer buffer = ByteBuffer.wrap(bs); + buffer.putChar((char) map.size()); + map.forEach((key, value) -> { + putShortString(buffer, key); + putLongString(buffer, value); + }); + return bs; + } + + public static void putLongString(ByteBuffer buffer, String value) { + if (value == null || value.isEmpty()) { + buffer.putInt(0); + } else { + byte[] bs = value.getBytes(StandardCharsets.UTF_8); + buffer.putInt(bs.length); + buffer.put(bs); + } + } + + public static String getLongString(ByteBuffer buffer) { + int len = buffer.getInt(); + if (len == 0) return null; + byte[] bs = new byte[len]; + buffer.get(bs); + return new String(bs, StandardCharsets.UTF_8); + } + + public static void putShortString(ByteBuffer buffer, String value) { + if (value == null || value.isEmpty()) { + buffer.putChar((char) 0); + } else { + byte[] bs = value.getBytes(StandardCharsets.UTF_8); + buffer.putChar((char) bs.length); + buffer.put(bs); + } + } + + public static String getShortString(ByteBuffer buffer) { + int len = buffer.getChar(); + if (len == 0) return null; + byte[] bs = new byte[len]; + buffer.get(bs); + return new String(bs, StandardCharsets.UTF_8); + } + + public static Map getMap(ByteBuffer buffer) { + int len = buffer.getChar(); + if (len == 0) return null; + Map map = new HashMap<>(len); + for (int i = 0; i < len; i++) { + map.put(getShortString(buffer), getLongString(buffer)); + } + return map; + } +} diff --git a/src/main/java/org/redkale/mq/MessageConsumer.java b/src/main/java/org/redkale/mq/MessageConsumer.java index 2488d7165..a1ffd20e3 100644 --- a/src/main/java/org/redkale/mq/MessageConsumer.java +++ b/src/main/java/org/redkale/mq/MessageConsumer.java @@ -1,63 +1,63 @@ -/* - * 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.mq; - -import java.util.Objects; -import java.util.concurrent.CompletableFuture; -import java.util.logging.Logger; - -/** - * - *

- * 璇︽儏瑙: https://redkale.org - * - * - * @author zhangjx - * - * @since 2.1.0 - */ -public abstract class MessageConsumer { - - protected final String[] topics; - - protected final String consumerid; - - protected MessageAgent messageAgent; - - protected final MessageProcessor processor; - - protected final Logger logger; - - protected volatile boolean closed; - - protected MessageConsumer(MessageAgent messageAgent, String[] topics, final String consumerid, MessageProcessor processor) { - Objects.requireNonNull(messageAgent); - Objects.requireNonNull(topics); - Objects.requireNonNull(consumerid); - Objects.requireNonNull(processor); - this.messageAgent = messageAgent; - this.logger = messageAgent.logger; - this.topics = topics; - this.consumerid = consumerid; - this.processor = processor; - } - - public MessageProcessor getProcessor() { - return processor; - } - - public String[] getTopics() { - return topics; - } - - public abstract CompletableFuture startup(); - - public boolean isClosed() { - return closed; - } - - public abstract CompletableFuture shutdown(); -} +/* + * 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.mq; + +import java.util.Objects; +import java.util.concurrent.CompletableFuture; +import java.util.logging.Logger; + +/** + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * + * @author zhangjx + * + * @since 2.1.0 + */ +public abstract class MessageConsumer { + + protected final String[] topics; + + protected final String consumerid; + + protected MessageAgent messageAgent; + + protected final MessageProcessor processor; + + protected final Logger logger; + + protected volatile boolean closed; + + protected MessageConsumer(MessageAgent messageAgent, String[] topics, final String consumerid, MessageProcessor processor) { + Objects.requireNonNull(messageAgent); + Objects.requireNonNull(topics); + Objects.requireNonNull(consumerid); + Objects.requireNonNull(processor); + this.messageAgent = messageAgent; + this.logger = messageAgent.logger; + this.topics = topics; + this.consumerid = consumerid; + this.processor = processor; + } + + public MessageProcessor getProcessor() { + return processor; + } + + public String[] getTopics() { + return topics; + } + + public abstract CompletableFuture startup(); + + public boolean isClosed() { + return closed; + } + + public abstract CompletableFuture shutdown(); +} diff --git a/src/main/java/org/redkale/mq/MessageMultiConsumer.java b/src/main/java/org/redkale/mq/MessageMultiConsumer.java index 78a54392c..51a825a56 100644 --- a/src/main/java/org/redkale/mq/MessageMultiConsumer.java +++ b/src/main/java/org/redkale/mq/MessageMultiConsumer.java @@ -1,61 +1,61 @@ -/* - * 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.mq; - -import java.lang.annotation.*; -import static java.lang.annotation.ElementType.*; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * 澶氭秷璐圭粍锛岄渶瑕佸悓 @RestService 涓璧蜂娇鐢 - *

- * 閫氬父涓涓猼opic鍙細琚竴涓猂estService娑堣垂锛 褰撲竴涓猼opic闇瑕佽鍏朵粬RestService娑堣垂鏃讹紝灏遍渶瑕佷娇鐢@MessageMultiConsumer - * - *

- * @RestService(name = "user", comment = "鐢ㄦ埛鏈嶅姟")
- * public class UserService implements Service{
- *
- *      @RestMapping(comment = "鐢ㄦ埛鐧诲綍")
- *      public RetResult login(LoginBean bean){
- *          //do something
- *      }
- * }
- * 
- * - * 闇姹傦細缁熻鐢ㄦ埛鐧诲綍娆℃暟锛 鍙互鍒涘缓涓涓狹essageMultiConsumer 鐨 RestService锛 - *
- * @MessageMultiConsumer(module = "user") 
- * @RestService(name = "loginstat", comment = "鐢ㄦ埛缁熻鏈嶅姟")
- * public class LoginStatService implements Service{
- *
- *      private LongAdder counter = new LongAdder();
- *
- *      @RestMapping(name = "login", comment = "鐢ㄦ埛鐧诲綍缁熻")
- *      public void stat(LoginBean bean){     //鍙傛暟蹇呴』鍜孶serService.login鏂规硶涓鑷
- *          counter.increment();
- *      }
- * }
- * 
- * - *

- * 娉細 鏍囪 @MessageMultiConsumer 鐨凷ervice鐨@RestMapping鏂规硶閮藉彧鑳芥槸void杩斿洖绫诲瀷 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * - * @author zhangjx - * - * @since 2.1.0 - */ -@Inherited -@Documented -@Target({TYPE}) -@Retention(RUNTIME) -public @interface MessageMultiConsumer { - - String module(); -} +/* + * 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.mq; + +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * 澶氭秷璐圭粍锛岄渶瑕佸悓 @RestService 涓璧蜂娇鐢 + *

+ * 閫氬父涓涓猼opic鍙細琚竴涓猂estService娑堣垂锛 褰撲竴涓猼opic闇瑕佽鍏朵粬RestService娑堣垂鏃讹紝灏遍渶瑕佷娇鐢@MessageMultiConsumer + * + *

+ * @RestService(name = "user", comment = "鐢ㄦ埛鏈嶅姟")
+ * public class UserService implements Service{
+ *
+ *      @RestMapping(comment = "鐢ㄦ埛鐧诲綍")
+ *      public RetResult login(LoginBean bean){
+ *          //do something
+ *      }
+ * }
+ * 
+ * + * 闇姹傦細缁熻鐢ㄦ埛鐧诲綍娆℃暟锛 鍙互鍒涘缓涓涓狹essageMultiConsumer 鐨 RestService锛 + *
+ * @MessageMultiConsumer(module = "user") 
+ * @RestService(name = "loginstat", comment = "鐢ㄦ埛缁熻鏈嶅姟")
+ * public class LoginStatService implements Service{
+ *
+ *      private LongAdder counter = new LongAdder();
+ *
+ *      @RestMapping(name = "login", comment = "鐢ㄦ埛鐧诲綍缁熻")
+ *      public void stat(LoginBean bean){     //鍙傛暟蹇呴』鍜孶serService.login鏂规硶涓鑷
+ *          counter.increment();
+ *      }
+ * }
+ * 
+ * + *

+ * 娉細 鏍囪 @MessageMultiConsumer 鐨凷ervice鐨@RestMapping鏂规硶閮藉彧鑳芥槸void杩斿洖绫诲瀷 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * + * @author zhangjx + * + * @since 2.1.0 + */ +@Inherited +@Documented +@Target({TYPE}) +@Retention(RUNTIME) +public @interface MessageMultiConsumer { + + String module(); +} diff --git a/src/main/java/org/redkale/mq/MessageProcessor.java b/src/main/java/org/redkale/mq/MessageProcessor.java index 79ac2042a..288c0fb06 100644 --- a/src/main/java/org/redkale/mq/MessageProcessor.java +++ b/src/main/java/org/redkale/mq/MessageProcessor.java @@ -1,27 +1,27 @@ -/* - * 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.mq; - -/** - * 涓涓猄ervice瀵瑰簲涓涓狹essageProcessor - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * - * @since 2.1.0 - */ -public interface MessageProcessor { - - default void begin(int size, long starttime) { - } - - public void process(MessageRecord message, Runnable callback); - - default void commit() { - } -} +/* + * 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.mq; + +/** + * 涓涓猄ervice瀵瑰簲涓涓狹essageProcessor + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.1.0 + */ +public interface MessageProcessor { + + default void begin(int size, long starttime) { + } + + public void process(MessageRecord message, Runnable callback); + + default void commit() { + } +} diff --git a/src/main/java/org/redkale/mq/MessageProducer.java b/src/main/java/org/redkale/mq/MessageProducer.java index 41de2cd03..dcbabecc6 100644 --- a/src/main/java/org/redkale/mq/MessageProducer.java +++ b/src/main/java/org/redkale/mq/MessageProducer.java @@ -1,42 +1,42 @@ -/* - * 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.mq; - -import java.util.concurrent.CompletableFuture; -import java.util.logging.Logger; - -/** - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * - * @since 2.1.0 - */ -public abstract class MessageProducer { - - protected final Logger logger; - - protected final String name; - - protected volatile boolean closed; - - protected MessageProducer(String name, Logger logger) { - this.name = name; - this.logger = logger; - } - - public abstract CompletableFuture apply(MessageRecord message); - - public abstract CompletableFuture startup(); - - public boolean isClosed() { - return closed; - } - - public abstract CompletableFuture shutdown(); -} +/* + * 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.mq; + +import java.util.concurrent.CompletableFuture; +import java.util.logging.Logger; + +/** + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.1.0 + */ +public abstract class MessageProducer { + + protected final Logger logger; + + protected final String name; + + protected volatile boolean closed; + + protected MessageProducer(String name, Logger logger) { + this.name = name; + this.logger = logger; + } + + public abstract CompletableFuture apply(MessageRecord message); + + public abstract CompletableFuture startup(); + + public boolean isClosed() { + return closed; + } + + public abstract CompletableFuture shutdown(); +} diff --git a/src/main/java/org/redkale/mq/MessageProducers.java b/src/main/java/org/redkale/mq/MessageProducers.java index 2f8afd31a..91a0507c8 100644 --- a/src/main/java/org/redkale/mq/MessageProducers.java +++ b/src/main/java/org/redkale/mq/MessageProducers.java @@ -1,62 +1,62 @@ -/* - * 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.mq; - -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * - * @since 2.1.0 - */ -public class MessageProducers { - - protected final MessageProducer[] producers; - - protected final AtomicInteger index = new AtomicInteger(); - - public MessageProducers(MessageProducer[] producers) { - this.producers = producers; - } - - public MessageProducer getProducer(MessageRecord message) { - if (this.producers.length == 1) return this.producers[0]; - int hash = index.incrementAndGet(); - if (index.get() > 1000 * producers.length) { - synchronized (index) { - if (index.get() > 1000 * producers.length) { - index.addAndGet(-1000 * producers.length); - } - } - } - return producers[hash % producers.length]; - } - - public CompletableFuture apply(MessageRecord message) { - return getProducer(message).apply(message); - } - - public CompletableFuture startup() { - CompletableFuture[] futures = new CompletableFuture[producers.length]; - for (int i = 0; i < producers.length; i++) { - futures[i] = producers[i].startup(); - } - return CompletableFuture.allOf(futures); - } - - public CompletableFuture shutdown() { - CompletableFuture[] futures = new CompletableFuture[producers.length]; - for (int i = 0; i < producers.length; i++) { - futures[i] = producers[i].shutdown(); - } - return CompletableFuture.allOf(futures); - } -} +/* + * 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.mq; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.1.0 + */ +public class MessageProducers { + + protected final MessageProducer[] producers; + + protected final AtomicInteger index = new AtomicInteger(); + + public MessageProducers(MessageProducer[] producers) { + this.producers = producers; + } + + public MessageProducer getProducer(MessageRecord message) { + if (this.producers.length == 1) return this.producers[0]; + int hash = index.incrementAndGet(); + if (index.get() > 1000 * producers.length) { + synchronized (index) { + if (index.get() > 1000 * producers.length) { + index.addAndGet(-1000 * producers.length); + } + } + } + return producers[hash % producers.length]; + } + + public CompletableFuture apply(MessageRecord message) { + return getProducer(message).apply(message); + } + + public CompletableFuture startup() { + CompletableFuture[] futures = new CompletableFuture[producers.length]; + for (int i = 0; i < producers.length; i++) { + futures[i] = producers[i].startup(); + } + return CompletableFuture.allOf(futures); + } + + public CompletableFuture shutdown() { + CompletableFuture[] futures = new CompletableFuture[producers.length]; + for (int i = 0; i < producers.length; i++) { + futures[i] = producers[i].shutdown(); + } + return CompletableFuture.allOf(futures); + } +} diff --git a/src/main/java/org/redkale/mq/MessageRecord.java b/src/main/java/org/redkale/mq/MessageRecord.java index 5634ab430..2d78af8f7 100644 --- a/src/main/java/org/redkale/mq/MessageRecord.java +++ b/src/main/java/org/redkale/mq/MessageRecord.java @@ -1,308 +1,308 @@ -/* - * 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.mq; - -import java.io.Serializable; -import java.nio.charset.StandardCharsets; -import org.redkale.convert.*; -import org.redkale.convert.bson.BsonConvert; -import org.redkale.convert.json.JsonConvert; -import org.redkale.net.http.HttpSimpleRequest; -import org.redkale.net.sncp.SncpRequest; -import org.redkale.util.Comment; - -/** - * 瀛樺湪MQ閲岄潰鐨勬暟鎹粨鏋

- * groupid + userid 鏉ョ‘瀹歱artition锛 浼樺厛浣跨敤 groupid - * - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * - * @since 2.1.0 - */ -public class MessageRecord implements Serializable { - - static final byte[] EMPTY_BYTES = new byte[0]; - - protected static final byte CTYPE_STRING = 1; - - protected static final byte CTYPE_HTTP_REQUEST = 2; - - protected static final byte CTYPE_HTTP_RESULT = 3; - - protected static final byte CTYPE_BSON_RESULT = 4; - - @ConvertColumn(index = 1) - @Comment("娑堟伅搴忓垪鍙") - protected long seqid; - - @ConvertColumn(index = 2) - @Comment("鐗堟湰") - protected int version; - - @ConvertColumn(index = 3) - @Comment("鏍囪浣, 鑷畾涔夋椂浣跨敤") - protected int flag; - - @ConvertColumn(index = 4) - @Comment("鍒涘缓鏃堕棿") - protected long createtime; - - @ConvertColumn(index = 5) - @Comment("鐢ㄦ埛ID锛屾棤鐢ㄦ埛淇℃伅瑙嗕负null鎴0, 鍏蜂綋鏁版嵁绫诲瀷鍙兘鏄痠nt銆乴ong銆丼tring") //@since 2.5.0 鐢眎nt鏀规垚Serializable - protected Serializable userid; - - @ConvertColumn(index = 6) - @Comment("缁処D") - protected String groupid; - - @ConvertColumn(index = 7) - @Comment("褰撳墠topic") - protected String topic; - - @ConvertColumn(index = 8) - @Comment("鐩爣topic, 涓虹┖琛ㄧず鏃犵洰鏍噒opic") - protected String resptopic; - - @ConvertColumn(index = 9) - @Comment("娑堟伅鍐呭") - protected byte[] content; - - @ConvertColumn(index = 10) - @Comment("娑堟伅鍐呭鐨勭被鍨") - protected byte ctype; - - @Comment("鏈湴闄勫姞瀵硅薄锛屼笉浼氳搴忓垪鍖") - protected Object localattach; - - public MessageRecord() { - } - - protected MessageRecord(long seqid, byte ctype, String topic, String resptopic, byte[] content) { - this(seqid, ctype, 1, 0, System.currentTimeMillis(), 0, null, topic, resptopic, content); - } - - protected MessageRecord(long seqid, byte ctype, int flag, Serializable userid, String groupid, String topic, String resptopic, byte[] content) { - this(seqid, ctype, 1, flag, System.currentTimeMillis(), userid, groupid, topic, resptopic, content); - } - - protected MessageRecord(long seqid, byte ctype, int version, int flag, long createtime, Serializable userid, String groupid, String topic, String resptopic, byte[] content) { - this.seqid = seqid; - this.ctype = ctype; - this.version = version; - this.flag = flag; - this.createtime = createtime; - this.userid = userid; - this.groupid = groupid; - this.topic = topic; - this.resptopic = resptopic; - this.content = content; - } - - public String contentString() { - return content == null ? null : new String(content, StandardCharsets.UTF_8); - } - - public MessageRecord attach(Object attach) { - this.localattach = attach; - return this; - } - - @ConvertDisabled - public boolean isEmptyTopic() { - return this.topic == null || this.topic.isEmpty(); - } - - @ConvertDisabled - public boolean isEmptyResptopic() { - return this.resptopic == null || this.resptopic.isEmpty(); - } - - public T convertFromContent(Convert convert, java.lang.reflect.Type type) { - if (this.content == null || this.content.length == 0) return null; - return (T) convert.convertFrom(type, this.content); - } - - public T decodeContent(MessageCoder coder) { - if (this.content == null || this.content.length == 0) return null; - return (T) coder.decode(this.content); - } - - public MessageRecord encodeContent(MessageCoder coder, T data) { - this.content = coder.encode(data); - return this; - } - - public int hash() { - if (groupid != null && !groupid.isEmpty()) { - return groupid.hashCode(); - } else if (userid != null) { - return userid.hashCode(); - } else { - return 0; - } - } - - public MessageRecord version(int version) { - this.version = version; - return this; - } - - public MessageRecord flag(int flag) { - this.flag = flag; - return this; - } - - public MessageRecord createtime(long createtime) { - this.createtime = createtime; - return this; - } - - public MessageRecord userid(Serializable userid) { - this.userid = userid; - return this; - } - - public MessageRecord groupid(String groupid) { - this.groupid = groupid; - return this; - } - - public MessageRecord topic(String topic) { - this.topic = topic; - return this; - } - - public MessageRecord resptopic(String resptopic) { - this.resptopic = resptopic; - return this; - } - - public MessageRecord content(byte[] content) { - this.content = content; - return this; - } - - public MessageRecord contentString(String content) { - this.content = content == null ? null : content.getBytes(StandardCharsets.UTF_8); - return this; - } - - public long getSeqid() { - return seqid; - } - - public void setSeqid(long seqid) { - this.seqid = seqid; - } - - public int getVersion() { - return version; - } - - public void setVersion(int version) { - this.version = version; - } - - public int getFlag() { - return flag; - } - - public void setFlag(int flag) { - this.flag = flag; - } - - public long getCreatetime() { - return createtime; - } - - public void setCreatetime(long createtime) { - this.createtime = createtime; - } - - public Serializable getUserid() { - return userid; - } - - public void setUserid(Serializable userid) { - this.userid = userid; - } - - public String getGroupid() { - return groupid; - } - - public void setGroupid(String groupid) { - this.groupid = groupid; - } - - public String getTopic() { - return topic; - } - - public void setTopic(String topic) { - this.topic = topic; - } - - public String getResptopic() { - return resptopic; - } - - public void setResptopic(String resptopic) { - this.resptopic = resptopic; - } - - public byte[] getContent() { - return content; - } - - public void setContent(byte[] content) { - this.content = content; - } - - @Override - public String toString() { - //return JsonConvert.root().convertTo(this); - StringBuilder sb = new StringBuilder(128); - sb.append("{\"seqid\":").append(this.seqid); - sb.append(",\"version\":").append(this.version); - if (this.flag != 0) sb.append(",\"flag\":").append(this.flag); - if (this.createtime != 0) sb.append(",\"createtime\":").append(this.createtime); - if (this.userid != null) sb.append(",\"userid\":").append(this.userid); - if (this.groupid != null) sb.append(",\"groupid\":\"").append(this.groupid).append("\""); - if (this.topic != null) sb.append(",\"topic\":\"").append(this.topic).append("\""); - if (this.resptopic != null) sb.append(",\"resptopic\":\"").append(this.resptopic).append("\""); - if (this.content != null) { - if (this.ctype == CTYPE_BSON_RESULT && this.content.length > SncpRequest.HEADER_SIZE) { - int offset = SncpRequest.HEADER_SIZE + 1; //寰幆鍗犱綅绗 - Object rs = BsonConvert.root().convertFrom(Object.class, this.content, offset, this.content.length - offset); - sb.append(",\"content\":").append(rs); - } else if (this.ctype == CTYPE_HTTP_REQUEST) { - HttpSimpleRequest req = HttpSimpleRequestCoder.getInstance().decode(this.content); - if (req != null) { - if (req.getCurrentUserid() == null) req.setCurrentUserid(this.userid); - if (req.getHashid() == 0) req.setHashid(this.hash()); - } - sb.append(",\"content\":").append(req); - } else if (this.ctype == CTYPE_HTTP_RESULT) { - sb.append(",\"content\":").append(HttpResultCoder.getInstance().decode(this.content)); - } else if (localattach != null) { - sb.append(",\"attach\":").append(JsonConvert.root().convertTo(localattach)); - } else { - sb.append(",\"content\":\"").append(new String(this.content, StandardCharsets.UTF_8)).append("\""); - } - } - sb.append("}"); - return sb.toString(); - } - -// public static void main(String[] args) throws Throwable { -// System.out.println(new MessageRecord(333, 2, 3, null, "tt", null, "xxx".getBytes())); -// } -} +/* + * 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.mq; + +import java.io.Serializable; +import java.nio.charset.StandardCharsets; +import org.redkale.convert.*; +import org.redkale.convert.bson.BsonConvert; +import org.redkale.convert.json.JsonConvert; +import org.redkale.net.http.HttpSimpleRequest; +import org.redkale.net.sncp.SncpRequest; +import org.redkale.util.Comment; + +/** + * 瀛樺湪MQ閲岄潰鐨勬暟鎹粨鏋

+ * groupid + userid 鏉ョ‘瀹歱artition锛 浼樺厛浣跨敤 groupid + * + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.1.0 + */ +public class MessageRecord implements Serializable { + + static final byte[] EMPTY_BYTES = new byte[0]; + + protected static final byte CTYPE_STRING = 1; + + protected static final byte CTYPE_HTTP_REQUEST = 2; + + protected static final byte CTYPE_HTTP_RESULT = 3; + + protected static final byte CTYPE_BSON_RESULT = 4; + + @ConvertColumn(index = 1) + @Comment("娑堟伅搴忓垪鍙") + protected long seqid; + + @ConvertColumn(index = 2) + @Comment("鐗堟湰") + protected int version; + + @ConvertColumn(index = 3) + @Comment("鏍囪浣, 鑷畾涔夋椂浣跨敤") + protected int flag; + + @ConvertColumn(index = 4) + @Comment("鍒涘缓鏃堕棿") + protected long createtime; + + @ConvertColumn(index = 5) + @Comment("鐢ㄦ埛ID锛屾棤鐢ㄦ埛淇℃伅瑙嗕负null鎴0, 鍏蜂綋鏁版嵁绫诲瀷鍙兘鏄痠nt銆乴ong銆丼tring") //@since 2.5.0 鐢眎nt鏀规垚Serializable + protected Serializable userid; + + @ConvertColumn(index = 6) + @Comment("缁処D") + protected String groupid; + + @ConvertColumn(index = 7) + @Comment("褰撳墠topic") + protected String topic; + + @ConvertColumn(index = 8) + @Comment("鐩爣topic, 涓虹┖琛ㄧず鏃犵洰鏍噒opic") + protected String resptopic; + + @ConvertColumn(index = 9) + @Comment("娑堟伅鍐呭") + protected byte[] content; + + @ConvertColumn(index = 10) + @Comment("娑堟伅鍐呭鐨勭被鍨") + protected byte ctype; + + @Comment("鏈湴闄勫姞瀵硅薄锛屼笉浼氳搴忓垪鍖") + protected Object localattach; + + public MessageRecord() { + } + + protected MessageRecord(long seqid, byte ctype, String topic, String resptopic, byte[] content) { + this(seqid, ctype, 1, 0, System.currentTimeMillis(), 0, null, topic, resptopic, content); + } + + protected MessageRecord(long seqid, byte ctype, int flag, Serializable userid, String groupid, String topic, String resptopic, byte[] content) { + this(seqid, ctype, 1, flag, System.currentTimeMillis(), userid, groupid, topic, resptopic, content); + } + + protected MessageRecord(long seqid, byte ctype, int version, int flag, long createtime, Serializable userid, String groupid, String topic, String resptopic, byte[] content) { + this.seqid = seqid; + this.ctype = ctype; + this.version = version; + this.flag = flag; + this.createtime = createtime; + this.userid = userid; + this.groupid = groupid; + this.topic = topic; + this.resptopic = resptopic; + this.content = content; + } + + public String contentString() { + return content == null ? null : new String(content, StandardCharsets.UTF_8); + } + + public MessageRecord attach(Object attach) { + this.localattach = attach; + return this; + } + + @ConvertDisabled + public boolean isEmptyTopic() { + return this.topic == null || this.topic.isEmpty(); + } + + @ConvertDisabled + public boolean isEmptyResptopic() { + return this.resptopic == null || this.resptopic.isEmpty(); + } + + public T convertFromContent(Convert convert, java.lang.reflect.Type type) { + if (this.content == null || this.content.length == 0) return null; + return (T) convert.convertFrom(type, this.content); + } + + public T decodeContent(MessageCoder coder) { + if (this.content == null || this.content.length == 0) return null; + return (T) coder.decode(this.content); + } + + public MessageRecord encodeContent(MessageCoder coder, T data) { + this.content = coder.encode(data); + return this; + } + + public int hash() { + if (groupid != null && !groupid.isEmpty()) { + return groupid.hashCode(); + } else if (userid != null) { + return userid.hashCode(); + } else { + return 0; + } + } + + public MessageRecord version(int version) { + this.version = version; + return this; + } + + public MessageRecord flag(int flag) { + this.flag = flag; + return this; + } + + public MessageRecord createtime(long createtime) { + this.createtime = createtime; + return this; + } + + public MessageRecord userid(Serializable userid) { + this.userid = userid; + return this; + } + + public MessageRecord groupid(String groupid) { + this.groupid = groupid; + return this; + } + + public MessageRecord topic(String topic) { + this.topic = topic; + return this; + } + + public MessageRecord resptopic(String resptopic) { + this.resptopic = resptopic; + return this; + } + + public MessageRecord content(byte[] content) { + this.content = content; + return this; + } + + public MessageRecord contentString(String content) { + this.content = content == null ? null : content.getBytes(StandardCharsets.UTF_8); + return this; + } + + public long getSeqid() { + return seqid; + } + + public void setSeqid(long seqid) { + this.seqid = seqid; + } + + public int getVersion() { + return version; + } + + public void setVersion(int version) { + this.version = version; + } + + public int getFlag() { + return flag; + } + + public void setFlag(int flag) { + this.flag = flag; + } + + public long getCreatetime() { + return createtime; + } + + public void setCreatetime(long createtime) { + this.createtime = createtime; + } + + public Serializable getUserid() { + return userid; + } + + public void setUserid(Serializable userid) { + this.userid = userid; + } + + public String getGroupid() { + return groupid; + } + + public void setGroupid(String groupid) { + this.groupid = groupid; + } + + public String getTopic() { + return topic; + } + + public void setTopic(String topic) { + this.topic = topic; + } + + public String getResptopic() { + return resptopic; + } + + public void setResptopic(String resptopic) { + this.resptopic = resptopic; + } + + public byte[] getContent() { + return content; + } + + public void setContent(byte[] content) { + this.content = content; + } + + @Override + public String toString() { + //return JsonConvert.root().convertTo(this); + StringBuilder sb = new StringBuilder(128); + sb.append("{\"seqid\":").append(this.seqid); + sb.append(",\"version\":").append(this.version); + if (this.flag != 0) sb.append(",\"flag\":").append(this.flag); + if (this.createtime != 0) sb.append(",\"createtime\":").append(this.createtime); + if (this.userid != null) sb.append(",\"userid\":").append(this.userid); + if (this.groupid != null) sb.append(",\"groupid\":\"").append(this.groupid).append("\""); + if (this.topic != null) sb.append(",\"topic\":\"").append(this.topic).append("\""); + if (this.resptopic != null) sb.append(",\"resptopic\":\"").append(this.resptopic).append("\""); + if (this.content != null) { + if (this.ctype == CTYPE_BSON_RESULT && this.content.length > SncpRequest.HEADER_SIZE) { + int offset = SncpRequest.HEADER_SIZE + 1; //寰幆鍗犱綅绗 + Object rs = BsonConvert.root().convertFrom(Object.class, this.content, offset, this.content.length - offset); + sb.append(",\"content\":").append(rs); + } else if (this.ctype == CTYPE_HTTP_REQUEST) { + HttpSimpleRequest req = HttpSimpleRequestCoder.getInstance().decode(this.content); + if (req != null) { + if (req.getCurrentUserid() == null) req.setCurrentUserid(this.userid); + if (req.getHashid() == 0) req.setHashid(this.hash()); + } + sb.append(",\"content\":").append(req); + } else if (this.ctype == CTYPE_HTTP_RESULT) { + sb.append(",\"content\":").append(HttpResultCoder.getInstance().decode(this.content)); + } else if (localattach != null) { + sb.append(",\"attach\":").append(JsonConvert.root().convertTo(localattach)); + } else { + sb.append(",\"content\":\"").append(new String(this.content, StandardCharsets.UTF_8)).append("\""); + } + } + sb.append("}"); + return sb.toString(); + } + +// public static void main(String[] args) throws Throwable { +// System.out.println(new MessageRecord(333, 2, 3, null, "tt", null, "xxx".getBytes())); +// } +} diff --git a/src/main/java/org/redkale/mq/MessageRecordCoder.java b/src/main/java/org/redkale/mq/MessageRecordCoder.java index 736075572..34f0bd239 100644 --- a/src/main/java/org/redkale/mq/MessageRecordCoder.java +++ b/src/main/java/org/redkale/mq/MessageRecordCoder.java @@ -1,94 +1,94 @@ -/* - * 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.mq; - -import java.io.Serializable; -import java.nio.ByteBuffer; - -/** - * MessageRecord鐨凪essageCoder瀹炵幇 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * - * @since 2.1.0 - */ -public class MessageRecordCoder implements MessageCoder { - - private static final MessageRecordCoder instance = new MessageRecordCoder(); - - public static MessageRecordCoder getInstance() { - return instance; - } - - @Override - public byte[] encode(MessageRecord data) { - if (data == null) return null; - byte[] stopics = MessageCoder.getBytes(data.getTopic()); - byte[] dtopics = MessageCoder.getBytes(data.getResptopic()); - byte[] groupid = MessageCoder.getBytes(data.getGroupid()); - byte[] userid = MessageCoder.encodeUserid(data.getUserid()); - int count = 8 //seqid - + 1 //ctype - + 4 //version - + 4 //flag - + 8 //createtime - + 2 + userid.length - + 2 + groupid.length - + 2 + stopics.length - + 2 + dtopics.length - + 4 + (data.getContent() == null ? 0 : data.getContent().length); - final byte[] bs = new byte[count]; - ByteBuffer buffer = ByteBuffer.wrap(bs); - buffer.putLong(data.getSeqid()); - buffer.put(data.ctype); - buffer.putInt(data.getVersion()); - buffer.putInt(data.getFlag()); - buffer.putLong(data.getCreatetime()); - buffer.putChar((char) userid.length); - if (userid.length > 0) buffer.put(userid); - buffer.putChar((char) groupid.length); - if (groupid.length > 0) buffer.put(groupid); - buffer.putChar((char) stopics.length); - if (stopics.length > 0) buffer.put(stopics); - buffer.putChar((char) dtopics.length); - if (dtopics.length > 0) buffer.put(dtopics); - if (data.getContent() == null) { - buffer.putInt(0); - } else { - buffer.putInt(data.getContent().length); - buffer.put(data.getContent()); - } - return bs; - } - - @Override - public MessageRecord decode(byte[] data) { - if (data == null) return null; - ByteBuffer buffer = ByteBuffer.wrap(data); - long seqid = buffer.getLong(); - byte ctype = buffer.get(); - int version = buffer.getInt(); - int flag = buffer.getInt(); - long createtime = buffer.getLong(); - - Serializable userid = MessageCoder.decodeUserid(buffer); - String groupid = MessageCoder.getShortString(buffer); - String topic = MessageCoder.getShortString(buffer); - String resptopic = MessageCoder.getShortString(buffer); - - byte[] content = null; - int contentlen = buffer.getInt(); - if (contentlen > 0) { - content = new byte[contentlen]; - buffer.get(content); - } - return new MessageRecord(seqid, ctype, version, flag, createtime, userid, groupid, topic, resptopic, content); - } - -} +/* + * 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.mq; + +import java.io.Serializable; +import java.nio.ByteBuffer; + +/** + * MessageRecord鐨凪essageCoder瀹炵幇 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.1.0 + */ +public class MessageRecordCoder implements MessageCoder { + + private static final MessageRecordCoder instance = new MessageRecordCoder(); + + public static MessageRecordCoder getInstance() { + return instance; + } + + @Override + public byte[] encode(MessageRecord data) { + if (data == null) return null; + byte[] stopics = MessageCoder.getBytes(data.getTopic()); + byte[] dtopics = MessageCoder.getBytes(data.getResptopic()); + byte[] groupid = MessageCoder.getBytes(data.getGroupid()); + byte[] userid = MessageCoder.encodeUserid(data.getUserid()); + int count = 8 //seqid + + 1 //ctype + + 4 //version + + 4 //flag + + 8 //createtime + + 2 + userid.length + + 2 + groupid.length + + 2 + stopics.length + + 2 + dtopics.length + + 4 + (data.getContent() == null ? 0 : data.getContent().length); + final byte[] bs = new byte[count]; + ByteBuffer buffer = ByteBuffer.wrap(bs); + buffer.putLong(data.getSeqid()); + buffer.put(data.ctype); + buffer.putInt(data.getVersion()); + buffer.putInt(data.getFlag()); + buffer.putLong(data.getCreatetime()); + buffer.putChar((char) userid.length); + if (userid.length > 0) buffer.put(userid); + buffer.putChar((char) groupid.length); + if (groupid.length > 0) buffer.put(groupid); + buffer.putChar((char) stopics.length); + if (stopics.length > 0) buffer.put(stopics); + buffer.putChar((char) dtopics.length); + if (dtopics.length > 0) buffer.put(dtopics); + if (data.getContent() == null) { + buffer.putInt(0); + } else { + buffer.putInt(data.getContent().length); + buffer.put(data.getContent()); + } + return bs; + } + + @Override + public MessageRecord decode(byte[] data) { + if (data == null) return null; + ByteBuffer buffer = ByteBuffer.wrap(data); + long seqid = buffer.getLong(); + byte ctype = buffer.get(); + int version = buffer.getInt(); + int flag = buffer.getInt(); + long createtime = buffer.getLong(); + + Serializable userid = MessageCoder.decodeUserid(buffer); + String groupid = MessageCoder.getShortString(buffer); + String topic = MessageCoder.getShortString(buffer); + String resptopic = MessageCoder.getShortString(buffer); + + byte[] content = null; + int contentlen = buffer.getInt(); + if (contentlen > 0) { + content = new byte[contentlen]; + buffer.get(content); + } + return new MessageRecord(seqid, ctype, version, flag, createtime, userid, groupid, topic, resptopic, content); + } + +} diff --git a/src/main/java/org/redkale/mq/MessageRespFutureNode.java b/src/main/java/org/redkale/mq/MessageRespFutureNode.java index 65d794bd5..a25946c08 100644 --- a/src/main/java/org/redkale/mq/MessageRespFutureNode.java +++ b/src/main/java/org/redkale/mq/MessageRespFutureNode.java @@ -1,73 +1,73 @@ -/* - * 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.mq; - -import java.util.concurrent.*; -import java.util.concurrent.atomic.AtomicLong; -import java.util.logging.*; - -/** - * MQ绠$悊鍣 - * - * - * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * - * @since 2.1.0 - */ -public class MessageRespFutureNode implements Runnable { - - protected final long seqid; - - protected final long createtime; - - protected final AtomicLong counter; - - protected final CompletableFuture future; - - protected final Logger logger; - - protected final MessageRecord message; - - protected final ConcurrentHashMap respNodes; - - protected ScheduledFuture scheduledFuture; - - public MessageRespFutureNode(Logger logger, MessageRecord message, ConcurrentHashMap respNodes, AtomicLong counter, CompletableFuture future) { - this.logger = logger; - this.message = message; - this.seqid = message.getSeqid(); - this.respNodes = respNodes; - this.counter = counter; - this.future = future; - this.createtime = System.currentTimeMillis(); - } - - @Override //瓒呮椂鍚庤timeoutExecutor璋冪敤 - public void run() { //timeout - respNodes.remove(this.seqid); - future.completeExceptionally(new TimeoutException()); - logger.log(Level.WARNING, getClass().getSimpleName() + " wait msg: " + message + " timeout " + (System.currentTimeMillis() - createtime) + "ms" - + (message.userid != null || (message.groupid != null && !message.groupid.isEmpty()) ? (message.userid != null ? (", userid:" + message.userid) : (", groupid:" + message.groupid)) : "")); - } - - public long getSeqid() { - return seqid; - } - - public long getCreatetime() { - return createtime; - } - - public AtomicLong getCounter() { - return counter; - } - - public CompletableFuture getFuture() { - return future; - } -} +/* + * 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.mq; + +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicLong; +import java.util.logging.*; + +/** + * MQ绠$悊鍣 + * + * + * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.1.0 + */ +public class MessageRespFutureNode implements Runnable { + + protected final long seqid; + + protected final long createtime; + + protected final AtomicLong counter; + + protected final CompletableFuture future; + + protected final Logger logger; + + protected final MessageRecord message; + + protected final ConcurrentHashMap respNodes; + + protected ScheduledFuture scheduledFuture; + + public MessageRespFutureNode(Logger logger, MessageRecord message, ConcurrentHashMap respNodes, AtomicLong counter, CompletableFuture future) { + this.logger = logger; + this.message = message; + this.seqid = message.getSeqid(); + this.respNodes = respNodes; + this.counter = counter; + this.future = future; + this.createtime = System.currentTimeMillis(); + } + + @Override //瓒呮椂鍚庤timeoutExecutor璋冪敤 + public void run() { //timeout + respNodes.remove(this.seqid); + future.completeExceptionally(new TimeoutException()); + logger.log(Level.WARNING, getClass().getSimpleName() + " wait msg: " + message + " timeout " + (System.currentTimeMillis() - createtime) + "ms" + + (message.userid != null || (message.groupid != null && !message.groupid.isEmpty()) ? (message.userid != null ? (", userid:" + message.userid) : (", groupid:" + message.groupid)) : "")); + } + + public long getSeqid() { + return seqid; + } + + public long getCreatetime() { + return createtime; + } + + public AtomicLong getCounter() { + return counter; + } + + public CompletableFuture getFuture() { + return future; + } +} diff --git a/src/main/java/org/redkale/mq/MessageResponse.java b/src/main/java/org/redkale/mq/MessageResponse.java index 24cfe5258..0dab904b3 100644 --- a/src/main/java/org/redkale/mq/MessageResponse.java +++ b/src/main/java/org/redkale/mq/MessageResponse.java @@ -1,20 +1,20 @@ -/* - * 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.mq; - -/** - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * - * @since 2.1.0 - */ -public interface MessageResponse { - - public void finish(MessageRecord message); -} +/* + * 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.mq; + +/** + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.1.0 + */ +public interface MessageResponse { + + public void finish(MessageRecord message); +} diff --git a/src/main/java/org/redkale/mq/SncpMessageClient.java b/src/main/java/org/redkale/mq/SncpMessageClient.java index 839fb1444..471961769 100644 --- a/src/main/java/org/redkale/mq/SncpMessageClient.java +++ b/src/main/java/org/redkale/mq/SncpMessageClient.java @@ -1,61 +1,61 @@ -/* - * 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.mq; - -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.atomic.AtomicLong; - -/** - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * - * @since 2.1.0 - */ -public class SncpMessageClient extends MessageClient { - - protected SncpMessageClient(MessageAgent messageAgent) { - super(messageAgent); - this.respTopic = messageAgent.generateSncpRespTopic(); - } - - @Override - protected MessageProducers getProducer() { - return messageAgent.getSncpProducer(); - } - - public String getRespTopic() { - return this.respTopic; - } - - //鍙彂閫佹秷鎭紝涓嶉渶瑕佸搷搴 - public final void produceMessage(MessageRecord message) { - produceMessage(message, null); - } - - //鍙彂閫佹秷鎭紝涓嶉渶瑕佸搷搴 - public final void produceMessage(MessageRecord message, AtomicLong counter) { - sendMessage(message, false, counter); - } - - //鍙戦佹秷鎭紝闇瑕佸搷搴 - public final CompletableFuture sendMessage(MessageRecord message) { - return sendMessage(message, null); - } - - //鍙戦佹秷鎭紝闇瑕佸搷搴 - public final CompletableFuture sendMessage(MessageRecord message, AtomicLong counter) { - return sendMessage(message, true, counter); - } - - @Override - protected MessageRecord formatRespMessage(MessageRecord message) { - if (message != null) message.ctype = MessageRecord.CTYPE_BSON_RESULT; - return message; - } -} +/* + * 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.mq; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicLong; + +/** + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.1.0 + */ +public class SncpMessageClient extends MessageClient { + + protected SncpMessageClient(MessageAgent messageAgent) { + super(messageAgent); + this.respTopic = messageAgent.generateSncpRespTopic(); + } + + @Override + protected MessageProducers getProducer() { + return messageAgent.getSncpProducer(); + } + + public String getRespTopic() { + return this.respTopic; + } + + //鍙彂閫佹秷鎭紝涓嶉渶瑕佸搷搴 + public final void produceMessage(MessageRecord message) { + produceMessage(message, null); + } + + //鍙彂閫佹秷鎭紝涓嶉渶瑕佸搷搴 + public final void produceMessage(MessageRecord message, AtomicLong counter) { + sendMessage(message, false, counter); + } + + //鍙戦佹秷鎭紝闇瑕佸搷搴 + public final CompletableFuture sendMessage(MessageRecord message) { + return sendMessage(message, null); + } + + //鍙戦佹秷鎭紝闇瑕佸搷搴 + public final CompletableFuture sendMessage(MessageRecord message, AtomicLong counter) { + return sendMessage(message, true, counter); + } + + @Override + protected MessageRecord formatRespMessage(MessageRecord message) { + if (message != null) message.ctype = MessageRecord.CTYPE_BSON_RESULT; + return message; + } +} diff --git a/src/main/java/org/redkale/mq/SncpMessageProcessor.java b/src/main/java/org/redkale/mq/SncpMessageProcessor.java index 1ed3090fe..8174f0544 100644 --- a/src/main/java/org/redkale/mq/SncpMessageProcessor.java +++ b/src/main/java/org/redkale/mq/SncpMessageProcessor.java @@ -1,127 +1,127 @@ -/* - * 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.mq; - -import java.util.concurrent.*; -import java.util.logging.*; -import org.redkale.boot.NodeSncpServer; -import org.redkale.net.sncp.*; -import org.redkale.service.Service; - -/** - * 涓涓猄ervice瀵瑰簲涓涓狹essageProcessor - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * - * @since 2.1.0 - */ -public class SncpMessageProcessor implements MessageProcessor { - - protected final boolean finest; - - protected final boolean finer; - - protected final boolean fine; - - protected final Logger logger; - - protected MessageClient messageClient; - - protected final MessageProducers producer; - - protected final NodeSncpServer server; - - protected final Service service; - - protected final SncpServlet servlet; - - protected CountDownLatch cdl; - - protected long starttime; - - protected final Runnable innerCallback = () -> { - if (cdl != null) cdl.countDown(); - }; - - public SncpMessageProcessor(Logger logger, SncpMessageClient messageClient, MessageProducers producer, NodeSncpServer server, Service service, SncpServlet servlet) { - this.logger = logger; - this.finest = logger.isLoggable(Level.FINEST); - this.finer = logger.isLoggable(Level.FINER); - this.fine = logger.isLoggable(Level.FINE); - this.messageClient = messageClient; - this.producer = producer; - this.server = server; - this.service = service; - this.servlet = servlet; - } - - @Override - public void begin(final int size, long starttime) { - this.starttime = starttime; - this.cdl = new CountDownLatch(size); - } - - @Override - public void process(final MessageRecord message, final Runnable callback) { - execute(message, innerCallback); - } - - private void execute(final MessageRecord message, final Runnable callback) { - SncpMessageResponse response = null; - try { - long now = System.currentTimeMillis(); - long cha = now - message.createtime; - long e = now - starttime; - SncpContext context = server.getSncpServer().getContext(); - SncpMessageRequest request = new SncpMessageRequest(context, message); - response = new SncpMessageResponse(context, request, callback, messageClient, producer.getProducer(message)); - - context.execute(servlet, request, response); - long o = System.currentTimeMillis() - now; - if ((cha > 1000 || e > 100 || o > 1000) && fine) { - logger.log(Level.FINE, "SncpMessageProcessor.process (mqs.delays = " + cha + " ms, mqs.blocks = " + e + " ms, mqs.executes = " + o + " ms) message: " + message); - } else if ((cha > 50 || e > 10 || o > 50) && finer) { - logger.log(Level.FINER, "SncpMessageProcessor.process (mq.delays = " + cha + " ms, mq.blocks = " + e + " ms, mq.executes = " + o + " ms) message: " + message); - } else if (finest) { - logger.log(Level.FINEST, "SncpMessageProcessor.process (mq.delay = " + cha + " ms, mq.block = " + e + " ms, mq.execute = " + o + " ms) message: " + message); - } - } catch (Throwable ex) { - if (response != null) response.finish(SncpResponse.RETCODE_ILLSERVICEID, null); - logger.log(Level.SEVERE, SncpMessageProcessor.class.getSimpleName() + " process error, message=" + message, ex instanceof CompletionException ? ((CompletionException) ex).getCause() : ex); - } - } - - @Override - public void commit() { - if (this.cdl != null) { - try { - this.cdl.await(30, TimeUnit.SECONDS); - } catch (Exception ex) { - } - this.cdl = null; - } - } - - public MessageProducers getProducer() { - return producer; - } - - public NodeSncpServer getServer() { - return server; - } - - public Service getService() { - return service; - } - - public SncpServlet getServlet() { - return servlet; - } - -} +/* + * 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.mq; + +import java.util.concurrent.*; +import java.util.logging.*; +import org.redkale.boot.NodeSncpServer; +import org.redkale.net.sncp.*; +import org.redkale.service.Service; + +/** + * 涓涓猄ervice瀵瑰簲涓涓狹essageProcessor + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.1.0 + */ +public class SncpMessageProcessor implements MessageProcessor { + + protected final boolean finest; + + protected final boolean finer; + + protected final boolean fine; + + protected final Logger logger; + + protected MessageClient messageClient; + + protected final MessageProducers producer; + + protected final NodeSncpServer server; + + protected final Service service; + + protected final SncpServlet servlet; + + protected CountDownLatch cdl; + + protected long starttime; + + protected final Runnable innerCallback = () -> { + if (cdl != null) cdl.countDown(); + }; + + public SncpMessageProcessor(Logger logger, SncpMessageClient messageClient, MessageProducers producer, NodeSncpServer server, Service service, SncpServlet servlet) { + this.logger = logger; + this.finest = logger.isLoggable(Level.FINEST); + this.finer = logger.isLoggable(Level.FINER); + this.fine = logger.isLoggable(Level.FINE); + this.messageClient = messageClient; + this.producer = producer; + this.server = server; + this.service = service; + this.servlet = servlet; + } + + @Override + public void begin(final int size, long starttime) { + this.starttime = starttime; + this.cdl = new CountDownLatch(size); + } + + @Override + public void process(final MessageRecord message, final Runnable callback) { + execute(message, innerCallback); + } + + private void execute(final MessageRecord message, final Runnable callback) { + SncpMessageResponse response = null; + try { + long now = System.currentTimeMillis(); + long cha = now - message.createtime; + long e = now - starttime; + SncpContext context = server.getSncpServer().getContext(); + SncpMessageRequest request = new SncpMessageRequest(context, message); + response = new SncpMessageResponse(context, request, callback, messageClient, producer.getProducer(message)); + + context.execute(servlet, request, response); + long o = System.currentTimeMillis() - now; + if ((cha > 1000 || e > 100 || o > 1000) && fine) { + logger.log(Level.FINE, "SncpMessageProcessor.process (mqs.delays = " + cha + " ms, mqs.blocks = " + e + " ms, mqs.executes = " + o + " ms) message: " + message); + } else if ((cha > 50 || e > 10 || o > 50) && finer) { + logger.log(Level.FINER, "SncpMessageProcessor.process (mq.delays = " + cha + " ms, mq.blocks = " + e + " ms, mq.executes = " + o + " ms) message: " + message); + } else if (finest) { + logger.log(Level.FINEST, "SncpMessageProcessor.process (mq.delay = " + cha + " ms, mq.block = " + e + " ms, mq.execute = " + o + " ms) message: " + message); + } + } catch (Throwable ex) { + if (response != null) response.finish(SncpResponse.RETCODE_ILLSERVICEID, null); + logger.log(Level.SEVERE, SncpMessageProcessor.class.getSimpleName() + " process error, message=" + message, ex instanceof CompletionException ? ((CompletionException) ex).getCause() : ex); + } + } + + @Override + public void commit() { + if (this.cdl != null) { + try { + this.cdl.await(30, TimeUnit.SECONDS); + } catch (Exception ex) { + } + this.cdl = null; + } + } + + public MessageProducers getProducer() { + return producer; + } + + public NodeSncpServer getServer() { + return server; + } + + public Service getService() { + return service; + } + + public SncpServlet getServlet() { + return servlet; + } + +} diff --git a/src/main/java/org/redkale/mq/SncpMessageRequest.java b/src/main/java/org/redkale/mq/SncpMessageRequest.java index 548e5735e..75b6639a6 100644 --- a/src/main/java/org/redkale/mq/SncpMessageRequest.java +++ b/src/main/java/org/redkale/mq/SncpMessageRequest.java @@ -1,45 +1,45 @@ -/* - * 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.mq; - -import java.nio.ByteBuffer; -import java.util.logging.Level; -import java.util.logging.Logger; -import org.redkale.net.sncp.*; -import org.redkale.util.Utility; - -/** - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * - * @since 2.1.0 - */ -public class SncpMessageRequest extends SncpRequest { - - protected MessageRecord message; - - @SuppressWarnings("OverridableMethodCallInConstructor") - public SncpMessageRequest(SncpContext context, MessageRecord message) { - super(context); - this.message = message; - this.hashid = this.message.hash(); - this.createtime = System.currentTimeMillis(); - readHeader(ByteBuffer.wrap(message.getContent()), null); - } - - @Override //琚玈ncpAsyncHandler.sncp_setParams璋冪敤 - protected void sncp_setParams(SncpDynServlet.SncpServletAction action, Logger logger, Object... params) { - if (message.localattach != null) return; - if (logger.isLoggable(Level.FINER)) { - message.attach(Utility.append(new Object[]{action.actionName()}, params)); - } else { - message.attach(params); - } - } -} +/* + * 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.mq; + +import java.nio.ByteBuffer; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.redkale.net.sncp.*; +import org.redkale.util.Utility; + +/** + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.1.0 + */ +public class SncpMessageRequest extends SncpRequest { + + protected MessageRecord message; + + @SuppressWarnings("OverridableMethodCallInConstructor") + public SncpMessageRequest(SncpContext context, MessageRecord message) { + super(context); + this.message = message; + this.hashid = this.message.hash(); + this.createtime = System.currentTimeMillis(); + readHeader(ByteBuffer.wrap(message.getContent()), null); + } + + @Override //琚玈ncpAsyncHandler.sncp_setParams璋冪敤 + protected void sncp_setParams(SncpDynServlet.SncpServletAction action, Logger logger, Object... params) { + if (message.localattach != null) return; + if (logger.isLoggable(Level.FINER)) { + message.attach(Utility.append(new Object[]{action.actionName()}, params)); + } else { + message.attach(params); + } + } +} diff --git a/src/main/java/org/redkale/mq/SncpMessageResponse.java b/src/main/java/org/redkale/mq/SncpMessageResponse.java index 07dc3f457..78d935754 100644 --- a/src/main/java/org/redkale/mq/SncpMessageResponse.java +++ b/src/main/java/org/redkale/mq/SncpMessageResponse.java @@ -1,62 +1,62 @@ -/* - * 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.mq; - -import org.redkale.convert.bson.BsonWriter; -import org.redkale.net.sncp.*; -import static org.redkale.net.sncp.SncpRequest.HEADER_SIZE; -import org.redkale.util.ByteArray; - -/** - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * - * @since 2.1.0 - */ -public class SncpMessageResponse extends SncpResponse { - - protected MessageClient messageClient; - - protected MessageRecord message; - - protected MessageProducer producer; - - protected Runnable callback; - - public SncpMessageResponse(SncpContext context, SncpMessageRequest request, Runnable callback, MessageClient messageClient, MessageProducer producer) { - super(context, request); - this.message = request.message; - this.callback = callback; - this.messageClient = messageClient; - this.producer = producer; - } - - public SncpMessageResponse(SncpContext context, MessageRecord message, Runnable callback, MessageClient messageClient, MessageProducer producer) { - super(context, new SncpMessageRequest(context, message)); - this.message = message; - this.callback = callback; - this.messageClient = messageClient; - this.producer = producer; - } - - @Override - public void finish(final int retcode, final BsonWriter out) { - if (callback != null) callback.run(); - if (out == null) { - final ByteArray result = new ByteArray(SncpRequest.HEADER_SIZE); - fillHeader(result, 0, retcode); - producer.apply(messageClient.createMessageRecord(message.getSeqid(), message.getResptopic(), null, (byte[]) null)); - return; - } - final int respBodyLength = out.count(); //body鎬婚暱搴 - final ByteArray result = out.toByteArray(); - fillHeader(result, respBodyLength - HEADER_SIZE, retcode); - producer.apply(messageClient.createMessageRecord(message.getSeqid(), message.getResptopic(), null, result.getBytes())); - } -} +/* + * 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.mq; + +import org.redkale.convert.bson.BsonWriter; +import org.redkale.net.sncp.*; +import static org.redkale.net.sncp.SncpRequest.HEADER_SIZE; +import org.redkale.util.ByteArray; + +/** + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.1.0 + */ +public class SncpMessageResponse extends SncpResponse { + + protected MessageClient messageClient; + + protected MessageRecord message; + + protected MessageProducer producer; + + protected Runnable callback; + + public SncpMessageResponse(SncpContext context, SncpMessageRequest request, Runnable callback, MessageClient messageClient, MessageProducer producer) { + super(context, request); + this.message = request.message; + this.callback = callback; + this.messageClient = messageClient; + this.producer = producer; + } + + public SncpMessageResponse(SncpContext context, MessageRecord message, Runnable callback, MessageClient messageClient, MessageProducer producer) { + super(context, new SncpMessageRequest(context, message)); + this.message = message; + this.callback = callback; + this.messageClient = messageClient; + this.producer = producer; + } + + @Override + public void finish(final int retcode, final BsonWriter out) { + if (callback != null) callback.run(); + if (out == null) { + final ByteArray result = new ByteArray(SncpRequest.HEADER_SIZE); + fillHeader(result, 0, retcode); + producer.apply(messageClient.createMessageRecord(message.getSeqid(), message.getResptopic(), null, (byte[]) null)); + return; + } + final int respBodyLength = out.count(); //body鎬婚暱搴 + final ByteArray result = out.toByteArray(); + fillHeader(result, respBodyLength - HEADER_SIZE, retcode); + producer.apply(messageClient.createMessageRecord(message.getSeqid(), message.getResptopic(), null, result.getBytes())); + } +} diff --git a/src/main/java/org/redkale/net/AsyncConnection.java b/src/main/java/org/redkale/net/AsyncConnection.java index e403b15bd..ec06a7df4 100644 --- a/src/main/java/org/redkale/net/AsyncConnection.java +++ b/src/main/java/org/redkale/net/AsyncConnection.java @@ -1,947 +1,947 @@ -/* - * 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; - -import java.io.*; -import java.net.*; -import java.nio.*; -import java.nio.channels.*; -import java.util.*; -import java.util.concurrent.atomic.*; -import java.util.function.*; -import javax.net.ssl.*; -import javax.net.ssl.SSLEngineResult.HandshakeStatus; -import static javax.net.ssl.SSLEngineResult.Status.*; -import static javax.net.ssl.SSLEngineResult.HandshakeStatus.*; -import org.redkale.util.*; - -/** - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public abstract class AsyncConnection implements ChannelContext, Channel, AutoCloseable { - - private static final ByteBuffer EMPTY_BUFFER = ByteBuffer.allocate(0); - - //SSL - protected SSLEngine sslEngine; - - protected volatile long readtime; - - protected volatile long writetime; - - private Map attributes; //鐢ㄤ簬瀛樺偍缁戝畾鍦–onnection涓婄殑瀵硅薄闆嗗悎 - - private Object subobject; //鐢ㄤ簬瀛樺偍缁戝畾鍦–onnection涓婄殑瀵硅薄锛 鍚宎ttributes锛 鍙粦瀹氬崟涓璞℃椂灏介噺浣跨敤subobject鑰岄潪attributes - - protected final AsyncGroup ioGroup; - - protected final AsyncThread ioThread; - - protected final boolean client; - - protected final int bufferCapacity; - - private final Supplier bufferSupplier; - - private final Consumer bufferConsumer; - - private ByteBufferWriter pipelineWriter; - - private PipelineDataNode pipelineDataNode; - - private ByteBuffer readBuffer; - - private ByteBuffer readSSLHalfBuffer; - - //鍦ㄧ嚎鏁 - private LongAdder livingCounter; - - //鍏抽棴鏁 - private LongAdder closedCounter; - - private Consumer beforeCloseListener; - - //鍏宠仈鐨勪簨浠舵暟锛 灏忎簬1琛ㄧず娌℃湁浜嬩欢 - private final AtomicInteger eventing = new AtomicInteger(); - - //鐢ㄤ簬鏈嶅姟绔殑Socket, 绛夊悓浜庝竴鐩村瓨鍦ㄧ殑readCompletionHandler - ProtocolCodec protocolCodec; - - protected AsyncConnection(boolean client, AsyncGroup ioGroup, AsyncThread ioThread, final int bufferCapacity, ObjectPool bufferPool, - SSLBuilder sslBuilder, SSLContext sslContext, final LongAdder livingCounter, final LongAdder closedCounter) { - this(client, ioGroup, ioThread, bufferCapacity, bufferPool, bufferPool, sslBuilder, sslContext, livingCounter, closedCounter); - } - - protected AsyncConnection(boolean client, AsyncGroup ioGroup, AsyncThread ioThread, final int bufferCapacity, Supplier bufferSupplier, - Consumer bufferConsumer, SSLBuilder sslBuilder, SSLContext sslContext, final LongAdder livingCounter, final LongAdder closedCounter) { - Objects.requireNonNull(bufferSupplier); - Objects.requireNonNull(bufferConsumer); - this.client = client; - this.ioGroup = ioGroup; - this.ioThread = ioThread; - this.bufferCapacity = bufferCapacity; - this.bufferSupplier = bufferSupplier; - this.bufferConsumer = bufferConsumer; - this.livingCounter = livingCounter; - this.closedCounter = closedCounter; - if (client) { //client妯″紡涓嬫棤SSLBuilder - if (sslContext != null) { - if (sslBuilder != null) { - this.sslEngine = sslBuilder.createSSLEngine(sslContext, client); - } else { - this.sslEngine = sslContext.createSSLEngine(); - } - } - } else { - if (sslBuilder != null && sslContext != null) { - this.sslEngine = sslBuilder.createSSLEngine(sslContext, client); - } - } - } - - public Supplier getBufferSupplier() { - return this.bufferSupplier; - } - - public Consumer getBufferConsumer() { - return this.bufferConsumer; - } - - public final long getLastReadTime() { - return readtime; - } - - public final long getLastWriteTime() { - return writetime; - } - - public final boolean ssl() { - return sslEngine != null; - } - - public final int increEventing() { - return eventing.incrementAndGet(); - } - - public final int decreEventing() { - return eventing.decrementAndGet(); - } - - public final void execute(Runnable command) { - ioThread.execute(command); - } - - public final boolean inCurrThread() { - return ioThread.inCurrThread(); - } - - public final AsyncThread getAsyncThread() { - return ioThread; - } - - @Override - public abstract boolean isOpen(); - - public abstract boolean isTCP(); - - public abstract boolean shutdownInput(); - - public abstract boolean shutdownOutput(); - - public abstract boolean setOption(SocketOption name, T value); - - public abstract Set> supportedOptions(); - - public abstract SocketAddress getRemoteAddress(); - - public abstract SocketAddress getLocalAddress(); - - public abstract int getReadTimeoutSeconds(); - - public abstract int getWriteTimeoutSeconds(); - - public abstract void setReadTimeoutSeconds(int readTimeoutSeconds); - - public abstract void setWriteTimeoutSeconds(int writeTimeoutSeconds); - - protected abstract void readImpl(CompletionHandler handler); - - //src鍐欏畬鎵嶄細鍥炶皟 - protected abstract void writeImpl(ByteBuffer src, A attachment, CompletionHandler handler); - - //srcs鍐欏畬鎵嶄細鍥炶皟 - protected abstract void writeImpl(ByteBuffer[] srcs, int offset, int length, A attachment, CompletionHandler handler); - - protected void startRead(CompletionHandler handler) { - read(handler); - } - - public final void read(CompletionHandler handler) { - if (sslEngine == null) { - readImpl(handler); - } else { - sslReadImpl(false, handler); - } - } - - //src鍐欏畬鎵嶄細鍥炶皟 - public final void write(ByteBuffer src, A attachment, CompletionHandler handler) { - if (sslEngine == null) { - writeImpl(src, attachment, handler); - } else { - try { - int remain = src.remaining(); - sslWriteImpl(false, src, t -> { - if (t == null) { - handler.completed(remain - src.remaining(), attachment); - } else { - handler.failed(t, attachment); - } - }); - } catch (SSLException e) { - handler.failed(e, attachment); - } - } - } - - //srcs鍐欏畬鎵嶄細鍥炶皟 - public final void write(ByteBuffer[] srcs, int offset, int length, A attachment, CompletionHandler handler) { - if (sslEngine == null) { - writeImpl(srcs, offset, length, attachment, handler); - } else { - try { - int remain = ByteBufferReader.remaining(srcs, offset, length); - sslWriteImpl(false, srcs, offset, length, t -> { - if (t == null) { - handler.completed(remain - ByteBufferReader.remaining(srcs, offset, length), attachment); - } else { - handler.failed(t, attachment); - } - }); - } catch (SSLException e) { - handler.failed(e, attachment); - } - } - } - - //srcs鍐欏畬鎵嶄細鍥炶皟 - public final void write(ByteBuffer[] srcs, A attachment, CompletionHandler handler) { - write(srcs, 0, srcs.length, attachment, handler); - } - - public final void write(byte[] bytes, CompletionHandler handler) { - write(bytes, 0, bytes.length, null, 0, 0, null, null, handler); - } - - public final void write(ByteTuple array, CompletionHandler handler) { - write(array.content(), array.offset(), array.length(), null, 0, 0, null, null, handler); - } - - public final void write(byte[] bytes, int offset, int length, CompletionHandler handler) { - write(bytes, offset, length, null, 0, 0, null, null, handler); - } - - public final void write(ByteTuple header, ByteTuple body, CompletionHandler handler) { - write(header.content(), header.offset(), header.length(), body == null ? null : body.content(), body == null ? 0 : body.offset(), body == null ? 0 : body.length(), null, null, handler); - } - - public void write(byte[] headerContent, int headerOffset, int headerLength, byte[] bodyContent, int bodyOffset, int bodyLength, Consumer bodyCallback, Object bodyAttachment, CompletionHandler handler) { - final ByteBuffer buffer = sslEngine == null ? pollWriteBuffer() : pollWriteSSLBuffer(); - if (buffer.remaining() >= headerLength + bodyLength) { - buffer.put(headerContent, headerOffset, headerLength); - if (bodyLength > 0) { - buffer.put(bodyContent, bodyOffset, bodyLength); - if (bodyCallback != null) bodyCallback.accept(bodyAttachment); - } - buffer.flip(); - CompletionHandler newhandler = new CompletionHandler() { - @Override - public void completed(Integer result, Void attachment) { - offerBuffer(buffer); - handler.completed(result, attachment); - } - - @Override - public void failed(Throwable exc, Void attachment) { - offerBuffer(buffer); - handler.failed(exc, attachment); - } - }; - write(buffer, null, newhandler); - } else { - ByteBufferWriter writer = ByteBufferWriter.create(sslEngine == null ? bufferSupplier : () -> pollWriteSSLBuffer(), buffer); - writer.put(headerContent, headerOffset, headerLength); - if (bodyLength > 0) { - writer.put(bodyContent, bodyOffset, bodyLength); - if (bodyCallback != null) bodyCallback.accept(bodyAttachment); - } - final ByteBuffer[] buffers = writer.toBuffers(); - CompletionHandler newhandler = new CompletionHandler() { - @Override - public void completed(Integer result, Void attachment) { - offerBuffer(buffers); - handler.completed(result, attachment); - } - - @Override - public void failed(Throwable exc, Void attachment) { - offerBuffer(buffers); - handler.failed(exc, attachment); - } - }; - write(buffers, null, newhandler); - } - } - - public void setReadBuffer(ByteBuffer buffer) { - if (this.readBuffer != null) throw new RuntimeException("repeat AsyncConnection.setReadBuffer"); - this.readBuffer = buffer; - } - - public boolean hasPipelineData() { - ByteBufferWriter writer = this.pipelineWriter; - return writer != null && writer.position() > 0; - } - - public final void flushPipelineData(CompletionHandler handler) { - flushPipelineData(null, handler); - } - - public void flushPipelineData(A attachment, CompletionHandler handler) { - ByteBufferWriter writer = this.pipelineWriter; - this.pipelineWriter = null; - if (writer == null) { - handler.completed(0, attachment); - } else { - ByteBuffer[] srcs = writer.toBuffers(); - CompletionHandler newhandler = new CompletionHandler() { - @Override - public void completed(Integer result, A attachment) { - offerBuffer(srcs); - handler.completed(result, attachment); - } - - @Override - public void failed(Throwable exc, A attachment) { - offerBuffer(srcs); - handler.failed(exc, attachment); - } - }; - if (srcs.length == 1) { - write(srcs[0], attachment, newhandler); - } else { - write(srcs, attachment, newhandler); - } - } - } - - //杩斿洖 鏄惁over - public final boolean writePipelineData(int pipelineIndex, int pipelineCount, ByteTuple array) { - return writePipelineData(pipelineIndex, pipelineCount, array.content(), array.offset(), array.length()); - } - - //杩斿洖 鏄惁over - public boolean writePipelineData(int pipelineIndex, int pipelineCount, byte[] bs, int offset, int length) { - synchronized (this) { - ByteBufferWriter writer = this.pipelineWriter; - if (writer == null) { - writer = ByteBufferWriter.create(getBufferSupplier()); - this.pipelineWriter = writer; - } - if (this.pipelineDataNode == null && pipelineIndex == writer.getWriteBytesCounter() + 1) { - writer.put(bs, offset, length); - return (pipelineIndex == pipelineCount); - } else { - PipelineDataNode dataNode = this.pipelineDataNode; - if (dataNode == null) { - dataNode = new PipelineDataNode(); - this.pipelineDataNode = dataNode; - } - if (pipelineIndex == pipelineCount) { //姝ゆ椂pipelineCount涓烘渶澶у - dataNode.pipelineCount = pipelineCount; - } - dataNode.put(pipelineIndex, bs, offset, length); - if (writer.getWriteBytesCounter() + dataNode.itemsize == dataNode.pipelineCount) { - for (PipelineDataItem item : dataNode.arrayItems()) { - writer.put(item.data); - } - this.pipelineDataNode = null; - return true; - } - return false; - } - } - } - - //杩斿洖 鏄惁over - public final boolean writePipelineData(int pipelineIndex, int pipelineCount, ByteTuple header, ByteTuple body) { - return writePipelineData(pipelineIndex, pipelineCount, header.content(), header.offset(), header.length(), body == null ? null : body.content(), body == null ? 0 : body.offset(), body == null ? 0 : body.length()); - } - - //杩斿洖 鏄惁over - public boolean writePipelineData(int pipelineIndex, int pipelineCount, byte[] headerContent, int headerOffset, int headerLength, byte[] bodyContent, int bodyOffset, int bodyLength) { - synchronized (this) { - ByteBufferWriter writer = this.pipelineWriter; - if (writer == null) { - writer = ByteBufferWriter.create(getBufferSupplier()); - this.pipelineWriter = writer; - } - if (this.pipelineDataNode == null && pipelineIndex == writer.getWriteBytesCounter() + 1) { - writer.put(headerContent, headerOffset, headerLength, bodyContent, bodyOffset, bodyLength); - return (pipelineIndex == pipelineCount); - } else { - PipelineDataNode dataNode = this.pipelineDataNode; - if (dataNode == null) { - dataNode = new PipelineDataNode(); - this.pipelineDataNode = dataNode; - } - if (pipelineIndex == pipelineCount) { //姝ゆ椂pipelineCount涓烘渶澶у - dataNode.pipelineCount = pipelineCount; - } - dataNode.put(pipelineIndex, headerContent, headerOffset, headerLength, bodyContent, bodyOffset, bodyLength); - if (writer.getWriteBytesCounter() + dataNode.itemsize == dataNode.pipelineCount) { - for (PipelineDataItem item : dataNode.arrayItems()) { - writer.put(item.data); - } - this.pipelineDataNode = null; - return true; - } - return false; - } - } - } - - private static class PipelineDataNode { - - public int pipelineCount; - - public int itemsize; - - private PipelineDataItem head; - - private PipelineDataItem tail; - - public PipelineDataItem[] arrayItems() { - PipelineDataItem[] items = new PipelineDataItem[itemsize]; - PipelineDataItem item = head; - int i = 0; - while (item != null) { - items[i] = item; - item = item.next; - items[i].next = null; - i++; - } - Arrays.sort(items); - return items; - } - - public void put(int pipelineIndex, byte[] bs, int offset, int length) { - if (tail == null) { - head = new PipelineDataItem(pipelineIndex, bs, offset, length); - tail = head; - } else { - PipelineDataItem item = new PipelineDataItem(pipelineIndex, bs, offset, length); - tail.next = item; - tail = item; - } - itemsize++; - } - - public void put(int pipelineIndex, byte[] headerContent, int headerOffset, int headerLength, byte[] bodyContent, int bodyOffset, int bodyLength) { - if (tail == null) { - head = new PipelineDataItem(pipelineIndex, headerContent, headerOffset, headerLength, bodyContent, bodyOffset, bodyLength); - tail = head; - } else { - PipelineDataItem item = new PipelineDataItem(pipelineIndex, headerContent, headerOffset, headerLength, bodyContent, bodyOffset, bodyLength); - tail.next = item; - tail = item; - } - itemsize++; - } - - } - - private static class PipelineDataItem implements Comparable { - - final byte[] data; - - final int index; - - public PipelineDataItem next; - - public PipelineDataItem(int index, byte[] bs, int offset, int length) { - this.index = index; - this.data = Arrays.copyOfRange(bs, offset, offset + length); - } - - public PipelineDataItem(int index, byte[] headerContent, int headerOffset, int headerLength, byte[] bodyContent, int bodyOffset, int bodyLength) { - this.index = index; - this.data = bodyLength > 0 ? copyOfRange(headerContent, headerOffset, headerLength, bodyContent, bodyOffset, bodyLength) - : Arrays.copyOfRange(headerContent, headerOffset, headerOffset + headerLength); - } - - private static byte[] copyOfRange(byte[] headerContent, int headerOffset, int headerLength, byte[] bodyContent, int bodyOffset, int bodyLength) { - byte[] result = new byte[headerLength + bodyLength]; - System.arraycopy(headerContent, headerOffset, result, 0, headerLength); - System.arraycopy(bodyContent, bodyOffset, result, headerLength, bodyLength); - return result; - } - - @Override - public int compareTo(PipelineDataItem o) { - return this.index - o.index; - } - - @Override - public String toString() { - return "{\"index\":" + index + "}"; - } - } - - protected void setReadSSLBuffer(ByteBuffer buffer) { - if (this.readSSLHalfBuffer != null) throw new RuntimeException("repeat AsyncConnection.setReadSSLBuffer"); - this.readSSLHalfBuffer = buffer; - } - - protected ByteBuffer pollReadSSLBuffer() { - ByteBuffer rs = this.readSSLHalfBuffer; - if (rs != null) { - this.readSSLHalfBuffer = null; - return rs; - } - return bufferSupplier.get(); - } - - public ByteBuffer pollReadBuffer() { - ByteBuffer rs = this.readBuffer; - if (rs != null) { - this.readBuffer = null; - return rs; - } - return bufferSupplier.get(); - } - - public void offerBuffer(ByteBuffer buffer) { - if (buffer == null) return; - bufferConsumer.accept(buffer); - } - - public void offerBuffer(ByteBuffer... buffers) { - if (buffers == null) return; - Consumer consumer = this.bufferConsumer; - for (ByteBuffer buffer : buffers) { - consumer.accept(buffer); - } - } - - public ByteBuffer pollWriteSSLBuffer() { - return bufferSupplier.get(); - } - - public ByteBuffer pollWriteBuffer() { - return bufferSupplier.get(); - } - - public void dispose() {//鍚宑lose锛 鍙槸鍘绘帀throws IOException - try { - this.close(); - } catch (IOException io) { - } - } - - public AsyncConnection beforeCloseListener(Consumer beforeCloseListener) { - this.beforeCloseListener = beforeCloseListener; - return this; - } - - @Override - public void close() throws IOException { - if (closedCounter != null) { - closedCounter.increment(); - closedCounter = null; - } - if (livingCounter != null) { - livingCounter.decrement(); - livingCounter = null; - } - if (sslEngine != null) { - try { - sslEngine.closeInbound(); - sslEngine.closeOutbound(); - } catch (SSLException e) { - } - sslEngine = null; - } - if (beforeCloseListener != null) { - try { - beforeCloseListener.accept(this); - } catch (Exception io) { - } - } - if (this.readBuffer != null) { - Consumer consumer = this.bufferConsumer; - if (consumer != null) consumer.accept(this.readBuffer); - } - if (attributes == null) return; - try { - for (Object obj : attributes.values()) { - if (obj instanceof AutoCloseable) ((AutoCloseable) obj).close(); - } - attributes.clear(); - } catch (Exception io) { - } - } - - @SuppressWarnings("unchecked") - public final T getSubobject() { - return (T) this.subobject; - } - - public void setSubobject(Object value) { - this.subobject = value; - } - - @Override - public void setAttribute(String name, Object value) { - if (this.attributes == null) this.attributes = new HashMap<>(); - this.attributes.put(name, value); - } - - @Override - @SuppressWarnings("unchecked") - public final T getAttribute(String name) { - return (T) (this.attributes == null ? null : this.attributes.get(name)); - } - - @Override - public final void removeAttribute(String name) { - if (this.attributes != null) this.attributes.remove(name); - } - - @Override - public final Map getAttributes() { - return this.attributes; - } - - @Override - public final void clearAttribute() { - if (this.attributes != null) this.attributes.clear(); - } - - protected void startHandshake(final Consumer callback) { - if (sslEngine == null) { - callback.accept(null); - return; - } - SSLEngine engine = this.sslEngine; - try { - engine.beginHandshake(); - doHandshake(callback); - } catch (Throwable t) { - callback.accept(t); - } - } - - //瑙e瘑ssl缃戠粶鏁版嵁锛 杩斿洖null琛ㄧずCLOSED - protected ByteBuffer sslUnwrap(final boolean handshake, ByteBuffer netBuffer) throws SSLException { - ByteBuffer appBuffer = pollReadBuffer(); - SSLEngine engine = this.sslEngine; - HandshakeStatus hss; - do { //status鍙湁 CLOSED銆丱K銆丅UFFER_UNDERFLOW銆丅UFFER_OVERFLOW - //BUFFER_OVERFLOW: appBuffer鍙敤绌洪棿涓嶈冻, redkale纭繚appBuffer涓嶄細鍑虹幇绌洪棿涓嶈冻鐨勬儏鍐 - //BUFFER_UNDERFLOW: netBuffer鍙敤鍐呭涓嶈冻 - SSLEngineResult engineResult = engine.unwrap(netBuffer, appBuffer); - if (engineResult.getStatus() == SSLEngineResult.Status.CLOSED - && (engineResult.getHandshakeStatus() == NOT_HANDSHAKING || engineResult.getHandshakeStatus() == FINISHED)) { - offerBuffer(netBuffer); - offerBuffer(appBuffer); - return null; - } - hss = engineResult.getHandshakeStatus(); - if (hss == NEED_TASK) { - Runnable task; - while ((task = engine.getDelegatedTask()) != null) { - task.run(); - } - hss = engine.getHandshakeStatus(); - } - } while (hss == NEED_UNWRAP && netBuffer.hasRemaining()); - if (netBuffer.hasRemaining()) { - netBuffer.compact(); - setReadSSLBuffer(netBuffer); - } - return appBuffer; - } - - protected void sslReadImpl(final boolean handshake, final CompletionHandler handler) { - readImpl(new CompletionHandler() { - - @Override - public void completed(Integer count, ByteBuffer attachment) { - // System.out.println(AsyncConnection.this + " 杩涙潵浜嗚鍒扮殑瀛楄妭鏁: " + count); - if (count < 0) { - handler.completed(count, attachment); - return; - } - ByteBuffer netBuffer = attachment; - netBuffer.flip(); - try { - ByteBuffer appBuffer = sslUnwrap(handshake, netBuffer); - if (appBuffer == null) return; //CLOSED锛宯etBuffer宸茶鍥炴敹 - if (AsyncConnection.this.readSSLHalfBuffer != netBuffer) { - offerBuffer(netBuffer); - } - if (AsyncConnection.this.readBuffer != null) { - ByteBuffer rsBuffer = AsyncConnection.this.readBuffer; - AsyncConnection.this.readBuffer = null; - appBuffer.flip(); - if (rsBuffer.remaining() >= appBuffer.remaining()) { - rsBuffer.put(appBuffer); - offerBuffer(appBuffer); - appBuffer = rsBuffer; - } else { - while (rsBuffer.hasRemaining()) rsBuffer.put(appBuffer.get()); - AsyncConnection.this.readBuffer = appBuffer.compact(); - appBuffer = rsBuffer; - } - } - handler.completed(count, appBuffer); - } catch (SSLException e) { - failed(e, attachment); - } - } - - @Override - public void failed(Throwable t, ByteBuffer attachment) { - handler.failed(t, attachment); - } - }); - } - - //鍔犲瘑ssl鍐呭鏁版嵁 - protected ByteBuffer[] sslWrap(final boolean handshake, ByteBuffer appBuffer) throws SSLException { - final SSLEngine engine = this.sslEngine; - final int netSize = engine.getSession().getPacketBufferSize(); - ByteBuffer netBuffer = pollWriteBuffer(); - ByteBuffer[] netBuffers = new ByteBuffer[]{netBuffer}; - SSLEngineResult engineResult = engine.wrap(appBuffer, netBuffer); - //status鍙湁 CLOSED銆丱K銆丅UFFER_OVERFLOW - //BUFFER_OVERFLOW: netBuffer鍙敤绌洪棿涓嶈冻, redkale纭繚netBuffer涓嶄細鍑虹幇绌洪棿涓嶈冻鐨勬儏鍐 - while (appBuffer.hasRemaining() || (handshake && engine.getHandshakeStatus() == NEED_WRAP)) { - boolean enough = true; - if (engineResult.getHandshakeStatus() == NEED_TASK) { - Runnable task; - while ((task = engine.getDelegatedTask()) != null) { - task.run(); - } - } else if (engineResult.getStatus() == BUFFER_OVERFLOW) { //闇瑕侀噸鏂皐rap - enough = false; - } - if (enough && netBuffer.remaining() >= netSize) { - engineResult = engine.wrap(appBuffer, netBuffer); - if (engineResult.getStatus() != OK) { - netBuffer.flip(); - netBuffer = pollWriteBuffer(); - netBuffers = Utility.append(netBuffers, netBuffer); - engineResult = engine.wrap(appBuffer, netBuffer); - } - } else { - netBuffer.flip(); - netBuffer = pollWriteBuffer(); - netBuffers = Utility.append(netBuffers, netBuffer); - engineResult = engine.wrap(appBuffer, netBuffer); - } - } - netBuffer.flip(); - return netBuffers; - } - - //鍔犲瘑ssl鍐呭鏁版嵁 - protected ByteBuffer[] sslWrap(final boolean handshake, ByteBuffer[] appBuffers, int offset, int length) throws SSLException { - final SSLEngine engine = this.sslEngine; - final int netSize = engine.getSession().getPacketBufferSize(); - ByteBuffer netBuffer = pollWriteSSLBuffer(); - ByteBuffer[] netBuffers = new ByteBuffer[]{netBuffer}; - SSLEngineResult engineResult = engine.wrap(appBuffers, offset, length, netBuffer); - while (ByteBufferReader.remaining(appBuffers, offset, length) > 0) { - boolean enough = true; - if (engineResult.getHandshakeStatus() == NEED_TASK) { - Runnable task; - while ((task = engine.getDelegatedTask()) != null) { - task.run(); - } - } else if (engineResult.getStatus() == BUFFER_OVERFLOW) { //闇瑕侀噸鏂皐rap - enough = false; - } - if (enough && netBuffer.remaining() >= netSize) { - engineResult = engine.wrap(appBuffers, offset, length, netBuffer); - if (engineResult.getStatus() != OK) { - netBuffer.flip(); - netBuffer = pollWriteSSLBuffer(); - netBuffers = Utility.append(netBuffers, netBuffer); - engineResult = engine.wrap(appBuffers, offset, length, netBuffer); - } - } else { - netBuffer.flip(); - netBuffer = pollWriteSSLBuffer(); - netBuffers = Utility.append(netBuffers, netBuffer); - engineResult = engine.wrap(appBuffers, offset, length, netBuffer); - } - } - netBuffer.flip(); - return netBuffers; - } - - protected boolean sslWriteImpl(final boolean handshake, ByteBuffer appBuffer, final Consumer callback) throws SSLException { - ByteBuffer[] netBuffers = sslWrap(handshake, appBuffer); - if (netBuffers.length > 0) { - if (netBuffers.length == 1) { - writeImpl(netBuffers[0], null, new CompletionHandler() { - @Override - public void completed(Integer count, Void attachment) { - offerBuffer(netBuffers[0]); - callback.accept(null); - } - - @Override - public void failed(Throwable t, Void attachment) { - offerBuffer(netBuffers[0]); - callback.accept(t); - } - }); - } else { - writeImpl(netBuffers, 0, netBuffers.length, null, new CompletionHandler() { - @Override - public void completed(Integer count, Void attachment) { - offerBuffer(netBuffers); - callback.accept(null); - } - - @Override - public void failed(Throwable t, Void attachment) { - offerBuffer(netBuffers); - callback.accept(t); - } - }); - } - return true; - } else { - offerBuffer(netBuffers); - return false; - } - } - - protected boolean sslWriteImpl(final boolean handshake, ByteBuffer[] appBuffers, int offset, int length, final Consumer callback) throws SSLException { - ByteBuffer[] netBuffers = sslWrap(handshake, appBuffers, offset, length); - if (netBuffers.length > 0) { - if (netBuffers.length == 1) { - writeImpl(netBuffers[0], null, new CompletionHandler() { - @Override - public void completed(Integer count, Void attachment) { - offerBuffer(netBuffers[0]); - callback.accept(null); - } - - @Override - public void failed(Throwable t, Void attachment) { - offerBuffer(netBuffers[0]); - callback.accept(t); - } - }); - } else { - writeImpl(netBuffers, 0, netBuffers.length, null, new CompletionHandler() { - @Override - public void completed(Integer count, Void attachment) { - offerBuffer(netBuffers); - callback.accept(null); - } - - @Override - public void failed(Throwable t, Void attachment) { - offerBuffer(netBuffers); - callback.accept(t); - } - }); - } - return true; - } else { - offerBuffer(netBuffers); - return false; - } - } - - private void doHandshake(final Consumer callback) { - HandshakeStatus handshakeStatus; - final SSLEngine engine = this.sslEngine; - while ((handshakeStatus = engine.getHandshakeStatus()) != null) { - // System.out.println(AsyncConnection.this + " handshakeStatus = " + handshakeStatus); - switch (handshakeStatus) { - case FINISHED: - case NOT_HANDSHAKING: - // System.out.println(AsyncConnection.this + " doHandshakde瀹屾瘯锛屽紑濮嬭繘鍏ヨ鍐欐搷浣-----"); - callback.accept(null); - return; - case NEED_TASK: { - Runnable task; - while ((task = engine.getDelegatedTask()) != null) { - task.run(); - } - break; - } - case NEED_WRAP: { - try { // - boolean rs = sslWriteImpl(true, EMPTY_BUFFER, t -> { - if (t == null) { - doHandshake(callback); - } else { - callback.accept(t); - } - }); - if (rs) return; - } catch (SSLException e) { - callback.accept(e); - return; - } - break; - } - case NEED_UNWRAP: { - sslReadImpl(true, new CompletionHandler() { - @Override - public void completed(Integer count, ByteBuffer attachment) { - if (count < 1) { - callback.accept(new IOException("read data error")); - } else { - offerBuffer(attachment); - doHandshake(callback); - } - } - - @Override - public void failed(Throwable t, ByteBuffer attachment) { - callback.accept(t); - } - }); - return; - } - } - } - } - - @Override - public String toString() { - String s = super.toString(); - int pos = s.lastIndexOf('@'); - if (pos < 1) return s; - int cha = pos + 10 - s.length(); - if (cha < 1) return s; - for (int i = 0; i < cha; i++) s += ' '; - return s; - } -} +/* + * 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; + +import java.io.*; +import java.net.*; +import java.nio.*; +import java.nio.channels.*; +import java.util.*; +import java.util.concurrent.atomic.*; +import java.util.function.*; +import javax.net.ssl.*; +import javax.net.ssl.SSLEngineResult.HandshakeStatus; +import static javax.net.ssl.SSLEngineResult.Status.*; +import static javax.net.ssl.SSLEngineResult.HandshakeStatus.*; +import org.redkale.util.*; + +/** + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public abstract class AsyncConnection implements ChannelContext, Channel, AutoCloseable { + + private static final ByteBuffer EMPTY_BUFFER = ByteBuffer.allocate(0); + + //SSL + protected SSLEngine sslEngine; + + protected volatile long readtime; + + protected volatile long writetime; + + private Map attributes; //鐢ㄤ簬瀛樺偍缁戝畾鍦–onnection涓婄殑瀵硅薄闆嗗悎 + + private Object subobject; //鐢ㄤ簬瀛樺偍缁戝畾鍦–onnection涓婄殑瀵硅薄锛 鍚宎ttributes锛 鍙粦瀹氬崟涓璞℃椂灏介噺浣跨敤subobject鑰岄潪attributes + + protected final AsyncGroup ioGroup; + + protected final AsyncThread ioThread; + + protected final boolean client; + + protected final int bufferCapacity; + + private final Supplier bufferSupplier; + + private final Consumer bufferConsumer; + + private ByteBufferWriter pipelineWriter; + + private PipelineDataNode pipelineDataNode; + + private ByteBuffer readBuffer; + + private ByteBuffer readSSLHalfBuffer; + + //鍦ㄧ嚎鏁 + private LongAdder livingCounter; + + //鍏抽棴鏁 + private LongAdder closedCounter; + + private Consumer beforeCloseListener; + + //鍏宠仈鐨勪簨浠舵暟锛 灏忎簬1琛ㄧず娌℃湁浜嬩欢 + private final AtomicInteger eventing = new AtomicInteger(); + + //鐢ㄤ簬鏈嶅姟绔殑Socket, 绛夊悓浜庝竴鐩村瓨鍦ㄧ殑readCompletionHandler + ProtocolCodec protocolCodec; + + protected AsyncConnection(boolean client, AsyncGroup ioGroup, AsyncThread ioThread, final int bufferCapacity, ObjectPool bufferPool, + SSLBuilder sslBuilder, SSLContext sslContext, final LongAdder livingCounter, final LongAdder closedCounter) { + this(client, ioGroup, ioThread, bufferCapacity, bufferPool, bufferPool, sslBuilder, sslContext, livingCounter, closedCounter); + } + + protected AsyncConnection(boolean client, AsyncGroup ioGroup, AsyncThread ioThread, final int bufferCapacity, Supplier bufferSupplier, + Consumer bufferConsumer, SSLBuilder sslBuilder, SSLContext sslContext, final LongAdder livingCounter, final LongAdder closedCounter) { + Objects.requireNonNull(bufferSupplier); + Objects.requireNonNull(bufferConsumer); + this.client = client; + this.ioGroup = ioGroup; + this.ioThread = ioThread; + this.bufferCapacity = bufferCapacity; + this.bufferSupplier = bufferSupplier; + this.bufferConsumer = bufferConsumer; + this.livingCounter = livingCounter; + this.closedCounter = closedCounter; + if (client) { //client妯″紡涓嬫棤SSLBuilder + if (sslContext != null) { + if (sslBuilder != null) { + this.sslEngine = sslBuilder.createSSLEngine(sslContext, client); + } else { + this.sslEngine = sslContext.createSSLEngine(); + } + } + } else { + if (sslBuilder != null && sslContext != null) { + this.sslEngine = sslBuilder.createSSLEngine(sslContext, client); + } + } + } + + public Supplier getBufferSupplier() { + return this.bufferSupplier; + } + + public Consumer getBufferConsumer() { + return this.bufferConsumer; + } + + public final long getLastReadTime() { + return readtime; + } + + public final long getLastWriteTime() { + return writetime; + } + + public final boolean ssl() { + return sslEngine != null; + } + + public final int increEventing() { + return eventing.incrementAndGet(); + } + + public final int decreEventing() { + return eventing.decrementAndGet(); + } + + public final void execute(Runnable command) { + ioThread.execute(command); + } + + public final boolean inCurrThread() { + return ioThread.inCurrThread(); + } + + public final AsyncThread getAsyncThread() { + return ioThread; + } + + @Override + public abstract boolean isOpen(); + + public abstract boolean isTCP(); + + public abstract boolean shutdownInput(); + + public abstract boolean shutdownOutput(); + + public abstract boolean setOption(SocketOption name, T value); + + public abstract Set> supportedOptions(); + + public abstract SocketAddress getRemoteAddress(); + + public abstract SocketAddress getLocalAddress(); + + public abstract int getReadTimeoutSeconds(); + + public abstract int getWriteTimeoutSeconds(); + + public abstract void setReadTimeoutSeconds(int readTimeoutSeconds); + + public abstract void setWriteTimeoutSeconds(int writeTimeoutSeconds); + + protected abstract void readImpl(CompletionHandler handler); + + //src鍐欏畬鎵嶄細鍥炶皟 + protected abstract void writeImpl(ByteBuffer src, A attachment, CompletionHandler handler); + + //srcs鍐欏畬鎵嶄細鍥炶皟 + protected abstract void writeImpl(ByteBuffer[] srcs, int offset, int length, A attachment, CompletionHandler handler); + + protected void startRead(CompletionHandler handler) { + read(handler); + } + + public final void read(CompletionHandler handler) { + if (sslEngine == null) { + readImpl(handler); + } else { + sslReadImpl(false, handler); + } + } + + //src鍐欏畬鎵嶄細鍥炶皟 + public final void write(ByteBuffer src, A attachment, CompletionHandler handler) { + if (sslEngine == null) { + writeImpl(src, attachment, handler); + } else { + try { + int remain = src.remaining(); + sslWriteImpl(false, src, t -> { + if (t == null) { + handler.completed(remain - src.remaining(), attachment); + } else { + handler.failed(t, attachment); + } + }); + } catch (SSLException e) { + handler.failed(e, attachment); + } + } + } + + //srcs鍐欏畬鎵嶄細鍥炶皟 + public final void write(ByteBuffer[] srcs, int offset, int length, A attachment, CompletionHandler handler) { + if (sslEngine == null) { + writeImpl(srcs, offset, length, attachment, handler); + } else { + try { + int remain = ByteBufferReader.remaining(srcs, offset, length); + sslWriteImpl(false, srcs, offset, length, t -> { + if (t == null) { + handler.completed(remain - ByteBufferReader.remaining(srcs, offset, length), attachment); + } else { + handler.failed(t, attachment); + } + }); + } catch (SSLException e) { + handler.failed(e, attachment); + } + } + } + + //srcs鍐欏畬鎵嶄細鍥炶皟 + public final void write(ByteBuffer[] srcs, A attachment, CompletionHandler handler) { + write(srcs, 0, srcs.length, attachment, handler); + } + + public final void write(byte[] bytes, CompletionHandler handler) { + write(bytes, 0, bytes.length, null, 0, 0, null, null, handler); + } + + public final void write(ByteTuple array, CompletionHandler handler) { + write(array.content(), array.offset(), array.length(), null, 0, 0, null, null, handler); + } + + public final void write(byte[] bytes, int offset, int length, CompletionHandler handler) { + write(bytes, offset, length, null, 0, 0, null, null, handler); + } + + public final void write(ByteTuple header, ByteTuple body, CompletionHandler handler) { + write(header.content(), header.offset(), header.length(), body == null ? null : body.content(), body == null ? 0 : body.offset(), body == null ? 0 : body.length(), null, null, handler); + } + + public void write(byte[] headerContent, int headerOffset, int headerLength, byte[] bodyContent, int bodyOffset, int bodyLength, Consumer bodyCallback, Object bodyAttachment, CompletionHandler handler) { + final ByteBuffer buffer = sslEngine == null ? pollWriteBuffer() : pollWriteSSLBuffer(); + if (buffer.remaining() >= headerLength + bodyLength) { + buffer.put(headerContent, headerOffset, headerLength); + if (bodyLength > 0) { + buffer.put(bodyContent, bodyOffset, bodyLength); + if (bodyCallback != null) bodyCallback.accept(bodyAttachment); + } + buffer.flip(); + CompletionHandler newhandler = new CompletionHandler() { + @Override + public void completed(Integer result, Void attachment) { + offerBuffer(buffer); + handler.completed(result, attachment); + } + + @Override + public void failed(Throwable exc, Void attachment) { + offerBuffer(buffer); + handler.failed(exc, attachment); + } + }; + write(buffer, null, newhandler); + } else { + ByteBufferWriter writer = ByteBufferWriter.create(sslEngine == null ? bufferSupplier : () -> pollWriteSSLBuffer(), buffer); + writer.put(headerContent, headerOffset, headerLength); + if (bodyLength > 0) { + writer.put(bodyContent, bodyOffset, bodyLength); + if (bodyCallback != null) bodyCallback.accept(bodyAttachment); + } + final ByteBuffer[] buffers = writer.toBuffers(); + CompletionHandler newhandler = new CompletionHandler() { + @Override + public void completed(Integer result, Void attachment) { + offerBuffer(buffers); + handler.completed(result, attachment); + } + + @Override + public void failed(Throwable exc, Void attachment) { + offerBuffer(buffers); + handler.failed(exc, attachment); + } + }; + write(buffers, null, newhandler); + } + } + + public void setReadBuffer(ByteBuffer buffer) { + if (this.readBuffer != null) throw new RuntimeException("repeat AsyncConnection.setReadBuffer"); + this.readBuffer = buffer; + } + + public boolean hasPipelineData() { + ByteBufferWriter writer = this.pipelineWriter; + return writer != null && writer.position() > 0; + } + + public final void flushPipelineData(CompletionHandler handler) { + flushPipelineData(null, handler); + } + + public void flushPipelineData(A attachment, CompletionHandler handler) { + ByteBufferWriter writer = this.pipelineWriter; + this.pipelineWriter = null; + if (writer == null) { + handler.completed(0, attachment); + } else { + ByteBuffer[] srcs = writer.toBuffers(); + CompletionHandler newhandler = new CompletionHandler() { + @Override + public void completed(Integer result, A attachment) { + offerBuffer(srcs); + handler.completed(result, attachment); + } + + @Override + public void failed(Throwable exc, A attachment) { + offerBuffer(srcs); + handler.failed(exc, attachment); + } + }; + if (srcs.length == 1) { + write(srcs[0], attachment, newhandler); + } else { + write(srcs, attachment, newhandler); + } + } + } + + //杩斿洖 鏄惁over + public final boolean writePipelineData(int pipelineIndex, int pipelineCount, ByteTuple array) { + return writePipelineData(pipelineIndex, pipelineCount, array.content(), array.offset(), array.length()); + } + + //杩斿洖 鏄惁over + public boolean writePipelineData(int pipelineIndex, int pipelineCount, byte[] bs, int offset, int length) { + synchronized (this) { + ByteBufferWriter writer = this.pipelineWriter; + if (writer == null) { + writer = ByteBufferWriter.create(getBufferSupplier()); + this.pipelineWriter = writer; + } + if (this.pipelineDataNode == null && pipelineIndex == writer.getWriteBytesCounter() + 1) { + writer.put(bs, offset, length); + return (pipelineIndex == pipelineCount); + } else { + PipelineDataNode dataNode = this.pipelineDataNode; + if (dataNode == null) { + dataNode = new PipelineDataNode(); + this.pipelineDataNode = dataNode; + } + if (pipelineIndex == pipelineCount) { //姝ゆ椂pipelineCount涓烘渶澶у + dataNode.pipelineCount = pipelineCount; + } + dataNode.put(pipelineIndex, bs, offset, length); + if (writer.getWriteBytesCounter() + dataNode.itemsize == dataNode.pipelineCount) { + for (PipelineDataItem item : dataNode.arrayItems()) { + writer.put(item.data); + } + this.pipelineDataNode = null; + return true; + } + return false; + } + } + } + + //杩斿洖 鏄惁over + public final boolean writePipelineData(int pipelineIndex, int pipelineCount, ByteTuple header, ByteTuple body) { + return writePipelineData(pipelineIndex, pipelineCount, header.content(), header.offset(), header.length(), body == null ? null : body.content(), body == null ? 0 : body.offset(), body == null ? 0 : body.length()); + } + + //杩斿洖 鏄惁over + public boolean writePipelineData(int pipelineIndex, int pipelineCount, byte[] headerContent, int headerOffset, int headerLength, byte[] bodyContent, int bodyOffset, int bodyLength) { + synchronized (this) { + ByteBufferWriter writer = this.pipelineWriter; + if (writer == null) { + writer = ByteBufferWriter.create(getBufferSupplier()); + this.pipelineWriter = writer; + } + if (this.pipelineDataNode == null && pipelineIndex == writer.getWriteBytesCounter() + 1) { + writer.put(headerContent, headerOffset, headerLength, bodyContent, bodyOffset, bodyLength); + return (pipelineIndex == pipelineCount); + } else { + PipelineDataNode dataNode = this.pipelineDataNode; + if (dataNode == null) { + dataNode = new PipelineDataNode(); + this.pipelineDataNode = dataNode; + } + if (pipelineIndex == pipelineCount) { //姝ゆ椂pipelineCount涓烘渶澶у + dataNode.pipelineCount = pipelineCount; + } + dataNode.put(pipelineIndex, headerContent, headerOffset, headerLength, bodyContent, bodyOffset, bodyLength); + if (writer.getWriteBytesCounter() + dataNode.itemsize == dataNode.pipelineCount) { + for (PipelineDataItem item : dataNode.arrayItems()) { + writer.put(item.data); + } + this.pipelineDataNode = null; + return true; + } + return false; + } + } + } + + private static class PipelineDataNode { + + public int pipelineCount; + + public int itemsize; + + private PipelineDataItem head; + + private PipelineDataItem tail; + + public PipelineDataItem[] arrayItems() { + PipelineDataItem[] items = new PipelineDataItem[itemsize]; + PipelineDataItem item = head; + int i = 0; + while (item != null) { + items[i] = item; + item = item.next; + items[i].next = null; + i++; + } + Arrays.sort(items); + return items; + } + + public void put(int pipelineIndex, byte[] bs, int offset, int length) { + if (tail == null) { + head = new PipelineDataItem(pipelineIndex, bs, offset, length); + tail = head; + } else { + PipelineDataItem item = new PipelineDataItem(pipelineIndex, bs, offset, length); + tail.next = item; + tail = item; + } + itemsize++; + } + + public void put(int pipelineIndex, byte[] headerContent, int headerOffset, int headerLength, byte[] bodyContent, int bodyOffset, int bodyLength) { + if (tail == null) { + head = new PipelineDataItem(pipelineIndex, headerContent, headerOffset, headerLength, bodyContent, bodyOffset, bodyLength); + tail = head; + } else { + PipelineDataItem item = new PipelineDataItem(pipelineIndex, headerContent, headerOffset, headerLength, bodyContent, bodyOffset, bodyLength); + tail.next = item; + tail = item; + } + itemsize++; + } + + } + + private static class PipelineDataItem implements Comparable { + + final byte[] data; + + final int index; + + public PipelineDataItem next; + + public PipelineDataItem(int index, byte[] bs, int offset, int length) { + this.index = index; + this.data = Arrays.copyOfRange(bs, offset, offset + length); + } + + public PipelineDataItem(int index, byte[] headerContent, int headerOffset, int headerLength, byte[] bodyContent, int bodyOffset, int bodyLength) { + this.index = index; + this.data = bodyLength > 0 ? copyOfRange(headerContent, headerOffset, headerLength, bodyContent, bodyOffset, bodyLength) + : Arrays.copyOfRange(headerContent, headerOffset, headerOffset + headerLength); + } + + private static byte[] copyOfRange(byte[] headerContent, int headerOffset, int headerLength, byte[] bodyContent, int bodyOffset, int bodyLength) { + byte[] result = new byte[headerLength + bodyLength]; + System.arraycopy(headerContent, headerOffset, result, 0, headerLength); + System.arraycopy(bodyContent, bodyOffset, result, headerLength, bodyLength); + return result; + } + + @Override + public int compareTo(PipelineDataItem o) { + return this.index - o.index; + } + + @Override + public String toString() { + return "{\"index\":" + index + "}"; + } + } + + protected void setReadSSLBuffer(ByteBuffer buffer) { + if (this.readSSLHalfBuffer != null) throw new RuntimeException("repeat AsyncConnection.setReadSSLBuffer"); + this.readSSLHalfBuffer = buffer; + } + + protected ByteBuffer pollReadSSLBuffer() { + ByteBuffer rs = this.readSSLHalfBuffer; + if (rs != null) { + this.readSSLHalfBuffer = null; + return rs; + } + return bufferSupplier.get(); + } + + public ByteBuffer pollReadBuffer() { + ByteBuffer rs = this.readBuffer; + if (rs != null) { + this.readBuffer = null; + return rs; + } + return bufferSupplier.get(); + } + + public void offerBuffer(ByteBuffer buffer) { + if (buffer == null) return; + bufferConsumer.accept(buffer); + } + + public void offerBuffer(ByteBuffer... buffers) { + if (buffers == null) return; + Consumer consumer = this.bufferConsumer; + for (ByteBuffer buffer : buffers) { + consumer.accept(buffer); + } + } + + public ByteBuffer pollWriteSSLBuffer() { + return bufferSupplier.get(); + } + + public ByteBuffer pollWriteBuffer() { + return bufferSupplier.get(); + } + + public void dispose() {//鍚宑lose锛 鍙槸鍘绘帀throws IOException + try { + this.close(); + } catch (IOException io) { + } + } + + public AsyncConnection beforeCloseListener(Consumer beforeCloseListener) { + this.beforeCloseListener = beforeCloseListener; + return this; + } + + @Override + public void close() throws IOException { + if (closedCounter != null) { + closedCounter.increment(); + closedCounter = null; + } + if (livingCounter != null) { + livingCounter.decrement(); + livingCounter = null; + } + if (sslEngine != null) { + try { + sslEngine.closeInbound(); + sslEngine.closeOutbound(); + } catch (SSLException e) { + } + sslEngine = null; + } + if (beforeCloseListener != null) { + try { + beforeCloseListener.accept(this); + } catch (Exception io) { + } + } + if (this.readBuffer != null) { + Consumer consumer = this.bufferConsumer; + if (consumer != null) consumer.accept(this.readBuffer); + } + if (attributes == null) return; + try { + for (Object obj : attributes.values()) { + if (obj instanceof AutoCloseable) ((AutoCloseable) obj).close(); + } + attributes.clear(); + } catch (Exception io) { + } + } + + @SuppressWarnings("unchecked") + public final T getSubobject() { + return (T) this.subobject; + } + + public void setSubobject(Object value) { + this.subobject = value; + } + + @Override + public void setAttribute(String name, Object value) { + if (this.attributes == null) this.attributes = new HashMap<>(); + this.attributes.put(name, value); + } + + @Override + @SuppressWarnings("unchecked") + public final T getAttribute(String name) { + return (T) (this.attributes == null ? null : this.attributes.get(name)); + } + + @Override + public final void removeAttribute(String name) { + if (this.attributes != null) this.attributes.remove(name); + } + + @Override + public final Map getAttributes() { + return this.attributes; + } + + @Override + public final void clearAttribute() { + if (this.attributes != null) this.attributes.clear(); + } + + protected void startHandshake(final Consumer callback) { + if (sslEngine == null) { + callback.accept(null); + return; + } + SSLEngine engine = this.sslEngine; + try { + engine.beginHandshake(); + doHandshake(callback); + } catch (Throwable t) { + callback.accept(t); + } + } + + //瑙e瘑ssl缃戠粶鏁版嵁锛 杩斿洖null琛ㄧずCLOSED + protected ByteBuffer sslUnwrap(final boolean handshake, ByteBuffer netBuffer) throws SSLException { + ByteBuffer appBuffer = pollReadBuffer(); + SSLEngine engine = this.sslEngine; + HandshakeStatus hss; + do { //status鍙湁 CLOSED銆丱K銆丅UFFER_UNDERFLOW銆丅UFFER_OVERFLOW + //BUFFER_OVERFLOW: appBuffer鍙敤绌洪棿涓嶈冻, redkale纭繚appBuffer涓嶄細鍑虹幇绌洪棿涓嶈冻鐨勬儏鍐 + //BUFFER_UNDERFLOW: netBuffer鍙敤鍐呭涓嶈冻 + SSLEngineResult engineResult = engine.unwrap(netBuffer, appBuffer); + if (engineResult.getStatus() == SSLEngineResult.Status.CLOSED + && (engineResult.getHandshakeStatus() == NOT_HANDSHAKING || engineResult.getHandshakeStatus() == FINISHED)) { + offerBuffer(netBuffer); + offerBuffer(appBuffer); + return null; + } + hss = engineResult.getHandshakeStatus(); + if (hss == NEED_TASK) { + Runnable task; + while ((task = engine.getDelegatedTask()) != null) { + task.run(); + } + hss = engine.getHandshakeStatus(); + } + } while (hss == NEED_UNWRAP && netBuffer.hasRemaining()); + if (netBuffer.hasRemaining()) { + netBuffer.compact(); + setReadSSLBuffer(netBuffer); + } + return appBuffer; + } + + protected void sslReadImpl(final boolean handshake, final CompletionHandler handler) { + readImpl(new CompletionHandler() { + + @Override + public void completed(Integer count, ByteBuffer attachment) { + // System.out.println(AsyncConnection.this + " 杩涙潵浜嗚鍒扮殑瀛楄妭鏁: " + count); + if (count < 0) { + handler.completed(count, attachment); + return; + } + ByteBuffer netBuffer = attachment; + netBuffer.flip(); + try { + ByteBuffer appBuffer = sslUnwrap(handshake, netBuffer); + if (appBuffer == null) return; //CLOSED锛宯etBuffer宸茶鍥炴敹 + if (AsyncConnection.this.readSSLHalfBuffer != netBuffer) { + offerBuffer(netBuffer); + } + if (AsyncConnection.this.readBuffer != null) { + ByteBuffer rsBuffer = AsyncConnection.this.readBuffer; + AsyncConnection.this.readBuffer = null; + appBuffer.flip(); + if (rsBuffer.remaining() >= appBuffer.remaining()) { + rsBuffer.put(appBuffer); + offerBuffer(appBuffer); + appBuffer = rsBuffer; + } else { + while (rsBuffer.hasRemaining()) rsBuffer.put(appBuffer.get()); + AsyncConnection.this.readBuffer = appBuffer.compact(); + appBuffer = rsBuffer; + } + } + handler.completed(count, appBuffer); + } catch (SSLException e) { + failed(e, attachment); + } + } + + @Override + public void failed(Throwable t, ByteBuffer attachment) { + handler.failed(t, attachment); + } + }); + } + + //鍔犲瘑ssl鍐呭鏁版嵁 + protected ByteBuffer[] sslWrap(final boolean handshake, ByteBuffer appBuffer) throws SSLException { + final SSLEngine engine = this.sslEngine; + final int netSize = engine.getSession().getPacketBufferSize(); + ByteBuffer netBuffer = pollWriteBuffer(); + ByteBuffer[] netBuffers = new ByteBuffer[]{netBuffer}; + SSLEngineResult engineResult = engine.wrap(appBuffer, netBuffer); + //status鍙湁 CLOSED銆丱K銆丅UFFER_OVERFLOW + //BUFFER_OVERFLOW: netBuffer鍙敤绌洪棿涓嶈冻, redkale纭繚netBuffer涓嶄細鍑虹幇绌洪棿涓嶈冻鐨勬儏鍐 + while (appBuffer.hasRemaining() || (handshake && engine.getHandshakeStatus() == NEED_WRAP)) { + boolean enough = true; + if (engineResult.getHandshakeStatus() == NEED_TASK) { + Runnable task; + while ((task = engine.getDelegatedTask()) != null) { + task.run(); + } + } else if (engineResult.getStatus() == BUFFER_OVERFLOW) { //闇瑕侀噸鏂皐rap + enough = false; + } + if (enough && netBuffer.remaining() >= netSize) { + engineResult = engine.wrap(appBuffer, netBuffer); + if (engineResult.getStatus() != OK) { + netBuffer.flip(); + netBuffer = pollWriteBuffer(); + netBuffers = Utility.append(netBuffers, netBuffer); + engineResult = engine.wrap(appBuffer, netBuffer); + } + } else { + netBuffer.flip(); + netBuffer = pollWriteBuffer(); + netBuffers = Utility.append(netBuffers, netBuffer); + engineResult = engine.wrap(appBuffer, netBuffer); + } + } + netBuffer.flip(); + return netBuffers; + } + + //鍔犲瘑ssl鍐呭鏁版嵁 + protected ByteBuffer[] sslWrap(final boolean handshake, ByteBuffer[] appBuffers, int offset, int length) throws SSLException { + final SSLEngine engine = this.sslEngine; + final int netSize = engine.getSession().getPacketBufferSize(); + ByteBuffer netBuffer = pollWriteSSLBuffer(); + ByteBuffer[] netBuffers = new ByteBuffer[]{netBuffer}; + SSLEngineResult engineResult = engine.wrap(appBuffers, offset, length, netBuffer); + while (ByteBufferReader.remaining(appBuffers, offset, length) > 0) { + boolean enough = true; + if (engineResult.getHandshakeStatus() == NEED_TASK) { + Runnable task; + while ((task = engine.getDelegatedTask()) != null) { + task.run(); + } + } else if (engineResult.getStatus() == BUFFER_OVERFLOW) { //闇瑕侀噸鏂皐rap + enough = false; + } + if (enough && netBuffer.remaining() >= netSize) { + engineResult = engine.wrap(appBuffers, offset, length, netBuffer); + if (engineResult.getStatus() != OK) { + netBuffer.flip(); + netBuffer = pollWriteSSLBuffer(); + netBuffers = Utility.append(netBuffers, netBuffer); + engineResult = engine.wrap(appBuffers, offset, length, netBuffer); + } + } else { + netBuffer.flip(); + netBuffer = pollWriteSSLBuffer(); + netBuffers = Utility.append(netBuffers, netBuffer); + engineResult = engine.wrap(appBuffers, offset, length, netBuffer); + } + } + netBuffer.flip(); + return netBuffers; + } + + protected boolean sslWriteImpl(final boolean handshake, ByteBuffer appBuffer, final Consumer callback) throws SSLException { + ByteBuffer[] netBuffers = sslWrap(handshake, appBuffer); + if (netBuffers.length > 0) { + if (netBuffers.length == 1) { + writeImpl(netBuffers[0], null, new CompletionHandler() { + @Override + public void completed(Integer count, Void attachment) { + offerBuffer(netBuffers[0]); + callback.accept(null); + } + + @Override + public void failed(Throwable t, Void attachment) { + offerBuffer(netBuffers[0]); + callback.accept(t); + } + }); + } else { + writeImpl(netBuffers, 0, netBuffers.length, null, new CompletionHandler() { + @Override + public void completed(Integer count, Void attachment) { + offerBuffer(netBuffers); + callback.accept(null); + } + + @Override + public void failed(Throwable t, Void attachment) { + offerBuffer(netBuffers); + callback.accept(t); + } + }); + } + return true; + } else { + offerBuffer(netBuffers); + return false; + } + } + + protected boolean sslWriteImpl(final boolean handshake, ByteBuffer[] appBuffers, int offset, int length, final Consumer callback) throws SSLException { + ByteBuffer[] netBuffers = sslWrap(handshake, appBuffers, offset, length); + if (netBuffers.length > 0) { + if (netBuffers.length == 1) { + writeImpl(netBuffers[0], null, new CompletionHandler() { + @Override + public void completed(Integer count, Void attachment) { + offerBuffer(netBuffers[0]); + callback.accept(null); + } + + @Override + public void failed(Throwable t, Void attachment) { + offerBuffer(netBuffers[0]); + callback.accept(t); + } + }); + } else { + writeImpl(netBuffers, 0, netBuffers.length, null, new CompletionHandler() { + @Override + public void completed(Integer count, Void attachment) { + offerBuffer(netBuffers); + callback.accept(null); + } + + @Override + public void failed(Throwable t, Void attachment) { + offerBuffer(netBuffers); + callback.accept(t); + } + }); + } + return true; + } else { + offerBuffer(netBuffers); + return false; + } + } + + private void doHandshake(final Consumer callback) { + HandshakeStatus handshakeStatus; + final SSLEngine engine = this.sslEngine; + while ((handshakeStatus = engine.getHandshakeStatus()) != null) { + // System.out.println(AsyncConnection.this + " handshakeStatus = " + handshakeStatus); + switch (handshakeStatus) { + case FINISHED: + case NOT_HANDSHAKING: + // System.out.println(AsyncConnection.this + " doHandshakde瀹屾瘯锛屽紑濮嬭繘鍏ヨ鍐欐搷浣-----"); + callback.accept(null); + return; + case NEED_TASK: { + Runnable task; + while ((task = engine.getDelegatedTask()) != null) { + task.run(); + } + break; + } + case NEED_WRAP: { + try { // + boolean rs = sslWriteImpl(true, EMPTY_BUFFER, t -> { + if (t == null) { + doHandshake(callback); + } else { + callback.accept(t); + } + }); + if (rs) return; + } catch (SSLException e) { + callback.accept(e); + return; + } + break; + } + case NEED_UNWRAP: { + sslReadImpl(true, new CompletionHandler() { + @Override + public void completed(Integer count, ByteBuffer attachment) { + if (count < 1) { + callback.accept(new IOException("read data error")); + } else { + offerBuffer(attachment); + doHandshake(callback); + } + } + + @Override + public void failed(Throwable t, ByteBuffer attachment) { + callback.accept(t); + } + }); + return; + } + } + } + } + + @Override + public String toString() { + String s = super.toString(); + int pos = s.lastIndexOf('@'); + if (pos < 1) return s; + int cha = pos + 10 - s.length(); + if (cha < 1) return s; + for (int i = 0; i < cha; i++) s += ' '; + return s; + } +} diff --git a/src/main/java/org/redkale/net/AsyncGroup.java b/src/main/java/org/redkale/net/AsyncGroup.java index a8e9ff5e5..f9c951b2a 100644 --- a/src/main/java/org/redkale/net/AsyncGroup.java +++ b/src/main/java/org/redkale/net/AsyncGroup.java @@ -1,66 +1,66 @@ -/* - * 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; - -import java.net.SocketAddress; -import java.nio.ByteBuffer; -import java.util.concurrent.*; -import org.redkale.util.ObjectPool; - -/** - * Client妯″紡鐨凙syncConnection杩炴帴鏋勯犲櫒 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * - * @since 2.3.0 - */ -public abstract class AsyncGroup { - - public static AsyncGroup create(String threadPrefixName, final ExecutorService workExecutor, final int bufferCapacity, final int bufferPoolSize) { - return new AsyncIOGroup(true, threadPrefixName, workExecutor, bufferCapacity, bufferPoolSize); - } - - public static AsyncGroup create(String threadPrefixName, ExecutorService workExecutor, final int bufferCapacity, ObjectPool safeBufferPool) { - return new AsyncIOGroup(true, threadPrefixName, workExecutor, bufferCapacity, safeBufferPool); - } - - public static AsyncGroup create(boolean client, String threadPrefixName, final ExecutorService workExecutor, final int bufferCapacity, final int bufferPoolSize) { - return new AsyncIOGroup(client, threadPrefixName, workExecutor, bufferCapacity, bufferPoolSize); - } - - public static AsyncGroup create(boolean client, String threadPrefixName, ExecutorService workExecutor, final int bufferCapacity, ObjectPool safeBufferPool) { - return new AsyncIOGroup(client, threadPrefixName, workExecutor, bufferCapacity, safeBufferPool); - } - - public CompletableFuture createTCPClient(final SocketAddress address) { - return createTCPClient(address, 0, 0); - } - - public abstract CompletableFuture createTCPClient(final SocketAddress address, final int readTimeoutSeconds, final int writeTimeoutSeconds); - - public CompletableFuture createUDPClient(final SocketAddress address) { - return createUDPClient(address, 0, 0); - } - - public abstract CompletableFuture createUDPClient(final SocketAddress address, final int readTimeoutSeconds, final int writeTimeoutSeconds); - - public CompletableFuture createClient(final boolean tcp, final SocketAddress address) { - return tcp ? createTCPClient(address) : createUDPClient(address); - } - - public CompletableFuture createClient(final boolean tcp, final SocketAddress address, final int readTimeoutSeconds, final int writeTimeoutSeconds) { - return tcp ? createTCPClient(address, readTimeoutSeconds, writeTimeoutSeconds) : createUDPClient(address, readTimeoutSeconds, writeTimeoutSeconds); - } - - public abstract ScheduledFuture scheduleTimeout(Runnable callable, long delay, TimeUnit unit); - - public abstract AsyncGroup start(); - - public abstract AsyncGroup close(); -} +/* + * 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; + +import java.net.SocketAddress; +import java.nio.ByteBuffer; +import java.util.concurrent.*; +import org.redkale.util.ObjectPool; + +/** + * Client妯″紡鐨凙syncConnection杩炴帴鏋勯犲櫒 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.3.0 + */ +public abstract class AsyncGroup { + + public static AsyncGroup create(String threadPrefixName, final ExecutorService workExecutor, final int bufferCapacity, final int bufferPoolSize) { + return new AsyncIOGroup(true, threadPrefixName, workExecutor, bufferCapacity, bufferPoolSize); + } + + public static AsyncGroup create(String threadPrefixName, ExecutorService workExecutor, final int bufferCapacity, ObjectPool safeBufferPool) { + return new AsyncIOGroup(true, threadPrefixName, workExecutor, bufferCapacity, safeBufferPool); + } + + public static AsyncGroup create(boolean client, String threadPrefixName, final ExecutorService workExecutor, final int bufferCapacity, final int bufferPoolSize) { + return new AsyncIOGroup(client, threadPrefixName, workExecutor, bufferCapacity, bufferPoolSize); + } + + public static AsyncGroup create(boolean client, String threadPrefixName, ExecutorService workExecutor, final int bufferCapacity, ObjectPool safeBufferPool) { + return new AsyncIOGroup(client, threadPrefixName, workExecutor, bufferCapacity, safeBufferPool); + } + + public CompletableFuture createTCPClient(final SocketAddress address) { + return createTCPClient(address, 0, 0); + } + + public abstract CompletableFuture createTCPClient(final SocketAddress address, final int readTimeoutSeconds, final int writeTimeoutSeconds); + + public CompletableFuture createUDPClient(final SocketAddress address) { + return createUDPClient(address, 0, 0); + } + + public abstract CompletableFuture createUDPClient(final SocketAddress address, final int readTimeoutSeconds, final int writeTimeoutSeconds); + + public CompletableFuture createClient(final boolean tcp, final SocketAddress address) { + return tcp ? createTCPClient(address) : createUDPClient(address); + } + + public CompletableFuture createClient(final boolean tcp, final SocketAddress address, final int readTimeoutSeconds, final int writeTimeoutSeconds) { + return tcp ? createTCPClient(address, readTimeoutSeconds, writeTimeoutSeconds) : createUDPClient(address, readTimeoutSeconds, writeTimeoutSeconds); + } + + public abstract ScheduledFuture scheduleTimeout(Runnable callable, long delay, TimeUnit unit); + + public abstract AsyncGroup start(); + + public abstract AsyncGroup close(); +} diff --git a/src/main/java/org/redkale/net/AsyncIOGroup.java b/src/main/java/org/redkale/net/AsyncIOGroup.java index a68d30af9..71178d969 100644 --- a/src/main/java/org/redkale/net/AsyncIOGroup.java +++ b/src/main/java/org/redkale/net/AsyncIOGroup.java @@ -1,270 +1,270 @@ -/* - * 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; - -import java.io.IOException; -import java.net.*; -import java.nio.ByteBuffer; -import java.nio.channels.*; -import java.util.concurrent.*; -import java.util.concurrent.atomic.*; -import org.redkale.util.*; - -/** - * 鍗忚澶勭悊鐨処O绾跨▼缁 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * - * @since 2.1.0 - */ -@ResourceType(AsyncGroup.class) -public class AsyncIOGroup extends AsyncGroup { - - private boolean started; - - private boolean closed; - - AsyncIOThread[] ioThreads; - - private AsyncIOThread connectThread; - - final int bufferCapacity; - - final AtomicInteger shareCount = new AtomicInteger(1); - - private final AtomicInteger readIndex = new AtomicInteger(); - - //鍒涘缓鏁 - final LongAdder connCreateCounter = new LongAdder(); - - //鍏抽棴鏁 - final LongAdder connLivingCounter = new LongAdder(); - - //鍦ㄧ嚎鏁 - final LongAdder connClosedCounter = new LongAdder(); - - private ScheduledThreadPoolExecutor timeoutExecutor; - - public AsyncIOGroup(final int bufferCapacity, final int bufferPoolSize) { - this(true, null, null, bufferCapacity, bufferPoolSize); - } - - public AsyncIOGroup(boolean client, String threadPrefixName, final ExecutorService workExecutor, final int bufferCapacity, final int bufferPoolSize) { - this(client, threadPrefixName, workExecutor, bufferCapacity, ObjectPool.createSafePool(null, null, bufferPoolSize, - (Object... params) -> ByteBuffer.allocateDirect(bufferCapacity), null, (e) -> { - if (e == null || e.isReadOnly() || e.capacity() != bufferCapacity) return false; - e.clear(); - return true; - })); - } - - public AsyncIOGroup(boolean client, String threadPrefixName0, ExecutorService workExecutor, final int bufferCapacity, ObjectPool safeBufferPool) { - this.bufferCapacity = bufferCapacity; - final String threadPrefixName = threadPrefixName0 == null ? "Redkale-Client-IOThread" : threadPrefixName0; - this.ioThreads = new AsyncIOThread[Utility.cpus()]; - try { - for (int i = 0; i < this.ioThreads.length; i++) { - ObjectPool unsafeBufferPool = ObjectPool.createUnsafePool(safeBufferPool, safeBufferPool.getCreatCounter(), - safeBufferPool.getCycleCounter(), 512, safeBufferPool.getCreator(), safeBufferPool.getPrepare(), safeBufferPool.getRecycler()); - String name = threadPrefixName + "-" + (i >= 9 ? (i + 1) : ("0" + (i + 1))); - - this.ioThreads[i] = new AsyncIOThread(true, name, i, ioThreads.length, workExecutor, Selector.open(), unsafeBufferPool, safeBufferPool); - } - if (client) { - ObjectPool unsafeBufferPool = ObjectPool.createUnsafePool(safeBufferPool, safeBufferPool.getCreatCounter(), - safeBufferPool.getCycleCounter(), 512, safeBufferPool.getCreator(), safeBufferPool.getPrepare(), safeBufferPool.getRecycler()); - String name = threadPrefixName.replace("ServletThread", "ConnectThread").replace("IOThread", "ConnectThread"); - this.connectThread = new AsyncIOThread(false, name, 0, 0, workExecutor, Selector.open(), unsafeBufferPool, safeBufferPool); - } - } catch (IOException e) { - throw new RuntimeException(e); - } - this.timeoutExecutor = (ScheduledThreadPoolExecutor) Executors.newScheduledThreadPool(1, (Runnable r) -> { - Thread t = new Thread(r); - t.setName(threadPrefixName + "-Timeout"); - t.setDaemon(true); - return t; - }); - } - - public int size() { - return this.ioThreads.length; - } - - @Override - public AsyncGroup start() { - if (started) return this; - if (closed) throw new RuntimeException("group is closed"); - for (AsyncIOThread thread : ioThreads) { - thread.start(); - } - if (connectThread != null) connectThread.start(); - started = true; - return this; - } - - @Override - public AsyncGroup close() { - if (shareCount.decrementAndGet() > 0) return this; - if (closed) return this; - for (AsyncIOThread thread : ioThreads) { - thread.close(); - } - if (connectThread != null) connectThread.close(); - this.timeoutExecutor.shutdownNow(); - closed = true; - return this; - } - - public LongAdder getCreateConnectionCount() { - return connCreateCounter; - } - - public LongAdder getClosedConnectionCount() { - return connLivingCounter; - } - - public LongAdder getLivingConnectionCount() { - return connClosedCounter; - } - - public AsyncIOThread nextIOThread() { - return ioThreads[Math.abs(readIndex.getAndIncrement()) % ioThreads.length]; - } - - public AsyncIOThread connectThread() { - return connectThread; - } - - @Override - public ScheduledFuture scheduleTimeout(Runnable callable, long delay, TimeUnit unit) { - return timeoutExecutor.schedule(callable, delay, unit); - } - - public void interestOpsOr(AsyncIOThread thread, SelectionKey key, int opt) { - if (key == null) return; - if (key.selector() != thread.selector) throw new RuntimeException("NioThread.selector not the same to SelectionKey.selector"); - if ((key.interestOps() & opt) != 0) return; - key.interestOps(key.interestOps() | opt); - if (thread.inCurrThread()) { -// timeoutExecutor.execute(() -> { -// try { -// key.selector().wakeup(); -// } catch (Throwable t) { -// } -// }); - } else { - //闈濱O绾跨▼涓 - key.selector().wakeup(); - } - } - - @Override - public CompletableFuture createTCPClient(final SocketAddress address, final int readTimeoutSeconds, final int writeTimeoutSeconds) { - SocketChannel channel; - try { - channel = SocketChannel.open(); - channel.configureBlocking(false); - channel.setOption(StandardSocketOptions.TCP_NODELAY, true); - channel.setOption(StandardSocketOptions.SO_KEEPALIVE, true); - channel.setOption(StandardSocketOptions.SO_REUSEADDR, true); - } catch (IOException e) { - CompletableFuture future = new CompletableFuture(); - future.completeExceptionally(e); - return future; - } - AsyncIOThread ioThread = null; - Thread currThread = Thread.currentThread(); - if (currThread instanceof AsyncIOThread) { - for (AsyncIOThread thread : ioThreads) { - if (thread == currThread) { - ioThread = thread; - break; - } - } - } - if (ioThread == null) ioThread = nextIOThread(); - final AsyncNioTcpConnection conn = new AsyncNioTcpConnection(true, this, ioThread, connectThread, channel, null, null, address, connLivingCounter, connClosedCounter); - final CompletableFuture future = new CompletableFuture<>(); - conn.connect(address, null, new CompletionHandler() { - @Override - public void completed(Void result, Void attachment) { - conn.setReadTimeoutSeconds(readTimeoutSeconds); - conn.setWriteTimeoutSeconds(writeTimeoutSeconds); - if (connCreateCounter != null) connCreateCounter.increment(); - if (connLivingCounter != null) connLivingCounter.increment(); - if (conn.sslEngine == null) { - future.complete(conn); - } else { - conn.startHandshake(t -> { - if (t == null) { - future.complete(conn); - } else { - future.completeExceptionally(t); - } - }); - } - } - - @Override - public void failed(Throwable exc, Void attachment) { - future.completeExceptionally(exc); - } - }); - return Utility.orTimeout(future, 30, TimeUnit.SECONDS); - } - - @Override - public CompletableFuture createUDPClient(final SocketAddress address, final int readTimeoutSeconds, final int writeTimeoutSeconds) { - DatagramChannel channel; - try { - channel = DatagramChannel.open(); - } catch (IOException e) { - CompletableFuture future = new CompletableFuture(); - future.completeExceptionally(e); - return future; - } - AsyncIOThread ioThread = null; - Thread currThread = Thread.currentThread(); - if (currThread instanceof AsyncIOThread) { - for (AsyncIOThread thread : ioThreads) { - if (thread == currThread) { - ioThread = thread; - break; - } - } - } - if (ioThread == null) ioThread = nextIOThread(); - AsyncNioUdpConnection conn = new AsyncNioUdpConnection(true, this, ioThread, connectThread, channel, null, null, address, connLivingCounter, connClosedCounter); - CompletableFuture future = new CompletableFuture(); - conn.connect(address, null, new CompletionHandler() { - @Override - public void completed(Void result, Void attachment) { - if (conn.sslEngine == null) { - future.complete(conn); - } else { - conn.startHandshake(t -> { - if (t == null) { - future.complete(conn); - } else { - future.completeExceptionally(t); - } - }); - } - } - - @Override - public void failed(Throwable exc, Void attachment) { - future.completeExceptionally(exc); - } - }); - return future; - } - -} +/* + * 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; + +import java.io.IOException; +import java.net.*; +import java.nio.ByteBuffer; +import java.nio.channels.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.*; +import org.redkale.util.*; + +/** + * 鍗忚澶勭悊鐨処O绾跨▼缁 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.1.0 + */ +@ResourceType(AsyncGroup.class) +public class AsyncIOGroup extends AsyncGroup { + + private boolean started; + + private boolean closed; + + AsyncIOThread[] ioThreads; + + private AsyncIOThread connectThread; + + final int bufferCapacity; + + final AtomicInteger shareCount = new AtomicInteger(1); + + private final AtomicInteger readIndex = new AtomicInteger(); + + //鍒涘缓鏁 + final LongAdder connCreateCounter = new LongAdder(); + + //鍏抽棴鏁 + final LongAdder connLivingCounter = new LongAdder(); + + //鍦ㄧ嚎鏁 + final LongAdder connClosedCounter = new LongAdder(); + + private ScheduledThreadPoolExecutor timeoutExecutor; + + public AsyncIOGroup(final int bufferCapacity, final int bufferPoolSize) { + this(true, null, null, bufferCapacity, bufferPoolSize); + } + + public AsyncIOGroup(boolean client, String threadPrefixName, final ExecutorService workExecutor, final int bufferCapacity, final int bufferPoolSize) { + this(client, threadPrefixName, workExecutor, bufferCapacity, ObjectPool.createSafePool(null, null, bufferPoolSize, + (Object... params) -> ByteBuffer.allocateDirect(bufferCapacity), null, (e) -> { + if (e == null || e.isReadOnly() || e.capacity() != bufferCapacity) return false; + e.clear(); + return true; + })); + } + + public AsyncIOGroup(boolean client, String threadPrefixName0, ExecutorService workExecutor, final int bufferCapacity, ObjectPool safeBufferPool) { + this.bufferCapacity = bufferCapacity; + final String threadPrefixName = threadPrefixName0 == null ? "Redkale-Client-IOThread" : threadPrefixName0; + this.ioThreads = new AsyncIOThread[Utility.cpus()]; + try { + for (int i = 0; i < this.ioThreads.length; i++) { + ObjectPool unsafeBufferPool = ObjectPool.createUnsafePool(safeBufferPool, safeBufferPool.getCreatCounter(), + safeBufferPool.getCycleCounter(), 512, safeBufferPool.getCreator(), safeBufferPool.getPrepare(), safeBufferPool.getRecycler()); + String name = threadPrefixName + "-" + (i >= 9 ? (i + 1) : ("0" + (i + 1))); + + this.ioThreads[i] = new AsyncIOThread(true, name, i, ioThreads.length, workExecutor, Selector.open(), unsafeBufferPool, safeBufferPool); + } + if (client) { + ObjectPool unsafeBufferPool = ObjectPool.createUnsafePool(safeBufferPool, safeBufferPool.getCreatCounter(), + safeBufferPool.getCycleCounter(), 512, safeBufferPool.getCreator(), safeBufferPool.getPrepare(), safeBufferPool.getRecycler()); + String name = threadPrefixName.replace("ServletThread", "ConnectThread").replace("IOThread", "ConnectThread"); + this.connectThread = new AsyncIOThread(false, name, 0, 0, workExecutor, Selector.open(), unsafeBufferPool, safeBufferPool); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + this.timeoutExecutor = (ScheduledThreadPoolExecutor) Executors.newScheduledThreadPool(1, (Runnable r) -> { + Thread t = new Thread(r); + t.setName(threadPrefixName + "-Timeout"); + t.setDaemon(true); + return t; + }); + } + + public int size() { + return this.ioThreads.length; + } + + @Override + public AsyncGroup start() { + if (started) return this; + if (closed) throw new RuntimeException("group is closed"); + for (AsyncIOThread thread : ioThreads) { + thread.start(); + } + if (connectThread != null) connectThread.start(); + started = true; + return this; + } + + @Override + public AsyncGroup close() { + if (shareCount.decrementAndGet() > 0) return this; + if (closed) return this; + for (AsyncIOThread thread : ioThreads) { + thread.close(); + } + if (connectThread != null) connectThread.close(); + this.timeoutExecutor.shutdownNow(); + closed = true; + return this; + } + + public LongAdder getCreateConnectionCount() { + return connCreateCounter; + } + + public LongAdder getClosedConnectionCount() { + return connLivingCounter; + } + + public LongAdder getLivingConnectionCount() { + return connClosedCounter; + } + + public AsyncIOThread nextIOThread() { + return ioThreads[Math.abs(readIndex.getAndIncrement()) % ioThreads.length]; + } + + public AsyncIOThread connectThread() { + return connectThread; + } + + @Override + public ScheduledFuture scheduleTimeout(Runnable callable, long delay, TimeUnit unit) { + return timeoutExecutor.schedule(callable, delay, unit); + } + + public void interestOpsOr(AsyncIOThread thread, SelectionKey key, int opt) { + if (key == null) return; + if (key.selector() != thread.selector) throw new RuntimeException("NioThread.selector not the same to SelectionKey.selector"); + if ((key.interestOps() & opt) != 0) return; + key.interestOps(key.interestOps() | opt); + if (thread.inCurrThread()) { +// timeoutExecutor.execute(() -> { +// try { +// key.selector().wakeup(); +// } catch (Throwable t) { +// } +// }); + } else { + //闈濱O绾跨▼涓 + key.selector().wakeup(); + } + } + + @Override + public CompletableFuture createTCPClient(final SocketAddress address, final int readTimeoutSeconds, final int writeTimeoutSeconds) { + SocketChannel channel; + try { + channel = SocketChannel.open(); + channel.configureBlocking(false); + channel.setOption(StandardSocketOptions.TCP_NODELAY, true); + channel.setOption(StandardSocketOptions.SO_KEEPALIVE, true); + channel.setOption(StandardSocketOptions.SO_REUSEADDR, true); + } catch (IOException e) { + CompletableFuture future = new CompletableFuture(); + future.completeExceptionally(e); + return future; + } + AsyncIOThread ioThread = null; + Thread currThread = Thread.currentThread(); + if (currThread instanceof AsyncIOThread) { + for (AsyncIOThread thread : ioThreads) { + if (thread == currThread) { + ioThread = thread; + break; + } + } + } + if (ioThread == null) ioThread = nextIOThread(); + final AsyncNioTcpConnection conn = new AsyncNioTcpConnection(true, this, ioThread, connectThread, channel, null, null, address, connLivingCounter, connClosedCounter); + final CompletableFuture future = new CompletableFuture<>(); + conn.connect(address, null, new CompletionHandler() { + @Override + public void completed(Void result, Void attachment) { + conn.setReadTimeoutSeconds(readTimeoutSeconds); + conn.setWriteTimeoutSeconds(writeTimeoutSeconds); + if (connCreateCounter != null) connCreateCounter.increment(); + if (connLivingCounter != null) connLivingCounter.increment(); + if (conn.sslEngine == null) { + future.complete(conn); + } else { + conn.startHandshake(t -> { + if (t == null) { + future.complete(conn); + } else { + future.completeExceptionally(t); + } + }); + } + } + + @Override + public void failed(Throwable exc, Void attachment) { + future.completeExceptionally(exc); + } + }); + return Utility.orTimeout(future, 30, TimeUnit.SECONDS); + } + + @Override + public CompletableFuture createUDPClient(final SocketAddress address, final int readTimeoutSeconds, final int writeTimeoutSeconds) { + DatagramChannel channel; + try { + channel = DatagramChannel.open(); + } catch (IOException e) { + CompletableFuture future = new CompletableFuture(); + future.completeExceptionally(e); + return future; + } + AsyncIOThread ioThread = null; + Thread currThread = Thread.currentThread(); + if (currThread instanceof AsyncIOThread) { + for (AsyncIOThread thread : ioThreads) { + if (thread == currThread) { + ioThread = thread; + break; + } + } + } + if (ioThread == null) ioThread = nextIOThread(); + AsyncNioUdpConnection conn = new AsyncNioUdpConnection(true, this, ioThread, connectThread, channel, null, null, address, connLivingCounter, connClosedCounter); + CompletableFuture future = new CompletableFuture(); + conn.connect(address, null, new CompletionHandler() { + @Override + public void completed(Void result, Void attachment) { + if (conn.sslEngine == null) { + future.complete(conn); + } else { + conn.startHandshake(t -> { + if (t == null) { + future.complete(conn); + } else { + future.completeExceptionally(t); + } + }); + } + } + + @Override + public void failed(Throwable exc, Void attachment) { + future.completeExceptionally(exc); + } + }); + return future; + } + +} diff --git a/src/main/java/org/redkale/net/AsyncIOThread.java b/src/main/java/org/redkale/net/AsyncIOThread.java index dd78cbba2..973930b51 100644 --- a/src/main/java/org/redkale/net/AsyncIOThread.java +++ b/src/main/java/org/redkale/net/AsyncIOThread.java @@ -1,163 +1,163 @@ -/* - * 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; - -import java.nio.ByteBuffer; -import java.nio.channels.*; -import java.util.*; -import java.util.concurrent.*; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.*; -import java.util.logging.*; -import org.redkale.util.*; - -/** - * 鍗忚澶勭悊鐨処O绾跨▼绫 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * - * @since 2.1.0 - */ -public class AsyncIOThread extends AsyncThread { - - protected static final Logger logger = Logger.getLogger(AsyncIOThread.class.getSimpleName()); - - final Selector selector; - - final AtomicInteger connCounter = new AtomicInteger(); - - private final Supplier bufferSupplier; - - private final Consumer bufferConsumer; - - private final Queue commandQueue = Utility.unsafe() != null ? new MpscGrowableArrayQueue<>(16, 1 << 16) : new ConcurrentLinkedQueue<>(); - - private final Queue> registerQueue = Utility.unsafe() != null ? new MpscGrowableArrayQueue<>(16, 1 << 16) : new ConcurrentLinkedQueue<>(); - - private boolean closed; - - int invoker = 0; - - public AsyncIOThread(final boolean readable, String name, int index, int threads, ExecutorService workExecutor, Selector selector, - ObjectPool unsafeBufferPool, ObjectPool safeBufferPool) { - super(name, index, threads, workExecutor, null); - this.selector = selector; - this.setDaemon(true); - this.bufferSupplier = () -> (inCurrThread() ? unsafeBufferPool : safeBufferPool).get(); - this.bufferConsumer = (v) -> (inCurrThread() ? unsafeBufferPool : safeBufferPool).accept(v); - } - - @Override - public void execute(Runnable command) { - commandQueue.offer(command); - selector.wakeup(); - } - - @Override - public void execute(Runnable... commands) { - for (Runnable command : commands) { - commandQueue.offer(command); - } - selector.wakeup(); - } - - public void register(Consumer consumer) { - registerQueue.offer(consumer); - selector.wakeup(); - } - - public Supplier getBufferSupplier() { - return bufferSupplier; - } - - public Consumer getBufferConsumer() { - return bufferConsumer; - } - - public int currConnections() { - return connCounter.get(); - } - - @Override - public void run() { - final Queue commands = this.commandQueue; - final Queue> registers = this.registerQueue; - while (!this.closed) { - try { - Consumer register; - while ((register = registers.poll()) != null) { - try { - register.accept(selector); - } catch (Throwable t) { - if (!this.closed) logger.log(Level.INFO, getName() + " register run failed", t); - } - } - Runnable command; - while ((command = commands.poll()) != null) { - try { - command.run(); - } catch (Throwable t) { - if (!this.closed) logger.log(Level.INFO, getName() + " command run failed", t); - } - } - int count = selector.select(); - if (count == 0) continue; - - Set keys = selector.selectedKeys(); - Iterator it = keys.iterator(); - while (it.hasNext()) { - SelectionKey key = it.next(); - it.remove(); - invoker = 0; - if (!key.isValid()) continue; - AsyncNioConnection conn = (AsyncNioConnection) key.attachment(); - if (conn.client) { - if (key.isConnectable()) { - key.interestOps(key.interestOps() & ~SelectionKey.OP_CONNECT); - conn.doConnect(); - } else if (conn.readCompletionHandler != null && key.isReadable()) { - conn.currReadInvoker = 0; - key.interestOps(key.interestOps() & ~SelectionKey.OP_READ); - conn.doRead(true); - } else if (conn.writeCompletionHandler != null && key.isWritable()) { - conn.currWriteInvoker = 0; - key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE); - conn.doWrite(true); - } - } else { - if (conn.readCompletionHandler != null && key.isReadable()) { - conn.currReadInvoker = 0; - key.interestOps(key.interestOps() & ~SelectionKey.OP_READ); //涓嶆斁寮杩欒锛屽湪CompletableFuture鏃跺鏄揜eadPending - conn.doRead(true); - } else if (conn.writeCompletionHandler != null && key.isWritable()) { - conn.currWriteInvoker = 0; - key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE); - conn.doWrite(true); - } else if (key.isConnectable()) { - key.interestOps(key.interestOps() & ~SelectionKey.OP_CONNECT); - conn.doConnect(); - } - } - } - } catch (Throwable ex) { - if (!this.closed) logger.log(Level.FINE, getName() + " selector run failed", ex); - } - } - } - - public void close() { - this.closed = true; - this.interrupt(); - try { - this.selector.close(); - } catch (Exception e) { - logger.log(Level.FINE, getName() + " selector close failed", e); - } - } -} +/* + * 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; + +import java.nio.ByteBuffer; +import java.nio.channels.*; +import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.*; +import java.util.logging.*; +import org.redkale.util.*; + +/** + * 鍗忚澶勭悊鐨処O绾跨▼绫 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.1.0 + */ +public class AsyncIOThread extends AsyncThread { + + protected static final Logger logger = Logger.getLogger(AsyncIOThread.class.getSimpleName()); + + final Selector selector; + + final AtomicInteger connCounter = new AtomicInteger(); + + private final Supplier bufferSupplier; + + private final Consumer bufferConsumer; + + private final Queue commandQueue = Utility.unsafe() != null ? new MpscGrowableArrayQueue<>(16, 1 << 16) : new ConcurrentLinkedQueue<>(); + + private final Queue> registerQueue = Utility.unsafe() != null ? new MpscGrowableArrayQueue<>(16, 1 << 16) : new ConcurrentLinkedQueue<>(); + + private boolean closed; + + int invoker = 0; + + public AsyncIOThread(final boolean readable, String name, int index, int threads, ExecutorService workExecutor, Selector selector, + ObjectPool unsafeBufferPool, ObjectPool safeBufferPool) { + super(name, index, threads, workExecutor, null); + this.selector = selector; + this.setDaemon(true); + this.bufferSupplier = () -> (inCurrThread() ? unsafeBufferPool : safeBufferPool).get(); + this.bufferConsumer = (v) -> (inCurrThread() ? unsafeBufferPool : safeBufferPool).accept(v); + } + + @Override + public void execute(Runnable command) { + commandQueue.offer(command); + selector.wakeup(); + } + + @Override + public void execute(Runnable... commands) { + for (Runnable command : commands) { + commandQueue.offer(command); + } + selector.wakeup(); + } + + public void register(Consumer consumer) { + registerQueue.offer(consumer); + selector.wakeup(); + } + + public Supplier getBufferSupplier() { + return bufferSupplier; + } + + public Consumer getBufferConsumer() { + return bufferConsumer; + } + + public int currConnections() { + return connCounter.get(); + } + + @Override + public void run() { + final Queue commands = this.commandQueue; + final Queue> registers = this.registerQueue; + while (!this.closed) { + try { + Consumer register; + while ((register = registers.poll()) != null) { + try { + register.accept(selector); + } catch (Throwable t) { + if (!this.closed) logger.log(Level.INFO, getName() + " register run failed", t); + } + } + Runnable command; + while ((command = commands.poll()) != null) { + try { + command.run(); + } catch (Throwable t) { + if (!this.closed) logger.log(Level.INFO, getName() + " command run failed", t); + } + } + int count = selector.select(); + if (count == 0) continue; + + Set keys = selector.selectedKeys(); + Iterator it = keys.iterator(); + while (it.hasNext()) { + SelectionKey key = it.next(); + it.remove(); + invoker = 0; + if (!key.isValid()) continue; + AsyncNioConnection conn = (AsyncNioConnection) key.attachment(); + if (conn.client) { + if (key.isConnectable()) { + key.interestOps(key.interestOps() & ~SelectionKey.OP_CONNECT); + conn.doConnect(); + } else if (conn.readCompletionHandler != null && key.isReadable()) { + conn.currReadInvoker = 0; + key.interestOps(key.interestOps() & ~SelectionKey.OP_READ); + conn.doRead(true); + } else if (conn.writeCompletionHandler != null && key.isWritable()) { + conn.currWriteInvoker = 0; + key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE); + conn.doWrite(true); + } + } else { + if (conn.readCompletionHandler != null && key.isReadable()) { + conn.currReadInvoker = 0; + key.interestOps(key.interestOps() & ~SelectionKey.OP_READ); //涓嶆斁寮杩欒锛屽湪CompletableFuture鏃跺鏄揜eadPending + conn.doRead(true); + } else if (conn.writeCompletionHandler != null && key.isWritable()) { + conn.currWriteInvoker = 0; + key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE); + conn.doWrite(true); + } else if (key.isConnectable()) { + key.interestOps(key.interestOps() & ~SelectionKey.OP_CONNECT); + conn.doConnect(); + } + } + } + } catch (Throwable ex) { + if (!this.closed) logger.log(Level.FINE, getName() + " selector run failed", ex); + } + } + } + + public void close() { + this.closed = true; + this.interrupt(); + try { + this.selector.close(); + } catch (Exception e) { + logger.log(Level.FINE, getName() + " selector close failed", e); + } + } +} diff --git a/src/main/java/org/redkale/net/AsyncNioCompletionHandler.java b/src/main/java/org/redkale/net/AsyncNioCompletionHandler.java index b9774efc8..d96cc0fea 100644 --- a/src/main/java/org/redkale/net/AsyncNioCompletionHandler.java +++ b/src/main/java/org/redkale/net/AsyncNioCompletionHandler.java @@ -1,119 +1,119 @@ -/* - * 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; - -import java.nio.ByteBuffer; -import java.nio.channels.CompletionHandler; -import java.util.concurrent.*; - -/** - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * - * @since 2.1.0 - */ -class AsyncNioCompletionHandler implements CompletionHandler, Runnable { - - private final AsyncNioConnection conn; - - private CompletionHandler handler; - - private A attachment; - - public ScheduledFuture timeoutFuture; - - private ByteBuffer[] buffers; - - private ByteBuffer buffer; - - public AsyncNioCompletionHandler(AsyncNioConnection conn) { - this.conn = conn; - } - - public void handler(CompletionHandler handler, A attachment) { - this.handler = handler; - this.attachment = attachment; - } - - public void attachment(A attachment) { - this.attachment = attachment; - } - - public void buffers(ByteBuffer... buffs) { - this.buffers = buffs; - } - - public void buffer(ByteBuffer buff) { - this.buffer = buff; - } - - private void clear() { - this.handler = null; - this.attachment = null; - this.timeoutFuture = null; - this.buffers = null; - this.buffer = null; - } - - @Override - public void completed(Integer result, A attach) { - ScheduledFuture future = this.timeoutFuture; - if (future != null) { - this.timeoutFuture = null; - future.cancel(true); - } - if (conn != null) { - if (buffers != null) { - conn.offerBuffer(buffers); - } else if (buffer != null) { - conn.offerBuffer(buffer); - } - } - CompletionHandler handler0 = handler; - A attachment0 = attachment; - clear(); - handler0.completed(result, attachment0); - } - - @Override - public void failed(Throwable exc, A attach) { - ScheduledFuture future = this.timeoutFuture; - if (future != null) { - this.timeoutFuture = null; - future.cancel(true); - } - if (conn != null) { - if (buffers != null) { - conn.offerBuffer(buffers); - } else if (buffer != null) { - conn.offerBuffer(buffer); - } - } - CompletionHandler handler0 = handler; - A attachment0 = attachment; - clear(); - handler0.failed(exc, attachment0); - } - - @Override - public void run() { - if (conn != null) { - if (buffers != null) { - conn.offerBuffer(buffers); - } else if (buffer != null) { - conn.offerBuffer(buffer); - } - } - CompletionHandler handler0 = handler; - A attachment0 = attachment; - clear(); - handler0.failed(new TimeoutException(), attachment0); - } - -} +/* + * 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; + +import java.nio.ByteBuffer; +import java.nio.channels.CompletionHandler; +import java.util.concurrent.*; + +/** + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.1.0 + */ +class AsyncNioCompletionHandler implements CompletionHandler, Runnable { + + private final AsyncNioConnection conn; + + private CompletionHandler handler; + + private A attachment; + + public ScheduledFuture timeoutFuture; + + private ByteBuffer[] buffers; + + private ByteBuffer buffer; + + public AsyncNioCompletionHandler(AsyncNioConnection conn) { + this.conn = conn; + } + + public void handler(CompletionHandler handler, A attachment) { + this.handler = handler; + this.attachment = attachment; + } + + public void attachment(A attachment) { + this.attachment = attachment; + } + + public void buffers(ByteBuffer... buffs) { + this.buffers = buffs; + } + + public void buffer(ByteBuffer buff) { + this.buffer = buff; + } + + private void clear() { + this.handler = null; + this.attachment = null; + this.timeoutFuture = null; + this.buffers = null; + this.buffer = null; + } + + @Override + public void completed(Integer result, A attach) { + ScheduledFuture future = this.timeoutFuture; + if (future != null) { + this.timeoutFuture = null; + future.cancel(true); + } + if (conn != null) { + if (buffers != null) { + conn.offerBuffer(buffers); + } else if (buffer != null) { + conn.offerBuffer(buffer); + } + } + CompletionHandler handler0 = handler; + A attachment0 = attachment; + clear(); + handler0.completed(result, attachment0); + } + + @Override + public void failed(Throwable exc, A attach) { + ScheduledFuture future = this.timeoutFuture; + if (future != null) { + this.timeoutFuture = null; + future.cancel(true); + } + if (conn != null) { + if (buffers != null) { + conn.offerBuffer(buffers); + } else if (buffer != null) { + conn.offerBuffer(buffer); + } + } + CompletionHandler handler0 = handler; + A attachment0 = attachment; + clear(); + handler0.failed(exc, attachment0); + } + + @Override + public void run() { + if (conn != null) { + if (buffers != null) { + conn.offerBuffer(buffers); + } else if (buffer != null) { + conn.offerBuffer(buffer); + } + } + CompletionHandler handler0 = handler; + A attachment0 = attachment; + clear(); + handler0.failed(new TimeoutException(), attachment0); + } + +} diff --git a/src/main/java/org/redkale/net/AsyncNioConnection.java b/src/main/java/org/redkale/net/AsyncNioConnection.java index a65893f72..e70953984 100644 --- a/src/main/java/org/redkale/net/AsyncNioConnection.java +++ b/src/main/java/org/redkale/net/AsyncNioConnection.java @@ -1,570 +1,570 @@ -/* - * 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; - -import java.io.*; -import java.net.SocketAddress; -import java.nio.ByteBuffer; -import java.nio.channels.*; -import java.util.Objects; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.LongAdder; -import java.util.function.*; -import javax.net.ssl.SSLContext; -import org.redkale.util.*; - -/** - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * - * @since 2.3.0 - */ -abstract class AsyncNioConnection extends AsyncConnection { - - protected static final int MAX_INVOKER_ONSTACK = Integer.getInteger("redkale.net.invoker.max.onstack", 16); - - final AsyncIOThread connectThread; - - protected SocketAddress remoteAddress; - - //-------------------------------- 杩炴搷浣 -------------------------------------- - protected Object connectAttachment; - - protected CompletionHandler connectCompletionHandler; - - protected boolean connectPending; - - protected SelectionKey connectKey; - - //-------------------------------- 璇绘搷浣 -------------------------------------- - protected final AsyncNioCompletionHandler readTimeoutCompletionHandler = new AsyncNioCompletionHandler<>(this); - - protected int readTimeoutSeconds; - - int currReadInvoker; - - protected ByteBuffer readByteBuffer; - - protected CompletionHandler readCompletionHandler; - - protected boolean readPending; - - protected SelectionKey readKey; - - //-------------------------------- 鍐欐搷浣 -------------------------------------- - protected final AsyncNioCompletionHandler writeTimeoutCompletionHandler = new AsyncNioCompletionHandler<>(this); - - protected int writeTimeoutSeconds; - - int currWriteInvoker; - - protected byte[] writeByteTuple1Array; - - protected int writeByteTuple1Offset; - - protected int writeByteTuple1Length; - - protected byte[] writeByteTuple2Array; - - protected int writeByteTuple2Offset; - - protected int writeByteTuple2Length; - - protected Consumer writeByteTuple2Callback; - - protected Object writeByteTuple2Attachment; - - //鍐欐搷浣, 浜岄変竴锛岃涔坵riteByteBuffer鏈夊硷紝瑕佷箞writeByteBuffers銆亀riteOffset銆亀riteLength鏈夊 - protected ByteBuffer writeByteBuffer; - - protected ByteBuffer[] writeByteBuffers; - - protected int writeOffset; - - protected int writeLength; - - protected int writeTotal; - - protected Object writeAttachment; - - protected CompletionHandler writeCompletionHandler; - - protected boolean writePending; - - protected SelectionKey writeKey; - - public AsyncNioConnection(boolean client, AsyncIOGroup ioGroup, AsyncIOThread ioThread, AsyncIOThread connectThread, - final int bufferCapacity, ObjectPool bufferPool, SSLBuilder sslBuilder, SSLContext sslContext, LongAdder livingCounter, LongAdder closedCounter) { - super(client, ioGroup, ioThread, bufferCapacity, bufferPool, sslBuilder, sslContext, livingCounter, closedCounter); - this.connectThread = connectThread; - } - - public AsyncNioConnection(boolean client, AsyncIOGroup ioGroup, AsyncIOThread ioThread, AsyncIOThread connectThread, - final int bufferCapacity, Supplier bufferSupplier, Consumer bufferConsumer, SSLBuilder sslBuilder, SSLContext sslContext, LongAdder livingCounter, LongAdder closedCounter) { - super(client, ioGroup, ioThread, bufferCapacity, bufferSupplier, bufferConsumer, sslBuilder, sslContext, livingCounter, closedCounter); - this.connectThread = connectThread; - } - - @Override - public SocketAddress getRemoteAddress() { - return remoteAddress; - } - - @Override - public void setReadTimeoutSeconds(int readTimeoutSeconds) { - this.readTimeoutSeconds = readTimeoutSeconds; - } - - @Override - public void setWriteTimeoutSeconds(int writeTimeoutSeconds) { - this.writeTimeoutSeconds = writeTimeoutSeconds; - } - - @Override - public int getReadTimeoutSeconds() { - return this.readTimeoutSeconds; - } - - @Override - public int getWriteTimeoutSeconds() { - return this.writeTimeoutSeconds; - } - - @Override - protected void startHandshake(final Consumer callback) { - ((AsyncIOThread) ioThread).register(t -> super.startHandshake(callback)); - } - - @Override - protected void startRead(CompletionHandler handler) { - currReadInvoker = MAX_INVOKER_ONSTACK; - read(handler); - } - - @Override - public void readImpl(CompletionHandler handler) { - Objects.requireNonNull(handler); - if (!this.isConnected()) { - handler.failed(new NotYetConnectedException(), null); - return; - } - if (this.readPending) { - handler.failed(new ReadPendingException(), null); - return; - } - this.readPending = true; - if (this.readTimeoutSeconds > 0) { - AsyncNioCompletionHandler newhandler = this.readTimeoutCompletionHandler; - newhandler.handler(handler, this.readByteBuffer); // new AsyncNioCompletionHandler(handler, this.readByteBuffer); - this.readCompletionHandler = newhandler; - newhandler.timeoutFuture = ioGroup.scheduleTimeout(newhandler, this.readTimeoutSeconds, TimeUnit.SECONDS); - } else { - this.readCompletionHandler = handler; - } - if (client) { - doRead(this.ioThread.inCurrThread()); - } else { - doRead(currReadInvoker < MAX_INVOKER_ONSTACK || this.ioThread.inCurrThread()); //鍚屼竴绾跨▼涓璖elector.wakeup鏃犳晥 - } - } - - @Override - public void write(byte[] headerContent, int headerOffset, int headerLength, byte[] bodyContent, int bodyOffset, int bodyLength, Consumer bodyCallback, Object bodyAttachment, CompletionHandler handler) { - if (sslEngine != null) { - super.write(headerContent, headerOffset, headerLength, bodyContent, bodyOffset, bodyLength, bodyCallback, bodyAttachment, handler); - return; - } - Objects.requireNonNull(headerContent); - Objects.requireNonNull(handler); - if (!this.isConnected()) { - handler.failed(new NotYetConnectedException(), null); - return; - } - if (this.writePending) { - handler.failed(new WritePendingException(), null); - return; - } - this.writePending = true; - this.writeByteTuple1Array = headerContent; - this.writeByteTuple1Offset = headerOffset; - this.writeByteTuple1Length = headerLength; - this.writeByteTuple2Array = bodyContent; - this.writeByteTuple2Offset = bodyOffset; - this.writeByteTuple2Length = bodyLength; - this.writeByteTuple2Callback = bodyCallback; - this.writeByteTuple2Attachment = bodyAttachment; - this.writeAttachment = null; - if (this.writeTimeoutSeconds > 0) { - AsyncNioCompletionHandler newhandler = this.writeTimeoutCompletionHandler; - newhandler.handler(handler, null); // new AsyncNioCompletionHandler(handler, null); - this.writeCompletionHandler = newhandler; - newhandler.timeoutFuture = ioGroup.scheduleTimeout(newhandler, this.writeTimeoutSeconds, TimeUnit.SECONDS); - } else { - AsyncNioCompletionHandler newhandler = this.writeTimeoutCompletionHandler; - newhandler.handler(handler, null); // new AsyncNioCompletionHandler(handler, null); - this.writeCompletionHandler = newhandler; - } - doWrite(true); //濡傛灉涓嶆槸true锛屽垯bodyCallback鐨勬墽琛屽彲鑳戒細鍒囨崲绾跨▼ - } - - @Override - public void writeImpl(ByteBuffer src, A attachment, CompletionHandler handler) { - Objects.requireNonNull(src); - Objects.requireNonNull(handler); - if (!this.isConnected()) { - handler.failed(new NotYetConnectedException(), attachment); - return; - } - if (this.writePending) { - handler.failed(new WritePendingException(), attachment); - return; - } - this.writePending = true; - this.writeByteBuffer = src; - this.writeAttachment = attachment; - if (this.writeTimeoutSeconds > 0) { - AsyncNioCompletionHandler newhandler = this.writeTimeoutCompletionHandler; - newhandler.handler(handler, attachment); // new AsyncNioCompletionHandler(handler, attachment); - this.writeCompletionHandler = newhandler; - newhandler.timeoutFuture = ioGroup.scheduleTimeout(newhandler, this.writeTimeoutSeconds, TimeUnit.SECONDS); - } else { - this.writeCompletionHandler = (CompletionHandler) handler; - } - doWrite(true); // || !client || currWriteInvoker < MAX_INVOKER_ONSTACK // !client && ioThread.workExecutor == null - } - - @Override - public void writeImpl(ByteBuffer[] srcs, int offset, int length, A attachment, CompletionHandler handler) { - Objects.requireNonNull(srcs); - Objects.requireNonNull(handler); - if (!this.isConnected()) { - handler.failed(new NotYetConnectedException(), attachment); - return; - } - if (this.writePending) { - handler.failed(new WritePendingException(), attachment); - return; - } - this.writePending = true; - this.writeByteBuffers = srcs; - this.writeOffset = offset; - this.writeLength = length; - this.writeAttachment = attachment; - if (this.writeTimeoutSeconds > 0) { - AsyncNioCompletionHandler newhandler = this.writeTimeoutCompletionHandler; - newhandler.handler(handler, attachment); // new AsyncNioCompletionHandler(handler, attachment); - this.writeCompletionHandler = newhandler; - newhandler.timeoutFuture = ioGroup.scheduleTimeout(newhandler, this.writeTimeoutSeconds, TimeUnit.SECONDS); - } else { - this.writeCompletionHandler = (CompletionHandler) handler; - } - doWrite(true); // || !client || currWriteInvoker < MAX_INVOKER_ONSTACK // !client && ioThread.workExecutor == null - } - - public void doRead(boolean direct) { - try { - this.readtime = System.currentTimeMillis(); - int readCount = 0; - if (direct) { - currReadInvoker++; - if (this.readByteBuffer == null) { - this.readByteBuffer = sslEngine == null ? pollReadBuffer() : pollReadSSLBuffer(); - if (this.readTimeoutSeconds > 0) { - this.readTimeoutCompletionHandler.attachment(this.readByteBuffer); - } - } - readCount = implRead(readByteBuffer); - } - - if (readCount != 0) { - handleRead(readCount, null); - } else if (readKey == null) { - ((AsyncIOThread) ioThread).register(selector -> { - try { - readKey = implRegister(selector, SelectionKey.OP_READ); - readKey.attach(this); - } catch (ClosedChannelException e) { - handleRead(0, e); - } - }); - } else { - ((AsyncIOGroup) ioGroup).interestOpsOr((AsyncIOThread) ioThread, readKey, SelectionKey.OP_READ); - } - } catch (Exception e) { - handleRead(0, e); - } - } - - public void doWrite(boolean direct) { - try { - this.writetime = System.currentTimeMillis(); - final boolean invokeDirect = direct; - int totalCount = 0; - boolean hasRemain = true; - boolean writeOver = true; - if (invokeDirect) currWriteInvoker++; - while (invokeDirect && hasRemain) { //蹇呴』瑕佸皢buffer鍐欏畬涓烘 - if (writeByteTuple1Array != null) { - final ByteBuffer buffer = pollWriteBuffer(); - if (buffer.remaining() >= writeByteTuple1Length + writeByteTuple2Length) { - buffer.put(writeByteTuple1Array, writeByteTuple1Offset, writeByteTuple1Length); - if (writeByteTuple2Length > 0) { - buffer.put(writeByteTuple2Array, writeByteTuple2Offset, writeByteTuple2Length); - if (writeByteTuple2Callback != null) writeByteTuple2Callback.accept(writeByteTuple2Attachment); - } - buffer.flip(); - writeByteBuffer = buffer; - writeByteTuple1Array = null; - writeByteTuple1Offset = 0; - writeByteTuple1Length = 0; - writeByteTuple2Array = null; - writeByteTuple2Offset = 0; - writeByteTuple2Length = 0; - writeByteTuple2Callback = null; - writeByteTuple2Attachment = null; - } else { - ByteBufferWriter writer = ByteBufferWriter.create(getBufferSupplier(), buffer); - writer.put(writeByteTuple1Array, writeByteTuple1Offset, writeByteTuple1Length); - if (writeByteTuple2Length > 0) { - writer.put(writeByteTuple2Array, writeByteTuple2Offset, writeByteTuple2Length); - if (writeByteTuple2Callback != null) writeByteTuple2Callback.accept(writeByteTuple2Attachment); - } - final ByteBuffer[] buffers = writer.toBuffers(); - writeByteBuffers = buffers; - writeOffset = 0; - writeLength = buffers.length; - writeByteTuple1Array = null; - writeByteTuple1Offset = 0; - writeByteTuple1Length = 0; - writeByteTuple2Array = null; - writeByteTuple2Offset = 0; - writeByteTuple2Length = 0; - writeByteTuple2Callback = null; - writeByteTuple2Attachment = null; - } - if (this.writeCompletionHandler == this.writeTimeoutCompletionHandler) { - if (writeByteBuffer == null) { - this.writeTimeoutCompletionHandler.buffers(writeByteBuffers); - } else { - this.writeTimeoutCompletionHandler.buffer(writeByteBuffer); - } - } - } - int writeCount; - if (writeByteBuffer != null) { - writeCount = implWrite(writeByteBuffer); - hasRemain = writeByteBuffer.hasRemaining(); - } else { - writeCount = implWrite(writeByteBuffers, writeOffset, writeLength); - boolean remain = false; - for (int i = writeByteBuffers.length - 1; i >= writeOffset; i--) { - if (writeByteBuffers[i].hasRemaining()) { - remain = true; - break; - } - } - hasRemain = remain; - } - if (writeCount == 0) { - if (hasRemain) { - writeOver = false; - writeTotal = totalCount; - } - break; - } else if (writeCount < 0) { - if (totalCount == 0) totalCount = writeCount; - break; - } else { - totalCount += writeCount; - } - if (!hasRemain) break; - } - - if (writeOver && (totalCount != 0 || !hasRemain)) { - handleWrite(writeTotal + totalCount, null); - } else if (writeKey == null) { - ((AsyncIOThread) ioThread).register(selector -> { - try { - writeKey = implRegister(selector, SelectionKey.OP_WRITE); - writeKey.attach(this); - } catch (ClosedChannelException e) { - handleWrite(0, e); - } - }); - } else { - ((AsyncIOGroup) ioGroup).interestOpsOr((AsyncIOThread) ioThread, writeKey, SelectionKey.OP_WRITE); - } - } catch (IOException e) { - handleWrite(0, e); - } - } - - protected void handleConnect(Throwable t) { - if (connectKey != null) { - connectKey.cancel(); - connectKey = null; - } - CompletionHandler handler = this.connectCompletionHandler; - Object attach = this.connectAttachment; - - this.connectCompletionHandler = null; - this.connectAttachment = null; - this.connectPending = false;//蹇呴』鏀炬渶鍚 - - if (handler != null) { - if (!client || inCurrThread()) { //client妯″紡涓嬪繀椤讳繚璇乺ead銆亀rite鍦╥oThread鍐呰繍琛 - if (t == null) { - handler.completed(null, attach); - } else { - handler.failed(t, attach); - } - } else { - ioThread.execute(() -> { - if (t == null) { - handler.completed(null, attach); - } else { - handler.failed(t, attach); - } - }); - } - } - } - - protected void handleRead(final int totalCount, Throwable t) { - CompletionHandler handler = this.readCompletionHandler; - ByteBuffer attach = this.readByteBuffer; - //娓呯┖璇诲弬鏁 - this.readCompletionHandler = null; - this.readByteBuffer = null; - this.readPending = false; //蹇呴』鏀炬渶鍚 - - if (handler == null) { - if (t == null) { - protocolCodec.completed(totalCount, attach); - } else { - protocolCodec.failed(t, attach); - } - } else { - if (t == null) { - handler.completed(totalCount, attach); - } else { - handler.failed(t, attach); - } - } - } - - protected void handleWrite(final int totalCount, Throwable t) { - CompletionHandler handler = this.writeCompletionHandler; - Object attach = this.writeAttachment; - //娓呯┖鍐欏弬鏁 - this.writeCompletionHandler = null; - this.writeAttachment = null; - this.writeByteBuffer = null; - this.writeByteBuffers = null; - this.writeOffset = 0; - this.writeLength = 0; - this.writeTotal = 0; - this.writePending = false; //蹇呴』鏀炬渶鍚 - - if (t == null) { - handler.completed(totalCount, attach); - } else { - handler.failed(t, attach); - } - } - - @Deprecated //@since 2.5.0 - protected abstract ReadableByteChannel readableByteChannel(); - - @Deprecated //@since 2.5.0 - protected abstract WritableByteChannel writableByteChannel(); - - protected InputStream newInputStream() { - final ReadableByteChannel reader = readableByteChannel(); - return new InputStream() { - - ByteBuffer bb; - - int count; - - @Override - public synchronized int read() throws IOException { - if (bb == null || !bb.hasRemaining()) { - int r = readBuffer(); - if (r < 1) return -1; - } - return bb.get() & 0xff; - } - - @Override - public synchronized int read(byte b[], int off, int len) throws IOException { - if (b == null) { - throw new NullPointerException(); - } else if (off < 0 || len < 0 || len > b.length - off) { - throw new IndexOutOfBoundsException(); - } else if (len == 0) { - return 0; - } - if (bb == null || !bb.hasRemaining()) { - int r = readBuffer(); - if (r < 1) return -1; - } - int size = Math.min(b.length, Math.min(len, bb.remaining())); - bb.get(b, off, size); - return size; - } - - @Override - public void close() throws IOException { - if (bb != null) { - offerBuffer(bb); - bb = null; - } - reader.close(); - } - - @Override - public int available() throws IOException { - if (bb == null || !bb.hasRemaining()) return 0; - return bb.remaining(); - } - - private int readBuffer() throws IOException { - if (bb == null) { - bb = pollReadBuffer(); - } else { - bb.clear(); - } - try { - int size = reader.read(bb); - bb.flip(); - return size; - } catch (IOException ioe) { - throw ioe; - } catch (Exception e) { - throw new IOException(e); - } - - } - - }; - } - - protected abstract SelectionKey implRegister(Selector sel, int ops) throws ClosedChannelException; - - protected abstract int implRead(ByteBuffer dst) throws IOException; - - protected abstract int implWrite(ByteBuffer src) throws IOException; - - protected abstract int implWrite(ByteBuffer[] srcs, int offset, int length) throws IOException; - - public abstract boolean isConnected(); - - public abstract void doConnect(); -} +/* + * 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; + +import java.io.*; +import java.net.SocketAddress; +import java.nio.ByteBuffer; +import java.nio.channels.*; +import java.util.Objects; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.LongAdder; +import java.util.function.*; +import javax.net.ssl.SSLContext; +import org.redkale.util.*; + +/** + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.3.0 + */ +abstract class AsyncNioConnection extends AsyncConnection { + + protected static final int MAX_INVOKER_ONSTACK = Integer.getInteger("redkale.net.invoker.max.onstack", 16); + + final AsyncIOThread connectThread; + + protected SocketAddress remoteAddress; + + //-------------------------------- 杩炴搷浣 -------------------------------------- + protected Object connectAttachment; + + protected CompletionHandler connectCompletionHandler; + + protected boolean connectPending; + + protected SelectionKey connectKey; + + //-------------------------------- 璇绘搷浣 -------------------------------------- + protected final AsyncNioCompletionHandler readTimeoutCompletionHandler = new AsyncNioCompletionHandler<>(this); + + protected int readTimeoutSeconds; + + int currReadInvoker; + + protected ByteBuffer readByteBuffer; + + protected CompletionHandler readCompletionHandler; + + protected boolean readPending; + + protected SelectionKey readKey; + + //-------------------------------- 鍐欐搷浣 -------------------------------------- + protected final AsyncNioCompletionHandler writeTimeoutCompletionHandler = new AsyncNioCompletionHandler<>(this); + + protected int writeTimeoutSeconds; + + int currWriteInvoker; + + protected byte[] writeByteTuple1Array; + + protected int writeByteTuple1Offset; + + protected int writeByteTuple1Length; + + protected byte[] writeByteTuple2Array; + + protected int writeByteTuple2Offset; + + protected int writeByteTuple2Length; + + protected Consumer writeByteTuple2Callback; + + protected Object writeByteTuple2Attachment; + + //鍐欐搷浣, 浜岄変竴锛岃涔坵riteByteBuffer鏈夊硷紝瑕佷箞writeByteBuffers銆亀riteOffset銆亀riteLength鏈夊 + protected ByteBuffer writeByteBuffer; + + protected ByteBuffer[] writeByteBuffers; + + protected int writeOffset; + + protected int writeLength; + + protected int writeTotal; + + protected Object writeAttachment; + + protected CompletionHandler writeCompletionHandler; + + protected boolean writePending; + + protected SelectionKey writeKey; + + public AsyncNioConnection(boolean client, AsyncIOGroup ioGroup, AsyncIOThread ioThread, AsyncIOThread connectThread, + final int bufferCapacity, ObjectPool bufferPool, SSLBuilder sslBuilder, SSLContext sslContext, LongAdder livingCounter, LongAdder closedCounter) { + super(client, ioGroup, ioThread, bufferCapacity, bufferPool, sslBuilder, sslContext, livingCounter, closedCounter); + this.connectThread = connectThread; + } + + public AsyncNioConnection(boolean client, AsyncIOGroup ioGroup, AsyncIOThread ioThread, AsyncIOThread connectThread, + final int bufferCapacity, Supplier bufferSupplier, Consumer bufferConsumer, SSLBuilder sslBuilder, SSLContext sslContext, LongAdder livingCounter, LongAdder closedCounter) { + super(client, ioGroup, ioThread, bufferCapacity, bufferSupplier, bufferConsumer, sslBuilder, sslContext, livingCounter, closedCounter); + this.connectThread = connectThread; + } + + @Override + public SocketAddress getRemoteAddress() { + return remoteAddress; + } + + @Override + public void setReadTimeoutSeconds(int readTimeoutSeconds) { + this.readTimeoutSeconds = readTimeoutSeconds; + } + + @Override + public void setWriteTimeoutSeconds(int writeTimeoutSeconds) { + this.writeTimeoutSeconds = writeTimeoutSeconds; + } + + @Override + public int getReadTimeoutSeconds() { + return this.readTimeoutSeconds; + } + + @Override + public int getWriteTimeoutSeconds() { + return this.writeTimeoutSeconds; + } + + @Override + protected void startHandshake(final Consumer callback) { + ((AsyncIOThread) ioThread).register(t -> super.startHandshake(callback)); + } + + @Override + protected void startRead(CompletionHandler handler) { + currReadInvoker = MAX_INVOKER_ONSTACK; + read(handler); + } + + @Override + public void readImpl(CompletionHandler handler) { + Objects.requireNonNull(handler); + if (!this.isConnected()) { + handler.failed(new NotYetConnectedException(), null); + return; + } + if (this.readPending) { + handler.failed(new ReadPendingException(), null); + return; + } + this.readPending = true; + if (this.readTimeoutSeconds > 0) { + AsyncNioCompletionHandler newhandler = this.readTimeoutCompletionHandler; + newhandler.handler(handler, this.readByteBuffer); // new AsyncNioCompletionHandler(handler, this.readByteBuffer); + this.readCompletionHandler = newhandler; + newhandler.timeoutFuture = ioGroup.scheduleTimeout(newhandler, this.readTimeoutSeconds, TimeUnit.SECONDS); + } else { + this.readCompletionHandler = handler; + } + if (client) { + doRead(this.ioThread.inCurrThread()); + } else { + doRead(currReadInvoker < MAX_INVOKER_ONSTACK || this.ioThread.inCurrThread()); //鍚屼竴绾跨▼涓璖elector.wakeup鏃犳晥 + } + } + + @Override + public void write(byte[] headerContent, int headerOffset, int headerLength, byte[] bodyContent, int bodyOffset, int bodyLength, Consumer bodyCallback, Object bodyAttachment, CompletionHandler handler) { + if (sslEngine != null) { + super.write(headerContent, headerOffset, headerLength, bodyContent, bodyOffset, bodyLength, bodyCallback, bodyAttachment, handler); + return; + } + Objects.requireNonNull(headerContent); + Objects.requireNonNull(handler); + if (!this.isConnected()) { + handler.failed(new NotYetConnectedException(), null); + return; + } + if (this.writePending) { + handler.failed(new WritePendingException(), null); + return; + } + this.writePending = true; + this.writeByteTuple1Array = headerContent; + this.writeByteTuple1Offset = headerOffset; + this.writeByteTuple1Length = headerLength; + this.writeByteTuple2Array = bodyContent; + this.writeByteTuple2Offset = bodyOffset; + this.writeByteTuple2Length = bodyLength; + this.writeByteTuple2Callback = bodyCallback; + this.writeByteTuple2Attachment = bodyAttachment; + this.writeAttachment = null; + if (this.writeTimeoutSeconds > 0) { + AsyncNioCompletionHandler newhandler = this.writeTimeoutCompletionHandler; + newhandler.handler(handler, null); // new AsyncNioCompletionHandler(handler, null); + this.writeCompletionHandler = newhandler; + newhandler.timeoutFuture = ioGroup.scheduleTimeout(newhandler, this.writeTimeoutSeconds, TimeUnit.SECONDS); + } else { + AsyncNioCompletionHandler newhandler = this.writeTimeoutCompletionHandler; + newhandler.handler(handler, null); // new AsyncNioCompletionHandler(handler, null); + this.writeCompletionHandler = newhandler; + } + doWrite(true); //濡傛灉涓嶆槸true锛屽垯bodyCallback鐨勬墽琛屽彲鑳戒細鍒囨崲绾跨▼ + } + + @Override + public void writeImpl(ByteBuffer src, A attachment, CompletionHandler handler) { + Objects.requireNonNull(src); + Objects.requireNonNull(handler); + if (!this.isConnected()) { + handler.failed(new NotYetConnectedException(), attachment); + return; + } + if (this.writePending) { + handler.failed(new WritePendingException(), attachment); + return; + } + this.writePending = true; + this.writeByteBuffer = src; + this.writeAttachment = attachment; + if (this.writeTimeoutSeconds > 0) { + AsyncNioCompletionHandler newhandler = this.writeTimeoutCompletionHandler; + newhandler.handler(handler, attachment); // new AsyncNioCompletionHandler(handler, attachment); + this.writeCompletionHandler = newhandler; + newhandler.timeoutFuture = ioGroup.scheduleTimeout(newhandler, this.writeTimeoutSeconds, TimeUnit.SECONDS); + } else { + this.writeCompletionHandler = (CompletionHandler) handler; + } + doWrite(true); // || !client || currWriteInvoker < MAX_INVOKER_ONSTACK // !client && ioThread.workExecutor == null + } + + @Override + public void writeImpl(ByteBuffer[] srcs, int offset, int length, A attachment, CompletionHandler handler) { + Objects.requireNonNull(srcs); + Objects.requireNonNull(handler); + if (!this.isConnected()) { + handler.failed(new NotYetConnectedException(), attachment); + return; + } + if (this.writePending) { + handler.failed(new WritePendingException(), attachment); + return; + } + this.writePending = true; + this.writeByteBuffers = srcs; + this.writeOffset = offset; + this.writeLength = length; + this.writeAttachment = attachment; + if (this.writeTimeoutSeconds > 0) { + AsyncNioCompletionHandler newhandler = this.writeTimeoutCompletionHandler; + newhandler.handler(handler, attachment); // new AsyncNioCompletionHandler(handler, attachment); + this.writeCompletionHandler = newhandler; + newhandler.timeoutFuture = ioGroup.scheduleTimeout(newhandler, this.writeTimeoutSeconds, TimeUnit.SECONDS); + } else { + this.writeCompletionHandler = (CompletionHandler) handler; + } + doWrite(true); // || !client || currWriteInvoker < MAX_INVOKER_ONSTACK // !client && ioThread.workExecutor == null + } + + public void doRead(boolean direct) { + try { + this.readtime = System.currentTimeMillis(); + int readCount = 0; + if (direct) { + currReadInvoker++; + if (this.readByteBuffer == null) { + this.readByteBuffer = sslEngine == null ? pollReadBuffer() : pollReadSSLBuffer(); + if (this.readTimeoutSeconds > 0) { + this.readTimeoutCompletionHandler.attachment(this.readByteBuffer); + } + } + readCount = implRead(readByteBuffer); + } + + if (readCount != 0) { + handleRead(readCount, null); + } else if (readKey == null) { + ((AsyncIOThread) ioThread).register(selector -> { + try { + readKey = implRegister(selector, SelectionKey.OP_READ); + readKey.attach(this); + } catch (ClosedChannelException e) { + handleRead(0, e); + } + }); + } else { + ((AsyncIOGroup) ioGroup).interestOpsOr((AsyncIOThread) ioThread, readKey, SelectionKey.OP_READ); + } + } catch (Exception e) { + handleRead(0, e); + } + } + + public void doWrite(boolean direct) { + try { + this.writetime = System.currentTimeMillis(); + final boolean invokeDirect = direct; + int totalCount = 0; + boolean hasRemain = true; + boolean writeOver = true; + if (invokeDirect) currWriteInvoker++; + while (invokeDirect && hasRemain) { //蹇呴』瑕佸皢buffer鍐欏畬涓烘 + if (writeByteTuple1Array != null) { + final ByteBuffer buffer = pollWriteBuffer(); + if (buffer.remaining() >= writeByteTuple1Length + writeByteTuple2Length) { + buffer.put(writeByteTuple1Array, writeByteTuple1Offset, writeByteTuple1Length); + if (writeByteTuple2Length > 0) { + buffer.put(writeByteTuple2Array, writeByteTuple2Offset, writeByteTuple2Length); + if (writeByteTuple2Callback != null) writeByteTuple2Callback.accept(writeByteTuple2Attachment); + } + buffer.flip(); + writeByteBuffer = buffer; + writeByteTuple1Array = null; + writeByteTuple1Offset = 0; + writeByteTuple1Length = 0; + writeByteTuple2Array = null; + writeByteTuple2Offset = 0; + writeByteTuple2Length = 0; + writeByteTuple2Callback = null; + writeByteTuple2Attachment = null; + } else { + ByteBufferWriter writer = ByteBufferWriter.create(getBufferSupplier(), buffer); + writer.put(writeByteTuple1Array, writeByteTuple1Offset, writeByteTuple1Length); + if (writeByteTuple2Length > 0) { + writer.put(writeByteTuple2Array, writeByteTuple2Offset, writeByteTuple2Length); + if (writeByteTuple2Callback != null) writeByteTuple2Callback.accept(writeByteTuple2Attachment); + } + final ByteBuffer[] buffers = writer.toBuffers(); + writeByteBuffers = buffers; + writeOffset = 0; + writeLength = buffers.length; + writeByteTuple1Array = null; + writeByteTuple1Offset = 0; + writeByteTuple1Length = 0; + writeByteTuple2Array = null; + writeByteTuple2Offset = 0; + writeByteTuple2Length = 0; + writeByteTuple2Callback = null; + writeByteTuple2Attachment = null; + } + if (this.writeCompletionHandler == this.writeTimeoutCompletionHandler) { + if (writeByteBuffer == null) { + this.writeTimeoutCompletionHandler.buffers(writeByteBuffers); + } else { + this.writeTimeoutCompletionHandler.buffer(writeByteBuffer); + } + } + } + int writeCount; + if (writeByteBuffer != null) { + writeCount = implWrite(writeByteBuffer); + hasRemain = writeByteBuffer.hasRemaining(); + } else { + writeCount = implWrite(writeByteBuffers, writeOffset, writeLength); + boolean remain = false; + for (int i = writeByteBuffers.length - 1; i >= writeOffset; i--) { + if (writeByteBuffers[i].hasRemaining()) { + remain = true; + break; + } + } + hasRemain = remain; + } + if (writeCount == 0) { + if (hasRemain) { + writeOver = false; + writeTotal = totalCount; + } + break; + } else if (writeCount < 0) { + if (totalCount == 0) totalCount = writeCount; + break; + } else { + totalCount += writeCount; + } + if (!hasRemain) break; + } + + if (writeOver && (totalCount != 0 || !hasRemain)) { + handleWrite(writeTotal + totalCount, null); + } else if (writeKey == null) { + ((AsyncIOThread) ioThread).register(selector -> { + try { + writeKey = implRegister(selector, SelectionKey.OP_WRITE); + writeKey.attach(this); + } catch (ClosedChannelException e) { + handleWrite(0, e); + } + }); + } else { + ((AsyncIOGroup) ioGroup).interestOpsOr((AsyncIOThread) ioThread, writeKey, SelectionKey.OP_WRITE); + } + } catch (IOException e) { + handleWrite(0, e); + } + } + + protected void handleConnect(Throwable t) { + if (connectKey != null) { + connectKey.cancel(); + connectKey = null; + } + CompletionHandler handler = this.connectCompletionHandler; + Object attach = this.connectAttachment; + + this.connectCompletionHandler = null; + this.connectAttachment = null; + this.connectPending = false;//蹇呴』鏀炬渶鍚 + + if (handler != null) { + if (!client || inCurrThread()) { //client妯″紡涓嬪繀椤讳繚璇乺ead銆亀rite鍦╥oThread鍐呰繍琛 + if (t == null) { + handler.completed(null, attach); + } else { + handler.failed(t, attach); + } + } else { + ioThread.execute(() -> { + if (t == null) { + handler.completed(null, attach); + } else { + handler.failed(t, attach); + } + }); + } + } + } + + protected void handleRead(final int totalCount, Throwable t) { + CompletionHandler handler = this.readCompletionHandler; + ByteBuffer attach = this.readByteBuffer; + //娓呯┖璇诲弬鏁 + this.readCompletionHandler = null; + this.readByteBuffer = null; + this.readPending = false; //蹇呴』鏀炬渶鍚 + + if (handler == null) { + if (t == null) { + protocolCodec.completed(totalCount, attach); + } else { + protocolCodec.failed(t, attach); + } + } else { + if (t == null) { + handler.completed(totalCount, attach); + } else { + handler.failed(t, attach); + } + } + } + + protected void handleWrite(final int totalCount, Throwable t) { + CompletionHandler handler = this.writeCompletionHandler; + Object attach = this.writeAttachment; + //娓呯┖鍐欏弬鏁 + this.writeCompletionHandler = null; + this.writeAttachment = null; + this.writeByteBuffer = null; + this.writeByteBuffers = null; + this.writeOffset = 0; + this.writeLength = 0; + this.writeTotal = 0; + this.writePending = false; //蹇呴』鏀炬渶鍚 + + if (t == null) { + handler.completed(totalCount, attach); + } else { + handler.failed(t, attach); + } + } + + @Deprecated //@since 2.5.0 + protected abstract ReadableByteChannel readableByteChannel(); + + @Deprecated //@since 2.5.0 + protected abstract WritableByteChannel writableByteChannel(); + + protected InputStream newInputStream() { + final ReadableByteChannel reader = readableByteChannel(); + return new InputStream() { + + ByteBuffer bb; + + int count; + + @Override + public synchronized int read() throws IOException { + if (bb == null || !bb.hasRemaining()) { + int r = readBuffer(); + if (r < 1) return -1; + } + return bb.get() & 0xff; + } + + @Override + public synchronized int read(byte b[], int off, int len) throws IOException { + if (b == null) { + throw new NullPointerException(); + } else if (off < 0 || len < 0 || len > b.length - off) { + throw new IndexOutOfBoundsException(); + } else if (len == 0) { + return 0; + } + if (bb == null || !bb.hasRemaining()) { + int r = readBuffer(); + if (r < 1) return -1; + } + int size = Math.min(b.length, Math.min(len, bb.remaining())); + bb.get(b, off, size); + return size; + } + + @Override + public void close() throws IOException { + if (bb != null) { + offerBuffer(bb); + bb = null; + } + reader.close(); + } + + @Override + public int available() throws IOException { + if (bb == null || !bb.hasRemaining()) return 0; + return bb.remaining(); + } + + private int readBuffer() throws IOException { + if (bb == null) { + bb = pollReadBuffer(); + } else { + bb.clear(); + } + try { + int size = reader.read(bb); + bb.flip(); + return size; + } catch (IOException ioe) { + throw ioe; + } catch (Exception e) { + throw new IOException(e); + } + + } + + }; + } + + protected abstract SelectionKey implRegister(Selector sel, int ops) throws ClosedChannelException; + + protected abstract int implRead(ByteBuffer dst) throws IOException; + + protected abstract int implWrite(ByteBuffer src) throws IOException; + + protected abstract int implWrite(ByteBuffer[] srcs, int offset, int length) throws IOException; + + public abstract boolean isConnected(); + + public abstract void doConnect(); +} diff --git a/src/main/java/org/redkale/net/AsyncNioTcpConnection.java b/src/main/java/org/redkale/net/AsyncNioTcpConnection.java index 860ff96e2..aa58d9295 100644 --- a/src/main/java/org/redkale/net/AsyncNioTcpConnection.java +++ b/src/main/java/org/redkale/net/AsyncNioTcpConnection.java @@ -1,292 +1,292 @@ -/* - * 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; - -import java.io.*; -import java.net.*; -import java.nio.*; -import java.nio.channels.*; -import java.util.*; -import java.util.concurrent.atomic.LongAdder; -import java.util.function.*; -import javax.net.ssl.SSLContext; -import org.redkale.util.ByteBufferReader; - -/** - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * - * @since 2.1.0 - */ -class AsyncNioTcpConnection extends AsyncNioConnection { - - private final SocketChannel channel; - - public AsyncNioTcpConnection(boolean client, AsyncIOGroup ioGroup, AsyncIOThread ioThread, AsyncIOThread connectThread, - SocketChannel ch, SSLBuilder sslBuilder, SSLContext sslContext, final SocketAddress addr0, LongAdder livingCounter, LongAdder closedCounter) { - super(client, ioGroup, ioThread, connectThread, ioGroup.bufferCapacity, ioThread.getBufferSupplier(), ioThread.getBufferConsumer(), sslBuilder, sslContext, livingCounter, closedCounter); - this.channel = ch; - SocketAddress addr = addr0; - if (addr == null) { - try { - addr = ch.getRemoteAddress(); - } catch (Exception e) { - //do nothing - } - } - this.remoteAddress = addr; - ioThread.connCounter.incrementAndGet(); - } - - public AsyncNioTcpConnection(boolean client, AsyncIOGroup ioGroup, AsyncIOThread ioThread, AsyncIOThread connectThread, Supplier bufferSupplier, Consumer bufferConsumer, - SocketChannel ch, SSLBuilder sslBuilder, SSLContext sslContext, final SocketAddress addr0, LongAdder livingCounter, LongAdder closedCounter) { - super(client, ioGroup, ioThread, connectThread, ioGroup.bufferCapacity, bufferSupplier, bufferConsumer, sslBuilder, sslContext, livingCounter, closedCounter); - this.channel = ch; - SocketAddress addr = addr0; - if (addr == null) { - try { - addr = ch.getRemoteAddress(); - } catch (Exception e) { - //do nothing - } - } - this.remoteAddress = addr; - } - - @Override - public boolean isOpen() { - return this.channel.isOpen(); - } - - @Override - public boolean isTCP() { - return true; - } - - @Override - public boolean shutdownInput() { - try { - this.channel.shutdownInput(); - return true; - } catch (IOException e) { - return false; - } - } - - @Override - public boolean shutdownOutput() { - try { - this.channel.shutdownOutput(); - return true; - } catch (IOException e) { - return false; - } - } - - @Override - public boolean setOption(SocketOption name, T value) { - try { - this.channel.setOption(name, value); - return true; - } catch (IOException e) { - return false; - } - } - - @Override - public Set> supportedOptions() { - return this.channel.supportedOptions(); - } - - @Override - public SocketAddress getLocalAddress() { - try { - return channel.getLocalAddress(); - } catch (IOException e) { - return null; - } - } - - public ReadableByteChannel readableByteChannel() { - if (this.sslEngine == null) return this.channel; - - AsyncConnection self = this; - return new ReadableByteChannel() { - //ssl瑙e瘑鍚庣殑鍗婂寘鏁版嵁 - ByteBuffer halfBuffer; - - @Override - public int read(final ByteBuffer bb) throws IOException { - if (halfBuffer != null) { - int pos = bb.position(); - while (bb.hasRemaining() && halfBuffer.hasRemaining()) { - bb.put(halfBuffer.get()); - } - if (!halfBuffer.hasRemaining()) { - offerBuffer(halfBuffer); - halfBuffer = null; - } - return bb.position() - pos; - } - ByteBuffer netBuffer = pollReadSSLBuffer(); - channel.read(netBuffer); - netBuffer.flip(); - if (netBuffer.hasRemaining()) { - ByteBuffer appBuffer = sslUnwrap(false, netBuffer); - if (appBuffer == null) return -1; //CLOSED锛宯etBuffer宸茶鍥炴敹 - - appBuffer.flip(); - int pos = bb.position(); - while (bb.hasRemaining() && appBuffer.hasRemaining()) bb.put(appBuffer.get()); - if (appBuffer.hasRemaining()) { - halfBuffer = appBuffer; - } else { - offerBuffer(appBuffer); - } - return bb.position() - pos; - } else { - offerBuffer(netBuffer); - return 0; - } - } - - @Override - public boolean isOpen() { - return self.isOpen(); - } - - @Override - public void close() throws IOException { - if (halfBuffer != null) { - offerBuffer(halfBuffer); - halfBuffer = null; - } - self.close(); - } - - }; - } - - @Override - public WritableByteChannel writableByteChannel() { - if (this.sslEngine == null) return this.channel; - - AsyncConnection self = this; - return new WritableByteChannel() { - - @Override - public int write(final ByteBuffer src) throws IOException { - int remain = src.remaining(); - ByteBuffer[] netBuffers = sslWrap(false, src); - int len = remain - src.remaining(); - if (netBuffers.length == 1) { - while (netBuffers[0].hasRemaining()) { - channel.write(netBuffers[0]); - } - } else { - while (ByteBufferReader.hasRemaining(netBuffers)) { - channel.write(netBuffers); - } - } - offerBuffer(netBuffers); - return len; - } - - @Override - public boolean isOpen() { - return self.isOpen(); - } - - @Override - public void close() throws IOException { - self.close(); - } - }; - } - - @Override - public boolean isConnected() { - return this.channel.isConnected(); - } - - @Override - protected SelectionKey implRegister(Selector sel, int ops) throws ClosedChannelException { - return this.channel.register(sel, ops); - } - - @Override - protected int implRead(ByteBuffer dst) throws IOException { - return this.channel.read(dst); - } - - @Override - protected int implWrite(ByteBuffer src) throws IOException { - return this.channel.write(src); - } - - @Override - protected int implWrite(ByteBuffer[] srcs, int offset, int length) throws IOException { - return (int) this.channel.write(srcs, offset, length); - } - - public void connect(SocketAddress remote, A attachment, CompletionHandler handler) { - if (channel.isConnected()) { - throw new AlreadyConnectedException(); - } - if (connectPending) { - throw new ConnectionPendingException(); - } - connectPending = true; - this.connectAttachment = attachment; - this.connectCompletionHandler = (CompletionHandler) handler; - this.remoteAddress = remote; - doConnect(); - } - - @Override - public void doConnect() { - try { - boolean connected = channel.isConnectionPending(); - if (connected || channel.connect(remoteAddress)) { - connected = channel.finishConnect(); - } - if (connected) { - handleConnect(null); - } else if (connectKey == null) { - connectThread.register(selector -> { - try { - connectKey = channel.register(selector, SelectionKey.OP_CONNECT); - connectKey.attach(this); - } catch (ClosedChannelException e) { - handleConnect(e); - } - }); - } else { - handleConnect(new IOException()); - } - } catch (ConnectException ex) { - handleConnect(new IOException(remoteAddress + " connect error", ex)); - } catch (IOException e) { - handleConnect(e); - } - } - - @Override - public final void close() throws IOException { - super.close(); - ((AsyncIOThread) ioThread).connCounter.decrementAndGet(); - channel.shutdownInput(); - channel.shutdownOutput(); - channel.close(); - if (this.connectKey != null) this.connectKey.cancel(); - if (this.readKey != null) this.readKey.cancel(); - if (this.writeKey != null) this.writeKey.cancel(); - } - -} +/* + * 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; + +import java.io.*; +import java.net.*; +import java.nio.*; +import java.nio.channels.*; +import java.util.*; +import java.util.concurrent.atomic.LongAdder; +import java.util.function.*; +import javax.net.ssl.SSLContext; +import org.redkale.util.ByteBufferReader; + +/** + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.1.0 + */ +class AsyncNioTcpConnection extends AsyncNioConnection { + + private final SocketChannel channel; + + public AsyncNioTcpConnection(boolean client, AsyncIOGroup ioGroup, AsyncIOThread ioThread, AsyncIOThread connectThread, + SocketChannel ch, SSLBuilder sslBuilder, SSLContext sslContext, final SocketAddress addr0, LongAdder livingCounter, LongAdder closedCounter) { + super(client, ioGroup, ioThread, connectThread, ioGroup.bufferCapacity, ioThread.getBufferSupplier(), ioThread.getBufferConsumer(), sslBuilder, sslContext, livingCounter, closedCounter); + this.channel = ch; + SocketAddress addr = addr0; + if (addr == null) { + try { + addr = ch.getRemoteAddress(); + } catch (Exception e) { + //do nothing + } + } + this.remoteAddress = addr; + ioThread.connCounter.incrementAndGet(); + } + + public AsyncNioTcpConnection(boolean client, AsyncIOGroup ioGroup, AsyncIOThread ioThread, AsyncIOThread connectThread, Supplier bufferSupplier, Consumer bufferConsumer, + SocketChannel ch, SSLBuilder sslBuilder, SSLContext sslContext, final SocketAddress addr0, LongAdder livingCounter, LongAdder closedCounter) { + super(client, ioGroup, ioThread, connectThread, ioGroup.bufferCapacity, bufferSupplier, bufferConsumer, sslBuilder, sslContext, livingCounter, closedCounter); + this.channel = ch; + SocketAddress addr = addr0; + if (addr == null) { + try { + addr = ch.getRemoteAddress(); + } catch (Exception e) { + //do nothing + } + } + this.remoteAddress = addr; + } + + @Override + public boolean isOpen() { + return this.channel.isOpen(); + } + + @Override + public boolean isTCP() { + return true; + } + + @Override + public boolean shutdownInput() { + try { + this.channel.shutdownInput(); + return true; + } catch (IOException e) { + return false; + } + } + + @Override + public boolean shutdownOutput() { + try { + this.channel.shutdownOutput(); + return true; + } catch (IOException e) { + return false; + } + } + + @Override + public boolean setOption(SocketOption name, T value) { + try { + this.channel.setOption(name, value); + return true; + } catch (IOException e) { + return false; + } + } + + @Override + public Set> supportedOptions() { + return this.channel.supportedOptions(); + } + + @Override + public SocketAddress getLocalAddress() { + try { + return channel.getLocalAddress(); + } catch (IOException e) { + return null; + } + } + + public ReadableByteChannel readableByteChannel() { + if (this.sslEngine == null) return this.channel; + + AsyncConnection self = this; + return new ReadableByteChannel() { + //ssl瑙e瘑鍚庣殑鍗婂寘鏁版嵁 + ByteBuffer halfBuffer; + + @Override + public int read(final ByteBuffer bb) throws IOException { + if (halfBuffer != null) { + int pos = bb.position(); + while (bb.hasRemaining() && halfBuffer.hasRemaining()) { + bb.put(halfBuffer.get()); + } + if (!halfBuffer.hasRemaining()) { + offerBuffer(halfBuffer); + halfBuffer = null; + } + return bb.position() - pos; + } + ByteBuffer netBuffer = pollReadSSLBuffer(); + channel.read(netBuffer); + netBuffer.flip(); + if (netBuffer.hasRemaining()) { + ByteBuffer appBuffer = sslUnwrap(false, netBuffer); + if (appBuffer == null) return -1; //CLOSED锛宯etBuffer宸茶鍥炴敹 + + appBuffer.flip(); + int pos = bb.position(); + while (bb.hasRemaining() && appBuffer.hasRemaining()) bb.put(appBuffer.get()); + if (appBuffer.hasRemaining()) { + halfBuffer = appBuffer; + } else { + offerBuffer(appBuffer); + } + return bb.position() - pos; + } else { + offerBuffer(netBuffer); + return 0; + } + } + + @Override + public boolean isOpen() { + return self.isOpen(); + } + + @Override + public void close() throws IOException { + if (halfBuffer != null) { + offerBuffer(halfBuffer); + halfBuffer = null; + } + self.close(); + } + + }; + } + + @Override + public WritableByteChannel writableByteChannel() { + if (this.sslEngine == null) return this.channel; + + AsyncConnection self = this; + return new WritableByteChannel() { + + @Override + public int write(final ByteBuffer src) throws IOException { + int remain = src.remaining(); + ByteBuffer[] netBuffers = sslWrap(false, src); + int len = remain - src.remaining(); + if (netBuffers.length == 1) { + while (netBuffers[0].hasRemaining()) { + channel.write(netBuffers[0]); + } + } else { + while (ByteBufferReader.hasRemaining(netBuffers)) { + channel.write(netBuffers); + } + } + offerBuffer(netBuffers); + return len; + } + + @Override + public boolean isOpen() { + return self.isOpen(); + } + + @Override + public void close() throws IOException { + self.close(); + } + }; + } + + @Override + public boolean isConnected() { + return this.channel.isConnected(); + } + + @Override + protected SelectionKey implRegister(Selector sel, int ops) throws ClosedChannelException { + return this.channel.register(sel, ops); + } + + @Override + protected int implRead(ByteBuffer dst) throws IOException { + return this.channel.read(dst); + } + + @Override + protected int implWrite(ByteBuffer src) throws IOException { + return this.channel.write(src); + } + + @Override + protected int implWrite(ByteBuffer[] srcs, int offset, int length) throws IOException { + return (int) this.channel.write(srcs, offset, length); + } + + public void connect(SocketAddress remote, A attachment, CompletionHandler handler) { + if (channel.isConnected()) { + throw new AlreadyConnectedException(); + } + if (connectPending) { + throw new ConnectionPendingException(); + } + connectPending = true; + this.connectAttachment = attachment; + this.connectCompletionHandler = (CompletionHandler) handler; + this.remoteAddress = remote; + doConnect(); + } + + @Override + public void doConnect() { + try { + boolean connected = channel.isConnectionPending(); + if (connected || channel.connect(remoteAddress)) { + connected = channel.finishConnect(); + } + if (connected) { + handleConnect(null); + } else if (connectKey == null) { + connectThread.register(selector -> { + try { + connectKey = channel.register(selector, SelectionKey.OP_CONNECT); + connectKey.attach(this); + } catch (ClosedChannelException e) { + handleConnect(e); + } + }); + } else { + handleConnect(new IOException()); + } + } catch (ConnectException ex) { + handleConnect(new IOException(remoteAddress + " connect error", ex)); + } catch (IOException e) { + handleConnect(e); + } + } + + @Override + public final void close() throws IOException { + super.close(); + ((AsyncIOThread) ioThread).connCounter.decrementAndGet(); + channel.shutdownInput(); + channel.shutdownOutput(); + channel.close(); + if (this.connectKey != null) this.connectKey.cancel(); + if (this.readKey != null) this.readKey.cancel(); + if (this.writeKey != null) this.writeKey.cancel(); + } + +} diff --git a/src/main/java/org/redkale/net/AsyncNioTcpProtocolServer.java b/src/main/java/org/redkale/net/AsyncNioTcpProtocolServer.java index 4331d7e55..88fb1f50d 100644 --- a/src/main/java/org/redkale/net/AsyncNioTcpProtocolServer.java +++ b/src/main/java/org/redkale/net/AsyncNioTcpProtocolServer.java @@ -1,209 +1,209 @@ -/* - * 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; - -import java.io.IOException; -import java.net.*; -import java.nio.ByteBuffer; -import java.nio.channels.*; -import java.util.*; -import java.util.concurrent.atomic.LongAdder; -import java.util.function.*; -import java.util.logging.Level; -import org.redkale.boot.Application; -import org.redkale.util.*; - -/** - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * - * @since 2.1.0 - */ -class AsyncNioTcpProtocolServer extends ProtocolServer { - - private ServerSocketChannel serverChannel; - - private Selector selector; - - private AsyncIOGroup ioGroup; - - private Thread acceptThread; - - private boolean closed; - - private Supplier responseSupplier; - - private Consumer responseConsumer; - - public AsyncNioTcpProtocolServer(Context context) { - super(context); - } - - @Override - public void open(AnyValue config) throws IOException { - this.serverChannel = ServerSocketChannel.open(); - this.serverChannel.configureBlocking(false); - this.selector = Selector.open(); - final Set> options = this.serverChannel.supportedOptions(); - if (options.contains(StandardSocketOptions.TCP_NODELAY)) { - this.serverChannel.setOption(StandardSocketOptions.TCP_NODELAY, true); - } - if (options.contains(StandardSocketOptions.SO_KEEPALIVE)) { - this.serverChannel.setOption(StandardSocketOptions.SO_KEEPALIVE, true); - } - if (options.contains(StandardSocketOptions.SO_REUSEADDR)) { - this.serverChannel.setOption(StandardSocketOptions.SO_REUSEADDR, true); - } - if (options.contains(StandardSocketOptions.SO_RCVBUF)) { - this.serverChannel.setOption(StandardSocketOptions.SO_RCVBUF, 16 * 1024); - } - if (options.contains(StandardSocketOptions.SO_SNDBUF)) { - this.serverChannel.setOption(StandardSocketOptions.SO_SNDBUF, 16 * 1024); - } - } - - @Override - public void bind(SocketAddress local, int backlog) throws IOException { - this.serverChannel.bind(local, backlog); - } - - @Override - public Set> supportedOptions() { - return this.serverChannel.supportedOptions(); - } - - @Override - public void setOption(SocketOption name, T value) throws IOException { - this.serverChannel.setOption(name, value); - } - - @Override - public void accept(Application application, Server server) throws IOException { - this.serverChannel.register(this.selector, SelectionKey.OP_ACCEPT); - - LongAdder createBufferCounter = new LongAdder(); - LongAdder cycleBufferCounter = new LongAdder(); - LongAdder createResponseCounter = new LongAdder(); - LongAdder cycleResponseCounter = new LongAdder(); - - ObjectPool bufferPool = server.createBufferPool(createBufferCounter, cycleBufferCounter, server.bufferPoolSize); - ObjectPool safeResponsePool = server.createResponsePool(createResponseCounter, cycleResponseCounter, server.responsePoolSize); - final int respPoolMax = server.getResponsePoolSize(); - ThreadLocal> localResponsePool = ThreadLocal.withInitial(() -> { - if (!(Thread.currentThread() instanceof WorkThread)) return null; - return ObjectPool.createUnsafePool(safeResponsePool, safeResponsePool.getCreatCounter(), - safeResponsePool.getCycleCounter(), respPoolMax, safeResponsePool.getCreator(), safeResponsePool.getPrepare(), safeResponsePool.getRecycler()); - }); - this.responseSupplier = () -> { - ObjectPool pool = localResponsePool.get(); - return pool == null ? safeResponsePool.get() : pool.get(); - }; - this.responseConsumer = (v) -> { - if (Thread.currentThread() != v.thread && v.thread != null) { - v.thread.execute(() -> { - ObjectPool pool = localResponsePool.get(); - (pool == null ? safeResponsePool : pool).accept(v); - }); - return; - } - ObjectPool pool = localResponsePool.get(); - (pool == null ? safeResponsePool : pool).accept(v); - }; - final String threadPrefixName = server.name == null || server.name.isEmpty() ? "Redkale-IOServletThread" : ("Redkale-" + server.name.replace("Server-", "") + "-IOServletThread"); - this.ioGroup = new AsyncIOGroup(false, threadPrefixName, null, server.bufferCapacity, bufferPool); - this.ioGroup.start(); - - this.acceptThread = new Thread() { - { - setName(threadPrefixName.replace("ServletThread", "AcceptThread")); - } - - @Override - public void run() { - while (!closed) { - try { - int count = selector.select(); - if (count == 0) continue; - Set keys = selector.selectedKeys(); - Iterator it = keys.iterator(); - while (it.hasNext()) { - SelectionKey key = it.next(); - it.remove(); - if (key.isAcceptable()) accept(key); - } - } catch (Throwable t) { - server.logger.log(Level.SEVERE, "server accept error", t); - } - } - } - }; - this.acceptThread.start(); - } - - private void accept(SelectionKey key) throws IOException { - SocketChannel channel = this.serverChannel.accept(); - channel.configureBlocking(false); - channel.setOption(StandardSocketOptions.TCP_NODELAY, true); - channel.setOption(StandardSocketOptions.SO_KEEPALIVE, true); - channel.setOption(StandardSocketOptions.SO_REUSEADDR, true); - channel.setOption(StandardSocketOptions.SO_RCVBUF, 16 * 1024); - channel.setOption(StandardSocketOptions.SO_SNDBUF, 16 * 1024); - AsyncIOThread readThread = ioGroup.nextIOThread(); - LongAdder connCreateCounter = ioGroup.connCreateCounter; - if (connCreateCounter != null) connCreateCounter.increment(); - LongAdder connLivingCounter = ioGroup.connLivingCounter; - if (connLivingCounter != null) connLivingCounter.increment(); - AsyncNioTcpConnection conn = new AsyncNioTcpConnection(false, ioGroup, readThread, ioGroup.connectThread(), channel, context.getSSLBuilder(), context.getSSLContext(), null, connLivingCounter, ioGroup.connClosedCounter); - ProtocolCodec codec = new ProtocolCodec(context, responseSupplier, responseConsumer, conn); - conn.protocolCodec = codec; - if (conn.sslEngine == null) { - codec.start(null); - } else { - conn.startHandshake(t -> { - if (t == null) { - codec.start(null); - } else if (t instanceof RuntimeException) { - throw (RuntimeException) t; - } else { - throw new RuntimeException(t); - } - }); - } - } - - @Override - public void close() throws IOException { - if (this.closed) return; - this.closed = true; - this.selector.wakeup(); - this.ioGroup.close(); - this.serverChannel.close(); - this.selector.close(); - } - - @Override - public AsyncGroup getAsyncGroup() { - return ioGroup; - } - - @Override - public long getCreateConnectionCount() { - return ioGroup.connCreateCounter == null ? -1 : ioGroup.connCreateCounter.longValue(); - } - - @Override - public long getClosedConnectionCount() { - return ioGroup.connClosedCounter == null ? -1 : ioGroup.connClosedCounter.longValue(); - } - - @Override - public long getLivingConnectionCount() { - return ioGroup.connLivingCounter == null ? -1 : ioGroup.connLivingCounter.longValue(); - } -} +/* + * 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; + +import java.io.IOException; +import java.net.*; +import java.nio.ByteBuffer; +import java.nio.channels.*; +import java.util.*; +import java.util.concurrent.atomic.LongAdder; +import java.util.function.*; +import java.util.logging.Level; +import org.redkale.boot.Application; +import org.redkale.util.*; + +/** + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.1.0 + */ +class AsyncNioTcpProtocolServer extends ProtocolServer { + + private ServerSocketChannel serverChannel; + + private Selector selector; + + private AsyncIOGroup ioGroup; + + private Thread acceptThread; + + private boolean closed; + + private Supplier responseSupplier; + + private Consumer responseConsumer; + + public AsyncNioTcpProtocolServer(Context context) { + super(context); + } + + @Override + public void open(AnyValue config) throws IOException { + this.serverChannel = ServerSocketChannel.open(); + this.serverChannel.configureBlocking(false); + this.selector = Selector.open(); + final Set> options = this.serverChannel.supportedOptions(); + if (options.contains(StandardSocketOptions.TCP_NODELAY)) { + this.serverChannel.setOption(StandardSocketOptions.TCP_NODELAY, true); + } + if (options.contains(StandardSocketOptions.SO_KEEPALIVE)) { + this.serverChannel.setOption(StandardSocketOptions.SO_KEEPALIVE, true); + } + if (options.contains(StandardSocketOptions.SO_REUSEADDR)) { + this.serverChannel.setOption(StandardSocketOptions.SO_REUSEADDR, true); + } + if (options.contains(StandardSocketOptions.SO_RCVBUF)) { + this.serverChannel.setOption(StandardSocketOptions.SO_RCVBUF, 16 * 1024); + } + if (options.contains(StandardSocketOptions.SO_SNDBUF)) { + this.serverChannel.setOption(StandardSocketOptions.SO_SNDBUF, 16 * 1024); + } + } + + @Override + public void bind(SocketAddress local, int backlog) throws IOException { + this.serverChannel.bind(local, backlog); + } + + @Override + public Set> supportedOptions() { + return this.serverChannel.supportedOptions(); + } + + @Override + public void setOption(SocketOption name, T value) throws IOException { + this.serverChannel.setOption(name, value); + } + + @Override + public void accept(Application application, Server server) throws IOException { + this.serverChannel.register(this.selector, SelectionKey.OP_ACCEPT); + + LongAdder createBufferCounter = new LongAdder(); + LongAdder cycleBufferCounter = new LongAdder(); + LongAdder createResponseCounter = new LongAdder(); + LongAdder cycleResponseCounter = new LongAdder(); + + ObjectPool bufferPool = server.createBufferPool(createBufferCounter, cycleBufferCounter, server.bufferPoolSize); + ObjectPool safeResponsePool = server.createResponsePool(createResponseCounter, cycleResponseCounter, server.responsePoolSize); + final int respPoolMax = server.getResponsePoolSize(); + ThreadLocal> localResponsePool = ThreadLocal.withInitial(() -> { + if (!(Thread.currentThread() instanceof WorkThread)) return null; + return ObjectPool.createUnsafePool(safeResponsePool, safeResponsePool.getCreatCounter(), + safeResponsePool.getCycleCounter(), respPoolMax, safeResponsePool.getCreator(), safeResponsePool.getPrepare(), safeResponsePool.getRecycler()); + }); + this.responseSupplier = () -> { + ObjectPool pool = localResponsePool.get(); + return pool == null ? safeResponsePool.get() : pool.get(); + }; + this.responseConsumer = (v) -> { + if (Thread.currentThread() != v.thread && v.thread != null) { + v.thread.execute(() -> { + ObjectPool pool = localResponsePool.get(); + (pool == null ? safeResponsePool : pool).accept(v); + }); + return; + } + ObjectPool pool = localResponsePool.get(); + (pool == null ? safeResponsePool : pool).accept(v); + }; + final String threadPrefixName = server.name == null || server.name.isEmpty() ? "Redkale-IOServletThread" : ("Redkale-" + server.name.replace("Server-", "") + "-IOServletThread"); + this.ioGroup = new AsyncIOGroup(false, threadPrefixName, null, server.bufferCapacity, bufferPool); + this.ioGroup.start(); + + this.acceptThread = new Thread() { + { + setName(threadPrefixName.replace("ServletThread", "AcceptThread")); + } + + @Override + public void run() { + while (!closed) { + try { + int count = selector.select(); + if (count == 0) continue; + Set keys = selector.selectedKeys(); + Iterator it = keys.iterator(); + while (it.hasNext()) { + SelectionKey key = it.next(); + it.remove(); + if (key.isAcceptable()) accept(key); + } + } catch (Throwable t) { + server.logger.log(Level.SEVERE, "server accept error", t); + } + } + } + }; + this.acceptThread.start(); + } + + private void accept(SelectionKey key) throws IOException { + SocketChannel channel = this.serverChannel.accept(); + channel.configureBlocking(false); + channel.setOption(StandardSocketOptions.TCP_NODELAY, true); + channel.setOption(StandardSocketOptions.SO_KEEPALIVE, true); + channel.setOption(StandardSocketOptions.SO_REUSEADDR, true); + channel.setOption(StandardSocketOptions.SO_RCVBUF, 16 * 1024); + channel.setOption(StandardSocketOptions.SO_SNDBUF, 16 * 1024); + AsyncIOThread readThread = ioGroup.nextIOThread(); + LongAdder connCreateCounter = ioGroup.connCreateCounter; + if (connCreateCounter != null) connCreateCounter.increment(); + LongAdder connLivingCounter = ioGroup.connLivingCounter; + if (connLivingCounter != null) connLivingCounter.increment(); + AsyncNioTcpConnection conn = new AsyncNioTcpConnection(false, ioGroup, readThread, ioGroup.connectThread(), channel, context.getSSLBuilder(), context.getSSLContext(), null, connLivingCounter, ioGroup.connClosedCounter); + ProtocolCodec codec = new ProtocolCodec(context, responseSupplier, responseConsumer, conn); + conn.protocolCodec = codec; + if (conn.sslEngine == null) { + codec.start(null); + } else { + conn.startHandshake(t -> { + if (t == null) { + codec.start(null); + } else if (t instanceof RuntimeException) { + throw (RuntimeException) t; + } else { + throw new RuntimeException(t); + } + }); + } + } + + @Override + public void close() throws IOException { + if (this.closed) return; + this.closed = true; + this.selector.wakeup(); + this.ioGroup.close(); + this.serverChannel.close(); + this.selector.close(); + } + + @Override + public AsyncGroup getAsyncGroup() { + return ioGroup; + } + + @Override + public long getCreateConnectionCount() { + return ioGroup.connCreateCounter == null ? -1 : ioGroup.connCreateCounter.longValue(); + } + + @Override + public long getClosedConnectionCount() { + return ioGroup.connClosedCounter == null ? -1 : ioGroup.connClosedCounter.longValue(); + } + + @Override + public long getLivingConnectionCount() { + return ioGroup.connLivingCounter == null ? -1 : ioGroup.connLivingCounter.longValue(); + } +} diff --git a/src/main/java/org/redkale/net/AsyncNioUdpConnection.java b/src/main/java/org/redkale/net/AsyncNioUdpConnection.java index b47d0babc..15d2ee958 100644 --- a/src/main/java/org/redkale/net/AsyncNioUdpConnection.java +++ b/src/main/java/org/redkale/net/AsyncNioUdpConnection.java @@ -1,173 +1,173 @@ -/* - * 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; - -import java.io.*; -import java.net.*; -import java.nio.ByteBuffer; -import java.nio.channels.*; -import java.util.*; -import java.util.concurrent.atomic.LongAdder; -import java.util.function.*; -import javax.net.ssl.SSLContext; - -/** - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -class AsyncNioUdpConnection extends AsyncNioConnection { - - private final DatagramChannel channel; - - public AsyncNioUdpConnection(boolean client, AsyncIOGroup ioGroup, AsyncIOThread ioThread, AsyncIOThread connectThread, DatagramChannel ch, - SSLBuilder sslBuilder, SSLContext sslContext, final SocketAddress addr0, LongAdder livingCounter, LongAdder closedCounter) { - super(client, ioGroup, ioThread, connectThread, ioGroup.bufferCapacity, ioThread.getBufferSupplier(), ioThread.getBufferConsumer(), sslBuilder, sslContext, livingCounter, closedCounter); - this.channel = ch; - SocketAddress addr = addr0; - if (addr == null) { - try { - addr = ch.getRemoteAddress(); - } catch (Exception e) { - //do nothing - } - } - this.remoteAddress = addr; - } - - public AsyncNioUdpConnection(boolean client, AsyncIOGroup ioGroup, AsyncIOThread ioThread, AsyncIOThread connectThread, - Supplier bufferSupplier, Consumer bufferConsumer, - DatagramChannel ch, SSLBuilder sslBuilder, SSLContext sslContext, final SocketAddress addr0, - LongAdder livingCounter, LongAdder closedCounter) { - super(client, ioGroup, ioThread, connectThread, ioGroup.bufferCapacity, bufferSupplier, bufferConsumer, sslBuilder, sslContext, livingCounter, closedCounter); - this.channel = ch; - SocketAddress addr = addr0; - if (addr == null) { - try { - addr = ch.getRemoteAddress(); - } catch (Exception e) { - //do nothing - } - } - this.remoteAddress = addr; - } - - @Override - public boolean isOpen() { - return this.channel.isOpen(); - } - - @Override - public boolean isTCP() { - return false; - } - - @Override - public boolean shutdownInput() { - return true; - } - - @Override - public boolean shutdownOutput() { - return true; - } - - @Override - public boolean setOption(SocketOption name, T value) { - try { - this.channel.setOption(name, value); - return true; - } catch (IOException e) { - return false; - } - } - - @Override - public Set> supportedOptions() { - return this.channel.supportedOptions(); - } - - @Override - public SocketAddress getLocalAddress() { - try { - return channel.getLocalAddress(); - } catch (IOException e) { - return null; - } - } - - @Override - public ReadableByteChannel readableByteChannel() { - if (this.sslEngine == null) return this.channel; - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public WritableByteChannel writableByteChannel() { - if (this.sslEngine == null) return this.channel; - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public boolean isConnected() { - if (!client) return true; - return this.channel.isConnected(); - } - - @Override - protected SelectionKey implRegister(Selector sel, int ops) throws ClosedChannelException { - return this.channel.register(sel, ops); - } - - @Override - protected int implRead(ByteBuffer dst) throws IOException { - return this.channel.read(dst); - } - - @Override - protected int implWrite(ByteBuffer src) throws IOException { - return this.channel.send(src, remoteAddress); - } - - @Override - protected int implWrite(ByteBuffer[] srcs, int offset, int length) throws IOException { - int end = offset + length; - for (int i = offset; i < end; i++) { - ByteBuffer buf = srcs[i]; - if (buf.hasRemaining()) return this.channel.send(buf, remoteAddress); - } - return 0; - } - - public void connect(SocketAddress remote, A attachment, CompletionHandler handler) { - this.connectAttachment = attachment; - this.connectCompletionHandler = (CompletionHandler) handler; - this.remoteAddress = remote; - doConnect(); - } - - @Override - public void doConnect() { - try { - channel.connect(remoteAddress); - handleConnect(null); - } catch (IOException e) { - handleConnect(e); - } - } - - @Override - public final void close() throws IOException { - super.close(); - if (client) channel.close(); //涓嶈兘鍏抽棴channel - if (this.connectKey != null) this.connectKey.cancel(); - if (this.readKey != null) this.readKey.cancel(); - if (this.writeKey != null) this.writeKey.cancel(); - } - -} +/* + * 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; + +import java.io.*; +import java.net.*; +import java.nio.ByteBuffer; +import java.nio.channels.*; +import java.util.*; +import java.util.concurrent.atomic.LongAdder; +import java.util.function.*; +import javax.net.ssl.SSLContext; + +/** + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +class AsyncNioUdpConnection extends AsyncNioConnection { + + private final DatagramChannel channel; + + public AsyncNioUdpConnection(boolean client, AsyncIOGroup ioGroup, AsyncIOThread ioThread, AsyncIOThread connectThread, DatagramChannel ch, + SSLBuilder sslBuilder, SSLContext sslContext, final SocketAddress addr0, LongAdder livingCounter, LongAdder closedCounter) { + super(client, ioGroup, ioThread, connectThread, ioGroup.bufferCapacity, ioThread.getBufferSupplier(), ioThread.getBufferConsumer(), sslBuilder, sslContext, livingCounter, closedCounter); + this.channel = ch; + SocketAddress addr = addr0; + if (addr == null) { + try { + addr = ch.getRemoteAddress(); + } catch (Exception e) { + //do nothing + } + } + this.remoteAddress = addr; + } + + public AsyncNioUdpConnection(boolean client, AsyncIOGroup ioGroup, AsyncIOThread ioThread, AsyncIOThread connectThread, + Supplier bufferSupplier, Consumer bufferConsumer, + DatagramChannel ch, SSLBuilder sslBuilder, SSLContext sslContext, final SocketAddress addr0, + LongAdder livingCounter, LongAdder closedCounter) { + super(client, ioGroup, ioThread, connectThread, ioGroup.bufferCapacity, bufferSupplier, bufferConsumer, sslBuilder, sslContext, livingCounter, closedCounter); + this.channel = ch; + SocketAddress addr = addr0; + if (addr == null) { + try { + addr = ch.getRemoteAddress(); + } catch (Exception e) { + //do nothing + } + } + this.remoteAddress = addr; + } + + @Override + public boolean isOpen() { + return this.channel.isOpen(); + } + + @Override + public boolean isTCP() { + return false; + } + + @Override + public boolean shutdownInput() { + return true; + } + + @Override + public boolean shutdownOutput() { + return true; + } + + @Override + public boolean setOption(SocketOption name, T value) { + try { + this.channel.setOption(name, value); + return true; + } catch (IOException e) { + return false; + } + } + + @Override + public Set> supportedOptions() { + return this.channel.supportedOptions(); + } + + @Override + public SocketAddress getLocalAddress() { + try { + return channel.getLocalAddress(); + } catch (IOException e) { + return null; + } + } + + @Override + public ReadableByteChannel readableByteChannel() { + if (this.sslEngine == null) return this.channel; + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public WritableByteChannel writableByteChannel() { + if (this.sslEngine == null) return this.channel; + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isConnected() { + if (!client) return true; + return this.channel.isConnected(); + } + + @Override + protected SelectionKey implRegister(Selector sel, int ops) throws ClosedChannelException { + return this.channel.register(sel, ops); + } + + @Override + protected int implRead(ByteBuffer dst) throws IOException { + return this.channel.read(dst); + } + + @Override + protected int implWrite(ByteBuffer src) throws IOException { + return this.channel.send(src, remoteAddress); + } + + @Override + protected int implWrite(ByteBuffer[] srcs, int offset, int length) throws IOException { + int end = offset + length; + for (int i = offset; i < end; i++) { + ByteBuffer buf = srcs[i]; + if (buf.hasRemaining()) return this.channel.send(buf, remoteAddress); + } + return 0; + } + + public void connect(SocketAddress remote, A attachment, CompletionHandler handler) { + this.connectAttachment = attachment; + this.connectCompletionHandler = (CompletionHandler) handler; + this.remoteAddress = remote; + doConnect(); + } + + @Override + public void doConnect() { + try { + channel.connect(remoteAddress); + handleConnect(null); + } catch (IOException e) { + handleConnect(e); + } + } + + @Override + public final void close() throws IOException { + super.close(); + if (client) channel.close(); //涓嶈兘鍏抽棴channel + if (this.connectKey != null) this.connectKey.cancel(); + if (this.readKey != null) this.readKey.cancel(); + if (this.writeKey != null) this.writeKey.cancel(); + } + +} diff --git a/src/main/java/org/redkale/net/AsyncNioUdpProtocolServer.java b/src/main/java/org/redkale/net/AsyncNioUdpProtocolServer.java index bff0563e4..ce1cd6d73 100644 --- a/src/main/java/org/redkale/net/AsyncNioUdpProtocolServer.java +++ b/src/main/java/org/redkale/net/AsyncNioUdpProtocolServer.java @@ -1,188 +1,188 @@ -/* - * 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; - -import java.io.IOException; -import java.net.*; -import java.nio.ByteBuffer; -import java.nio.channels.*; -import java.util.*; -import java.util.concurrent.atomic.LongAdder; -import java.util.function.*; -import org.redkale.boot.Application; -import org.redkale.util.*; - -/** - * 鍗忚搴曞眰Server - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -class AsyncNioUdpProtocolServer extends ProtocolServer { - - private DatagramChannel serverChannel; - - private Selector selector; - - private AsyncIOGroup ioGroup; - - private Thread acceptThread; - - private boolean closed; - - private Supplier responseSupplier; - - private Consumer responseConsumer; - - public AsyncNioUdpProtocolServer(Context context) { - super(context); - } - - @Override - public void open(AnyValue config) throws IOException { - this.serverChannel = DatagramChannel.open(); - this.serverChannel.configureBlocking(false); - this.selector = Selector.open(); - final Set> options = this.serverChannel.supportedOptions(); - if (options.contains(StandardSocketOptions.TCP_NODELAY)) { - this.serverChannel.setOption(StandardSocketOptions.TCP_NODELAY, true); - } - if (options.contains(StandardSocketOptions.SO_KEEPALIVE)) { - this.serverChannel.setOption(StandardSocketOptions.SO_KEEPALIVE, true); - } - if (options.contains(StandardSocketOptions.SO_REUSEADDR)) { - this.serverChannel.setOption(StandardSocketOptions.SO_REUSEADDR, true); - } - if (options.contains(StandardSocketOptions.SO_RCVBUF)) { - this.serverChannel.setOption(StandardSocketOptions.SO_RCVBUF, 16 * 1024); - } - if (options.contains(StandardSocketOptions.SO_SNDBUF)) { - this.serverChannel.setOption(StandardSocketOptions.SO_SNDBUF, 16 * 1024); - } - } - - @Override - public void bind(SocketAddress local, int backlog) throws IOException { - this.serverChannel.bind(local); - } - - @Override - public void setOption(SocketOption name, T value) throws IOException { - this.serverChannel.setOption(name, value); - } - - @Override - public Set> supportedOptions() { - return this.serverChannel.supportedOptions(); - } - - @Override - public void accept(Application application, Server server) throws IOException { - - LongAdder createBufferCounter = new LongAdder(); - LongAdder cycleBufferCounter = new LongAdder(); - LongAdder createResponseCounter = new LongAdder(); - LongAdder cycleResponseCounter = new LongAdder(); - - ObjectPool safeBufferPool = server.createBufferPool(createBufferCounter, cycleBufferCounter, server.bufferPoolSize); - ObjectPool safeResponsePool = server.createResponsePool(createResponseCounter, cycleResponseCounter, server.responsePoolSize); - ThreadLocal> localResponsePool = ThreadLocal.withInitial(() -> { - if (!(Thread.currentThread() instanceof WorkThread)) return null; - return ObjectPool.createUnsafePool(safeResponsePool, safeResponsePool.getCreatCounter(), - safeResponsePool.getCycleCounter(), 16, safeResponsePool.getCreator(), safeResponsePool.getPrepare(), safeResponsePool.getRecycler()); - }); - this.responseSupplier = () -> { - ObjectPool pool = localResponsePool.get(); - return pool == null ? safeResponsePool.get() : pool.get(); - }; - this.responseConsumer = (v) -> { - ObjectPool pool = localResponsePool.get(); - (pool == null ? safeResponsePool : pool).accept(v); - }; - final String threadPrefixName = server.name == null || server.name.isEmpty() ? "Redkale-IOServletThread" : ("Redkale-" + server.name.replace("Server-", "") + "-IOServletThread"); - this.ioGroup = new AsyncIOGroup(false, threadPrefixName, null, server.bufferCapacity, safeBufferPool); - this.ioGroup.start(); - this.serverChannel.register(this.selector, SelectionKey.OP_READ); - - this.acceptThread = new Thread() { - ObjectPool unsafeBufferPool = ObjectPool.createUnsafePool(safeBufferPool, safeBufferPool.getCreatCounter(), - safeBufferPool.getCycleCounter(), 512, safeBufferPool.getCreator(), safeBufferPool.getPrepare(), safeBufferPool.getRecycler()); - - { - setName(threadPrefixName.replace("ServletThread", "AcceptThread")); - } - - @Override - public void run() { - while (!closed) { - final ByteBuffer buffer = unsafeBufferPool.get(); - try { - SocketAddress address = serverChannel.receive(buffer); - buffer.flip(); - accept(address, buffer); - } catch (Throwable t) { - unsafeBufferPool.accept(buffer); - } - } - } - }; - this.acceptThread.start(); - } - - private void accept(SocketAddress address, ByteBuffer buffer) throws IOException { - AsyncIOThread readThread = ioGroup.nextIOThread(); - LongAdder connCreateCounter = ioGroup.connCreateCounter; - if (connCreateCounter != null) connCreateCounter.increment(); - LongAdder connLivingCounter = ioGroup.connLivingCounter; - if (connLivingCounter != null) connLivingCounter.increment(); - AsyncNioUdpConnection conn = new AsyncNioUdpConnection(false, ioGroup, readThread, ioGroup.connectThread(), this.serverChannel, context.getSSLBuilder(), context.getSSLContext(), address, connLivingCounter, ioGroup.connClosedCounter); - ProtocolCodec codec = new ProtocolCodec(context, responseSupplier, responseConsumer, conn); - conn.protocolCodec = codec; - if (conn.sslEngine == null) { - codec.start(buffer); - } else { - conn.startHandshake(t -> { - if (t == null) { - codec.start(buffer); - } else if (t instanceof RuntimeException) { - throw (RuntimeException) t; - } else { - throw new RuntimeException(t); - } - }); - } - } - - @Override - public void close() throws IOException { - if (this.closed) return; - this.closed = true; - this.ioGroup.close(); - this.serverChannel.close(); - } - - @Override - public AsyncGroup getAsyncGroup() { - return ioGroup; - } - - @Override - public long getCreateConnectionCount() { - return -1; - } - - @Override - public long getClosedConnectionCount() { - return -1; - } - - @Override - public long getLivingConnectionCount() { - return -1; - } -} +/* + * 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; + +import java.io.IOException; +import java.net.*; +import java.nio.ByteBuffer; +import java.nio.channels.*; +import java.util.*; +import java.util.concurrent.atomic.LongAdder; +import java.util.function.*; +import org.redkale.boot.Application; +import org.redkale.util.*; + +/** + * 鍗忚搴曞眰Server + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +class AsyncNioUdpProtocolServer extends ProtocolServer { + + private DatagramChannel serverChannel; + + private Selector selector; + + private AsyncIOGroup ioGroup; + + private Thread acceptThread; + + private boolean closed; + + private Supplier responseSupplier; + + private Consumer responseConsumer; + + public AsyncNioUdpProtocolServer(Context context) { + super(context); + } + + @Override + public void open(AnyValue config) throws IOException { + this.serverChannel = DatagramChannel.open(); + this.serverChannel.configureBlocking(false); + this.selector = Selector.open(); + final Set> options = this.serverChannel.supportedOptions(); + if (options.contains(StandardSocketOptions.TCP_NODELAY)) { + this.serverChannel.setOption(StandardSocketOptions.TCP_NODELAY, true); + } + if (options.contains(StandardSocketOptions.SO_KEEPALIVE)) { + this.serverChannel.setOption(StandardSocketOptions.SO_KEEPALIVE, true); + } + if (options.contains(StandardSocketOptions.SO_REUSEADDR)) { + this.serverChannel.setOption(StandardSocketOptions.SO_REUSEADDR, true); + } + if (options.contains(StandardSocketOptions.SO_RCVBUF)) { + this.serverChannel.setOption(StandardSocketOptions.SO_RCVBUF, 16 * 1024); + } + if (options.contains(StandardSocketOptions.SO_SNDBUF)) { + this.serverChannel.setOption(StandardSocketOptions.SO_SNDBUF, 16 * 1024); + } + } + + @Override + public void bind(SocketAddress local, int backlog) throws IOException { + this.serverChannel.bind(local); + } + + @Override + public void setOption(SocketOption name, T value) throws IOException { + this.serverChannel.setOption(name, value); + } + + @Override + public Set> supportedOptions() { + return this.serverChannel.supportedOptions(); + } + + @Override + public void accept(Application application, Server server) throws IOException { + + LongAdder createBufferCounter = new LongAdder(); + LongAdder cycleBufferCounter = new LongAdder(); + LongAdder createResponseCounter = new LongAdder(); + LongAdder cycleResponseCounter = new LongAdder(); + + ObjectPool safeBufferPool = server.createBufferPool(createBufferCounter, cycleBufferCounter, server.bufferPoolSize); + ObjectPool safeResponsePool = server.createResponsePool(createResponseCounter, cycleResponseCounter, server.responsePoolSize); + ThreadLocal> localResponsePool = ThreadLocal.withInitial(() -> { + if (!(Thread.currentThread() instanceof WorkThread)) return null; + return ObjectPool.createUnsafePool(safeResponsePool, safeResponsePool.getCreatCounter(), + safeResponsePool.getCycleCounter(), 16, safeResponsePool.getCreator(), safeResponsePool.getPrepare(), safeResponsePool.getRecycler()); + }); + this.responseSupplier = () -> { + ObjectPool pool = localResponsePool.get(); + return pool == null ? safeResponsePool.get() : pool.get(); + }; + this.responseConsumer = (v) -> { + ObjectPool pool = localResponsePool.get(); + (pool == null ? safeResponsePool : pool).accept(v); + }; + final String threadPrefixName = server.name == null || server.name.isEmpty() ? "Redkale-IOServletThread" : ("Redkale-" + server.name.replace("Server-", "") + "-IOServletThread"); + this.ioGroup = new AsyncIOGroup(false, threadPrefixName, null, server.bufferCapacity, safeBufferPool); + this.ioGroup.start(); + this.serverChannel.register(this.selector, SelectionKey.OP_READ); + + this.acceptThread = new Thread() { + ObjectPool unsafeBufferPool = ObjectPool.createUnsafePool(safeBufferPool, safeBufferPool.getCreatCounter(), + safeBufferPool.getCycleCounter(), 512, safeBufferPool.getCreator(), safeBufferPool.getPrepare(), safeBufferPool.getRecycler()); + + { + setName(threadPrefixName.replace("ServletThread", "AcceptThread")); + } + + @Override + public void run() { + while (!closed) { + final ByteBuffer buffer = unsafeBufferPool.get(); + try { + SocketAddress address = serverChannel.receive(buffer); + buffer.flip(); + accept(address, buffer); + } catch (Throwable t) { + unsafeBufferPool.accept(buffer); + } + } + } + }; + this.acceptThread.start(); + } + + private void accept(SocketAddress address, ByteBuffer buffer) throws IOException { + AsyncIOThread readThread = ioGroup.nextIOThread(); + LongAdder connCreateCounter = ioGroup.connCreateCounter; + if (connCreateCounter != null) connCreateCounter.increment(); + LongAdder connLivingCounter = ioGroup.connLivingCounter; + if (connLivingCounter != null) connLivingCounter.increment(); + AsyncNioUdpConnection conn = new AsyncNioUdpConnection(false, ioGroup, readThread, ioGroup.connectThread(), this.serverChannel, context.getSSLBuilder(), context.getSSLContext(), address, connLivingCounter, ioGroup.connClosedCounter); + ProtocolCodec codec = new ProtocolCodec(context, responseSupplier, responseConsumer, conn); + conn.protocolCodec = codec; + if (conn.sslEngine == null) { + codec.start(buffer); + } else { + conn.startHandshake(t -> { + if (t == null) { + codec.start(buffer); + } else if (t instanceof RuntimeException) { + throw (RuntimeException) t; + } else { + throw new RuntimeException(t); + } + }); + } + } + + @Override + public void close() throws IOException { + if (this.closed) return; + this.closed = true; + this.ioGroup.close(); + this.serverChannel.close(); + } + + @Override + public AsyncGroup getAsyncGroup() { + return ioGroup; + } + + @Override + public long getCreateConnectionCount() { + return -1; + } + + @Override + public long getClosedConnectionCount() { + return -1; + } + + @Override + public long getLivingConnectionCount() { + return -1; + } +} diff --git a/src/main/java/org/redkale/net/ChannelContext.java b/src/main/java/org/redkale/net/ChannelContext.java index 2399303f2..acd990347 100644 --- a/src/main/java/org/redkale/net/ChannelContext.java +++ b/src/main/java/org/redkale/net/ChannelContext.java @@ -1,31 +1,31 @@ -/* - * 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; - -import java.util.*; - -/** - * 褰撳墠涓涓猂equest缁戝畾鐨凙syncConnection锛 绫讳技Session锛屼絾姒傚康涓婁笉鍚屼簬sessionid瀵瑰簲鐨勫璞 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @since 2.4.0 - */ -public interface ChannelContext { - - public void setAttribute(String name, Object value); - - @SuppressWarnings("unchecked") - public T getAttribute(String name); - - public void removeAttribute(String name); - - public Map getAttributes(); - - public void clearAttribute(); -} +/* + * 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; + +import java.util.*; + +/** + * 褰撳墠涓涓猂equest缁戝畾鐨凙syncConnection锛 绫讳技Session锛屼絾姒傚康涓婁笉鍚屼簬sessionid瀵瑰簲鐨勫璞 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @since 2.4.0 + */ +public interface ChannelContext { + + public void setAttribute(String name, Object value); + + @SuppressWarnings("unchecked") + public T getAttribute(String name); + + public void removeAttribute(String name); + + public Map getAttributes(); + + public void clearAttribute(); +} diff --git a/src/main/java/org/redkale/net/Context.java b/src/main/java/org/redkale/net/Context.java index 219189e24..4c349d6de 100644 --- a/src/main/java/org/redkale/net/Context.java +++ b/src/main/java/org/redkale/net/Context.java @@ -1,271 +1,271 @@ -/* - * 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; - -import java.net.*; -import java.nio.charset.*; -import java.util.concurrent.*; -import java.util.logging.*; -import javax.net.ssl.SSLContext; -import org.redkale.convert.bson.*; -import org.redkale.convert.json.*; -import org.redkale.util.*; - -/** - * 鏈嶅姟鍣ㄤ笂涓嬫枃瀵硅薄 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public class Context { - - //鏈嶅姟鍚姩鏃堕棿 - protected final long serverStartTime; - - //Server鐨勭嚎绋嬫睜 - protected final ExecutorService workExecutor; - - protected final ThreadHashExecutor workHashExecutor; - - //SSL - protected final SSLBuilder sslBuilder; - - //SSL - protected final SSLContext sslContext; - - //ByteBuffer鐨勫閲忥紝榛樿8K - protected final int bufferCapacity; - - //鏈嶅姟鐨勬牴Servlet - protected final PrepareServlet prepare; - - //鏃ュ織Logger - protected final Logger logger; - - //BSON鎿嶄綔宸ュ巶 - protected final BsonFactory bsonFactory; - - //JSON鎿嶄綔宸ュ巶 - protected final JsonFactory jsonFactory; - - //渚濊禆娉ㄥ叆宸ュ巶绫 - protected final ResourceFactory resourceFactory; - - //鏈澶ц繛鎺ユ暟, 涓0琛ㄧず娌¢檺鍒 - protected int maxconns; - - //璇锋眰鍐呭鐨勫ぇ灏忎笂闄, 榛樿64K - protected int maxbody; - - //keep alive IO璇诲彇鐨勮秴鏃舵椂闂 - protected int aliveTimeoutSeconds; - - //IO璇诲彇鐨勮秴鏃舵椂闂 - protected int readTimeoutSeconds; - - //IO鍐欏叆鐨勮秴鏃舵椂闂 - protected int writeTimeoutSeconds; - - //鏈嶅姟鐨勭洃鍚湴鍧 - protected InetSocketAddress address; - - //瀛楃闆 - protected Charset charset; - - public Context(ContextConfig config) { - this(config.serverStartTime, config.logger, config.workExecutor, config.sslBuilder, config.sslContext, - config.bufferCapacity, config.maxconns, config.maxbody, config.charset, config.address, config.resourceFactory, - config.prepare, config.aliveTimeoutSeconds, config.readTimeoutSeconds, config.writeTimeoutSeconds); - } - - public Context(long serverStartTime, Logger logger, ExecutorService workExecutor, SSLBuilder sslBuilder, SSLContext sslContext, - int bufferCapacity, final int maxconns, final int maxbody, Charset charset, InetSocketAddress address, - ResourceFactory resourceFactory, PrepareServlet prepare, int aliveTimeoutSeconds, int readTimeoutSeconds, int writeTimeoutSeconds) { - this.serverStartTime = serverStartTime; - this.logger = logger; - this.workExecutor = workExecutor; - this.sslBuilder = sslBuilder; - this.sslContext = sslContext; - this.bufferCapacity = bufferCapacity; - this.maxconns = maxconns; - this.maxbody = maxbody; - this.charset = StandardCharsets.UTF_8.equals(charset) ? null : charset; - this.address = address; - this.prepare = prepare; - this.resourceFactory = resourceFactory; - this.aliveTimeoutSeconds = aliveTimeoutSeconds; - this.readTimeoutSeconds = readTimeoutSeconds; - this.writeTimeoutSeconds = writeTimeoutSeconds; - this.jsonFactory = JsonFactory.root(); - this.bsonFactory = BsonFactory.root(); - if (workExecutor instanceof ThreadHashExecutor) { - this.workHashExecutor = (ThreadHashExecutor) workExecutor; - } else { - this.workHashExecutor = null; - } - } - - protected void executePrepareServlet(Request request, Response response) { - if (workHashExecutor != null) { - workHashExecutor.execute(request.getHashid(), () -> prepare.prepare(request, response)); - } else if (workExecutor != null) { - workExecutor.execute(() -> prepare.prepare(request, response)); - } else { - prepare.prepare(request, response); - } - } - - public void execute(Servlet servlet, Request request, Response response) { - if (workHashExecutor != null) { - workHashExecutor.execute(request.getHashid(), () -> { - try { - long cha = System.currentTimeMillis() - request.getCreatetime(); - servlet.execute(request, response); - if (cha > 1000 && response.context.logger.isLoggable(Level.WARNING)) { - response.context.logger.log(Level.WARNING, "hash execute servlet delays=" + cha + "ms, request=" + request); - } else if (cha > 100 && response.context.logger.isLoggable(Level.FINE)) { - response.context.logger.log(Level.FINE, "hash execute servlet delay=" + cha + "ms, request=" + request); - } - } catch (Throwable t) { - response.context.logger.log(Level.WARNING, "execute servlet abort, force to close channel ", t); - response.finish(true); - } - }); - } else if (workExecutor != null) { - workExecutor.execute(() -> { - try { - servlet.execute(request, response); - } catch (Throwable t) { - response.context.logger.log(Level.WARNING, "execute servlet abort, force to close channel ", t); - response.finish(true); - } - }); - } else { - try { - servlet.execute(request, response); - } catch (Throwable t) { - response.context.logger.log(Level.WARNING, "execute servlet abort, force to close channel ", t); - response.finish(true); - } - } - - } - - public ResourceFactory getResourceFactory() { - return resourceFactory; - } - - public SSLBuilder getSSLBuilder() { - return sslBuilder; - } - - public SSLContext getSSLContext() { - return sslContext; - } - - public int getMaxconns() { - return maxconns; - } - - public int getMaxbody() { - return maxbody; - } - - public InetSocketAddress getServerAddress() { - return address; - } - - public long getServerStartTime() { - return serverStartTime; - } - - public Charset getCharset() { - return charset; - } - - public int getBufferCapacity() { - return bufferCapacity; - } - - public Logger getLogger() { - return logger; - } - - public int getAliveTimeoutSeconds() { - return aliveTimeoutSeconds; - } - - public int getReadTimeoutSeconds() { - return readTimeoutSeconds; - } - - public int getWriteTimeoutSeconds() { - return writeTimeoutSeconds; - } - - public JsonConvert getJsonConvert() { - return jsonFactory.getConvert(); - } - - public BsonConvert getBsonConvert() { - return bsonFactory.getConvert(); - } - - public static class ContextConfig { - - //鏈嶅姟鍚姩鏃堕棿 - public long serverStartTime; - - //Server鐨勭嚎绋嬫睜 - public ExecutorService workExecutor; - - //SSL - public SSLBuilder sslBuilder; - - //SSL - public SSLContext sslContext; - - //ByteBuffer鐨勫閲忥紝榛樿8K - public int bufferCapacity; - - //鏈嶅姟鐨勬牴Servlet - public PrepareServlet prepare; - - //鏈嶅姟鐨勭洃鍚湴鍧 - public InetSocketAddress address; - - //瀛楃闆 - public Charset charset; - - //璇锋眰鍐呭鐨勫ぇ灏忎笂闄, 榛樿64K - public int maxbody; - - //鏈澶ц繛鎺ユ暟, 涓0琛ㄧず娌¢檺鍒 - public int maxconns; - - //keep alive IO璇诲彇鐨勮秴鏃舵椂闂 - public int aliveTimeoutSeconds; - - //IO璇诲彇鐨勮秴鏃舵椂闂 - public int readTimeoutSeconds; - - //IO鍐欏叆鐨勮秴鏃舵椂闂 - public int writeTimeoutSeconds; - - //鏃ュ織Logger - public Logger logger; - - //渚濊禆娉ㄥ叆宸ュ巶绫 - public ResourceFactory resourceFactory; - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - } -} +/* + * 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; + +import java.net.*; +import java.nio.charset.*; +import java.util.concurrent.*; +import java.util.logging.*; +import javax.net.ssl.SSLContext; +import org.redkale.convert.bson.*; +import org.redkale.convert.json.*; +import org.redkale.util.*; + +/** + * 鏈嶅姟鍣ㄤ笂涓嬫枃瀵硅薄 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public class Context { + + //鏈嶅姟鍚姩鏃堕棿 + protected final long serverStartTime; + + //Server鐨勭嚎绋嬫睜 + protected final ExecutorService workExecutor; + + protected final ThreadHashExecutor workHashExecutor; + + //SSL + protected final SSLBuilder sslBuilder; + + //SSL + protected final SSLContext sslContext; + + //ByteBuffer鐨勫閲忥紝榛樿8K + protected final int bufferCapacity; + + //鏈嶅姟鐨勬牴Servlet + protected final PrepareServlet prepare; + + //鏃ュ織Logger + protected final Logger logger; + + //BSON鎿嶄綔宸ュ巶 + protected final BsonFactory bsonFactory; + + //JSON鎿嶄綔宸ュ巶 + protected final JsonFactory jsonFactory; + + //渚濊禆娉ㄥ叆宸ュ巶绫 + protected final ResourceFactory resourceFactory; + + //鏈澶ц繛鎺ユ暟, 涓0琛ㄧず娌¢檺鍒 + protected int maxconns; + + //璇锋眰鍐呭鐨勫ぇ灏忎笂闄, 榛樿64K + protected int maxbody; + + //keep alive IO璇诲彇鐨勮秴鏃舵椂闂 + protected int aliveTimeoutSeconds; + + //IO璇诲彇鐨勮秴鏃舵椂闂 + protected int readTimeoutSeconds; + + //IO鍐欏叆鐨勮秴鏃舵椂闂 + protected int writeTimeoutSeconds; + + //鏈嶅姟鐨勭洃鍚湴鍧 + protected InetSocketAddress address; + + //瀛楃闆 + protected Charset charset; + + public Context(ContextConfig config) { + this(config.serverStartTime, config.logger, config.workExecutor, config.sslBuilder, config.sslContext, + config.bufferCapacity, config.maxconns, config.maxbody, config.charset, config.address, config.resourceFactory, + config.prepare, config.aliveTimeoutSeconds, config.readTimeoutSeconds, config.writeTimeoutSeconds); + } + + public Context(long serverStartTime, Logger logger, ExecutorService workExecutor, SSLBuilder sslBuilder, SSLContext sslContext, + int bufferCapacity, final int maxconns, final int maxbody, Charset charset, InetSocketAddress address, + ResourceFactory resourceFactory, PrepareServlet prepare, int aliveTimeoutSeconds, int readTimeoutSeconds, int writeTimeoutSeconds) { + this.serverStartTime = serverStartTime; + this.logger = logger; + this.workExecutor = workExecutor; + this.sslBuilder = sslBuilder; + this.sslContext = sslContext; + this.bufferCapacity = bufferCapacity; + this.maxconns = maxconns; + this.maxbody = maxbody; + this.charset = StandardCharsets.UTF_8.equals(charset) ? null : charset; + this.address = address; + this.prepare = prepare; + this.resourceFactory = resourceFactory; + this.aliveTimeoutSeconds = aliveTimeoutSeconds; + this.readTimeoutSeconds = readTimeoutSeconds; + this.writeTimeoutSeconds = writeTimeoutSeconds; + this.jsonFactory = JsonFactory.root(); + this.bsonFactory = BsonFactory.root(); + if (workExecutor instanceof ThreadHashExecutor) { + this.workHashExecutor = (ThreadHashExecutor) workExecutor; + } else { + this.workHashExecutor = null; + } + } + + protected void executePrepareServlet(Request request, Response response) { + if (workHashExecutor != null) { + workHashExecutor.execute(request.getHashid(), () -> prepare.prepare(request, response)); + } else if (workExecutor != null) { + workExecutor.execute(() -> prepare.prepare(request, response)); + } else { + prepare.prepare(request, response); + } + } + + public void execute(Servlet servlet, Request request, Response response) { + if (workHashExecutor != null) { + workHashExecutor.execute(request.getHashid(), () -> { + try { + long cha = System.currentTimeMillis() - request.getCreatetime(); + servlet.execute(request, response); + if (cha > 1000 && response.context.logger.isLoggable(Level.WARNING)) { + response.context.logger.log(Level.WARNING, "hash execute servlet delays=" + cha + "ms, request=" + request); + } else if (cha > 100 && response.context.logger.isLoggable(Level.FINE)) { + response.context.logger.log(Level.FINE, "hash execute servlet delay=" + cha + "ms, request=" + request); + } + } catch (Throwable t) { + response.context.logger.log(Level.WARNING, "execute servlet abort, force to close channel ", t); + response.finish(true); + } + }); + } else if (workExecutor != null) { + workExecutor.execute(() -> { + try { + servlet.execute(request, response); + } catch (Throwable t) { + response.context.logger.log(Level.WARNING, "execute servlet abort, force to close channel ", t); + response.finish(true); + } + }); + } else { + try { + servlet.execute(request, response); + } catch (Throwable t) { + response.context.logger.log(Level.WARNING, "execute servlet abort, force to close channel ", t); + response.finish(true); + } + } + + } + + public ResourceFactory getResourceFactory() { + return resourceFactory; + } + + public SSLBuilder getSSLBuilder() { + return sslBuilder; + } + + public SSLContext getSSLContext() { + return sslContext; + } + + public int getMaxconns() { + return maxconns; + } + + public int getMaxbody() { + return maxbody; + } + + public InetSocketAddress getServerAddress() { + return address; + } + + public long getServerStartTime() { + return serverStartTime; + } + + public Charset getCharset() { + return charset; + } + + public int getBufferCapacity() { + return bufferCapacity; + } + + public Logger getLogger() { + return logger; + } + + public int getAliveTimeoutSeconds() { + return aliveTimeoutSeconds; + } + + public int getReadTimeoutSeconds() { + return readTimeoutSeconds; + } + + public int getWriteTimeoutSeconds() { + return writeTimeoutSeconds; + } + + public JsonConvert getJsonConvert() { + return jsonFactory.getConvert(); + } + + public BsonConvert getBsonConvert() { + return bsonFactory.getConvert(); + } + + public static class ContextConfig { + + //鏈嶅姟鍚姩鏃堕棿 + public long serverStartTime; + + //Server鐨勭嚎绋嬫睜 + public ExecutorService workExecutor; + + //SSL + public SSLBuilder sslBuilder; + + //SSL + public SSLContext sslContext; + + //ByteBuffer鐨勫閲忥紝榛樿8K + public int bufferCapacity; + + //鏈嶅姟鐨勬牴Servlet + public PrepareServlet prepare; + + //鏈嶅姟鐨勭洃鍚湴鍧 + public InetSocketAddress address; + + //瀛楃闆 + public Charset charset; + + //璇锋眰鍐呭鐨勫ぇ灏忎笂闄, 榛樿64K + public int maxbody; + + //鏈澶ц繛鎺ユ暟, 涓0琛ㄧず娌¢檺鍒 + public int maxconns; + + //keep alive IO璇诲彇鐨勮秴鏃舵椂闂 + public int aliveTimeoutSeconds; + + //IO璇诲彇鐨勮秴鏃舵椂闂 + public int readTimeoutSeconds; + + //IO鍐欏叆鐨勮秴鏃舵椂闂 + public int writeTimeoutSeconds; + + //鏃ュ織Logger + public Logger logger; + + //渚濊禆娉ㄥ叆宸ュ巶绫 + public ResourceFactory resourceFactory; + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + } +} diff --git a/src/main/java/org/redkale/net/Cryptor.java b/src/main/java/org/redkale/net/Cryptor.java index e77aa2a1d..4cf1e36a0 100644 --- a/src/main/java/org/redkale/net/Cryptor.java +++ b/src/main/java/org/redkale/net/Cryptor.java @@ -1,42 +1,42 @@ -/* - * 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; - -import java.nio.ByteBuffer; -import java.util.function.*; - -/** - * 鍔犲瘑瑙e瘑鎺ュ彛 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public interface Cryptor { - - /** - * 鍔犲瘑 - * - * @param buffers 寰呭姞瀵嗘暟鎹 - * @param supplier ByteBuffer鐢熸垚鍣 - * @param consumer ByteBuffer鍥炴敹鍣 - * - * @return 鍔犲瘑鍚庢暟鎹 - */ - public ByteBuffer[] encrypt(ByteBuffer[] buffers, final Supplier supplier, final Consumer consumer); - - /** - * 瑙e瘑 - * - * @param buffers 寰呰В瀵嗘暟鎹 - * @param supplier ByteBuffer鐢熸垚鍣 - * @param consumer ByteBuffer鍥炴敹鍣 - * - * @return 瑙e瘑鍚庢暟鎹 - */ - public ByteBuffer[] decrypt(ByteBuffer[] buffers, final Supplier supplier, final Consumer consumer); -} +/* + * 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; + +import java.nio.ByteBuffer; +import java.util.function.*; + +/** + * 鍔犲瘑瑙e瘑鎺ュ彛 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public interface Cryptor { + + /** + * 鍔犲瘑 + * + * @param buffers 寰呭姞瀵嗘暟鎹 + * @param supplier ByteBuffer鐢熸垚鍣 + * @param consumer ByteBuffer鍥炴敹鍣 + * + * @return 鍔犲瘑鍚庢暟鎹 + */ + public ByteBuffer[] encrypt(ByteBuffer[] buffers, final Supplier supplier, final Consumer consumer); + + /** + * 瑙e瘑 + * + * @param buffers 寰呰В瀵嗘暟鎹 + * @param supplier ByteBuffer鐢熸垚鍣 + * @param consumer ByteBuffer鍥炴敹鍣 + * + * @return 瑙e瘑鍚庢暟鎹 + */ + public ByteBuffer[] decrypt(ByteBuffer[] buffers, final Supplier supplier, final Consumer consumer); +} diff --git a/src/main/java/org/redkale/net/Filter.java b/src/main/java/org/redkale/net/Filter.java index 3a5d08d42..6b145f7d4 100644 --- a/src/main/java/org/redkale/net/Filter.java +++ b/src/main/java/org/redkale/net/Filter.java @@ -1,44 +1,44 @@ -/* - * 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; - -import java.io.IOException; -import javax.annotation.Priority; -import org.redkale.util.*; - -/** - * 鍗忚鎷︽埅鍣ㄧ被 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Context鐨勫瓙绫诲瀷 - * @param Request鐨勫瓙绫诲瀷 - * @param

Response鐨勫瓙绫诲瀷 - */ -public abstract class Filter, P extends Response> implements Comparable { - - AnyValue _conf; //褰撳墠Filter鐨勯厤缃 - - Filter _next; //涓嬩竴涓狥ilter - - public void init(C context, AnyValue config) { - } - - public abstract void doFilter(R request, P response) throws IOException; - - public void destroy(C context, AnyValue config) { - } - - @Override - public int compareTo(Object o) { - if (!(o instanceof Filter)) return 1; - Priority p1 = this.getClass().getAnnotation(Priority.class); - Priority p2 = o.getClass().getAnnotation(Priority.class); - return (p2 == null ? 0 : p2.value()) - (p1 == null ? 0 : p1.value()); - } -} +/* + * 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; + +import java.io.IOException; +import javax.annotation.Priority; +import org.redkale.util.*; + +/** + * 鍗忚鎷︽埅鍣ㄧ被 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Context鐨勫瓙绫诲瀷 + * @param Request鐨勫瓙绫诲瀷 + * @param

Response鐨勫瓙绫诲瀷 + */ +public abstract class Filter, P extends Response> implements Comparable { + + AnyValue _conf; //褰撳墠Filter鐨勯厤缃 + + Filter _next; //涓嬩竴涓狥ilter + + public void init(C context, AnyValue config) { + } + + public abstract void doFilter(R request, P response) throws IOException; + + public void destroy(C context, AnyValue config) { + } + + @Override + public int compareTo(Object o) { + if (!(o instanceof Filter)) return 1; + Priority p1 = this.getClass().getAnnotation(Priority.class); + Priority p2 = o.getClass().getAnnotation(Priority.class); + return (p2 == null ? 0 : p2.value()) - (p1 == null ? 0 : p1.value()); + } +} diff --git a/src/main/java/org/redkale/net/PrepareServlet.java b/src/main/java/org/redkale/net/PrepareServlet.java index 214da4303..4b36475c8 100644 --- a/src/main/java/org/redkale/net/PrepareServlet.java +++ b/src/main/java/org/redkale/net/PrepareServlet.java @@ -1,243 +1,243 @@ -/* - * 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; - -import java.io.*; -import java.util.*; -import java.util.concurrent.atomic.*; -import java.util.function.Predicate; -import java.util.logging.Level; -import java.util.stream.Stream; -import org.redkale.boot.Application; -import org.redkale.util.*; - -/** - * 鏍筍ervlet锛 涓涓猄erver鍙兘瀛樺湪涓涓牴Servlet - * - * 鐢ㄤ簬鍒嗗彂Request璇锋眰 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param SessionID鐨勭被鍨 - * @param Context鐨勫瓙绫诲瀷 - * @param Request鐨勫瓙绫诲瀷 - * @param

Response鐨勫瓙绫诲瀷 - * @param Servlet鐨勫瓙绫诲瀷 - */ -public abstract class PrepareServlet, P extends Response, S extends Servlet> extends Servlet { - - protected final LongAdder executeCounter = new LongAdder(); //鎵ц璇锋眰娆℃暟 - - protected final LongAdder illRequestCounter = new LongAdder(); //閿欒璇锋眰娆℃暟 - - protected Application application; - - private final Object lock1 = new Object(); - - private Set servlets = new HashSet<>(); - - private final Object lock2 = new Object(); - - private Map mappings = new HashMap<>(); - - private final List> filters = new ArrayList<>(); - - protected Filter headFilter; - - protected void putServlet(S servlet) { - synchronized (lock1) { - Set newservlets = new HashSet<>(servlets); - newservlets.add(servlet); - this.servlets = newservlets; - } - } - - protected void removeServlet(S servlet) { - synchronized (lock1) { - Set newservlets = new HashSet<>(servlets); - newservlets.remove(servlet); - this.servlets = newservlets; - } - } - - public boolean containsServlet(Class servletClass) { - synchronized (lock1) { - for (S servlet : new HashSet<>(servlets)) { - if (servlet.getClass().equals(servletClass)) return true; - } - return false; - } - } - - public boolean containsServlet(String servletClassName) { - synchronized (lock1) { - for (S servlet : new HashSet<>(servlets)) { - if (servlet.getClass().getName().equals(servletClassName)) return true; - } - return false; - } - } - - protected void putMapping(K key, S servlet) { - synchronized (lock2) { - Map newmappings = new HashMap<>(mappings); - newmappings.put(key, servlet); - this.mappings = newmappings; - } - } - - protected void removeMapping(K key) { - synchronized (lock2) { - if (mappings.containsKey(key)) { - Map newmappings = new HashMap<>(mappings); - newmappings.remove(key); - this.mappings = newmappings; - } - } - } - - protected void removeMapping(S servlet) { - synchronized (lock2) { - List keys = new ArrayList<>(); - Map newmappings = new HashMap<>(mappings); - for (Map.Entry en : newmappings.entrySet()) { - if (en.getValue().equals(servlet)) { - keys.add(en.getKey()); - } - } - for (K key : keys) newmappings.remove(key); - this.mappings = newmappings; - } - } - - protected S mappingServlet(K key) { - return mappings.get(key); - } - - @Override - @SuppressWarnings("unchecked") - public void init(C context, AnyValue config) { - if (application != null && application.isCompileMode()) return; - synchronized (filters) { - if (!filters.isEmpty()) { - Collections.sort(filters); - for (Filter filter : filters) { - filter.init(context, config); - } - this.headFilter = filters.get(0); - Filter filter = this.headFilter; - for (int i = 1; i < filters.size(); i++) { - filter._next = filters.get(i); - filter = filter._next; - } - } - } - } - - @Override - @SuppressWarnings("unchecked") - public void destroy(C context, AnyValue config) { - synchronized (filters) { - if (!filters.isEmpty()) { - for (Filter filter : filters) { - filter.destroy(context, config); - } - } - } - } - - @SuppressWarnings("unchecked") - public void addFilter(Filter filter, AnyValue conf) { - filter._conf = conf; - synchronized (filters) { - this.filters.add(filter); - Collections.sort(this.filters); - } - } - - public > T removeFilter(Class filterClass) { - return removeFilter(f -> filterClass.equals(f.getClass())); - } - - public boolean containsFilter(Class filterClass) { - if (this.headFilter == null || filterClass == null) return false; - Filter filter = this.headFilter; - do { - if (filter.getClass().equals(filterClass)) return true; - } while ((filter = filter._next) != null); - return false; - } - - public boolean containsFilter(String filterClassName) { - if (this.headFilter == null || filterClassName == null) return false; - Filter filter = this.headFilter; - do { - if (filter.getClass().getName().equals(filterClassName)) return true; - } while ((filter = filter._next) != null); - return false; - } - - @SuppressWarnings("unchecked") - public > T removeFilter(Predicate predicate) { - if (this.headFilter == null || predicate == null) return null; - synchronized (filters) { - Filter filter = this.headFilter; - Filter prev = null; - do { - if (predicate.test((T) filter)) break; - prev = filter; - } while ((filter = filter._next) != null); - if (filter != null) { - if (prev == null) { - this.headFilter = filter._next; - } else { - prev._next = filter._next; - } - filter._next = null; - this.filters.remove(filter); - } - return (T) filter; - } - } - - @SuppressWarnings("unchecked") - public > List getFilters() { - return (List) new ArrayList<>(filters); - } - - @SuppressWarnings("unchecked") - public abstract void addServlet(S servlet, Object attachment, AnyValue conf, K... mappings); - - public final void prepare(final R request, final P response) { - try { - request.prepare(); - response.filter = this.headFilter; - response.servlet = this; - response.nextEvent(); - } catch (Throwable t) { - response.context.logger.log(Level.WARNING, "prepare servlet abort, force to close channel ", t); - response.finish(true); - } - } - - protected AnyValue getServletConf(Servlet servlet) { - return servlet._conf; - } - - protected void setServletConf(Servlet servlet, AnyValue conf) { - servlet._conf = conf; - } - - public List getServlets() { - return new ArrayList<>(servlets); - } - - protected Stream servletStream() { - return servlets.stream(); - } -} +/* + * 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; + +import java.io.*; +import java.util.*; +import java.util.concurrent.atomic.*; +import java.util.function.Predicate; +import java.util.logging.Level; +import java.util.stream.Stream; +import org.redkale.boot.Application; +import org.redkale.util.*; + +/** + * 鏍筍ervlet锛 涓涓猄erver鍙兘瀛樺湪涓涓牴Servlet + * + * 鐢ㄤ簬鍒嗗彂Request璇锋眰 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param SessionID鐨勭被鍨 + * @param Context鐨勫瓙绫诲瀷 + * @param Request鐨勫瓙绫诲瀷 + * @param

Response鐨勫瓙绫诲瀷 + * @param Servlet鐨勫瓙绫诲瀷 + */ +public abstract class PrepareServlet, P extends Response, S extends Servlet> extends Servlet { + + protected final LongAdder executeCounter = new LongAdder(); //鎵ц璇锋眰娆℃暟 + + protected final LongAdder illRequestCounter = new LongAdder(); //閿欒璇锋眰娆℃暟 + + protected Application application; + + private final Object lock1 = new Object(); + + private Set servlets = new HashSet<>(); + + private final Object lock2 = new Object(); + + private Map mappings = new HashMap<>(); + + private final List> filters = new ArrayList<>(); + + protected Filter headFilter; + + protected void putServlet(S servlet) { + synchronized (lock1) { + Set newservlets = new HashSet<>(servlets); + newservlets.add(servlet); + this.servlets = newservlets; + } + } + + protected void removeServlet(S servlet) { + synchronized (lock1) { + Set newservlets = new HashSet<>(servlets); + newservlets.remove(servlet); + this.servlets = newservlets; + } + } + + public boolean containsServlet(Class servletClass) { + synchronized (lock1) { + for (S servlet : new HashSet<>(servlets)) { + if (servlet.getClass().equals(servletClass)) return true; + } + return false; + } + } + + public boolean containsServlet(String servletClassName) { + synchronized (lock1) { + for (S servlet : new HashSet<>(servlets)) { + if (servlet.getClass().getName().equals(servletClassName)) return true; + } + return false; + } + } + + protected void putMapping(K key, S servlet) { + synchronized (lock2) { + Map newmappings = new HashMap<>(mappings); + newmappings.put(key, servlet); + this.mappings = newmappings; + } + } + + protected void removeMapping(K key) { + synchronized (lock2) { + if (mappings.containsKey(key)) { + Map newmappings = new HashMap<>(mappings); + newmappings.remove(key); + this.mappings = newmappings; + } + } + } + + protected void removeMapping(S servlet) { + synchronized (lock2) { + List keys = new ArrayList<>(); + Map newmappings = new HashMap<>(mappings); + for (Map.Entry en : newmappings.entrySet()) { + if (en.getValue().equals(servlet)) { + keys.add(en.getKey()); + } + } + for (K key : keys) newmappings.remove(key); + this.mappings = newmappings; + } + } + + protected S mappingServlet(K key) { + return mappings.get(key); + } + + @Override + @SuppressWarnings("unchecked") + public void init(C context, AnyValue config) { + if (application != null && application.isCompileMode()) return; + synchronized (filters) { + if (!filters.isEmpty()) { + Collections.sort(filters); + for (Filter filter : filters) { + filter.init(context, config); + } + this.headFilter = filters.get(0); + Filter filter = this.headFilter; + for (int i = 1; i < filters.size(); i++) { + filter._next = filters.get(i); + filter = filter._next; + } + } + } + } + + @Override + @SuppressWarnings("unchecked") + public void destroy(C context, AnyValue config) { + synchronized (filters) { + if (!filters.isEmpty()) { + for (Filter filter : filters) { + filter.destroy(context, config); + } + } + } + } + + @SuppressWarnings("unchecked") + public void addFilter(Filter filter, AnyValue conf) { + filter._conf = conf; + synchronized (filters) { + this.filters.add(filter); + Collections.sort(this.filters); + } + } + + public > T removeFilter(Class filterClass) { + return removeFilter(f -> filterClass.equals(f.getClass())); + } + + public boolean containsFilter(Class filterClass) { + if (this.headFilter == null || filterClass == null) return false; + Filter filter = this.headFilter; + do { + if (filter.getClass().equals(filterClass)) return true; + } while ((filter = filter._next) != null); + return false; + } + + public boolean containsFilter(String filterClassName) { + if (this.headFilter == null || filterClassName == null) return false; + Filter filter = this.headFilter; + do { + if (filter.getClass().getName().equals(filterClassName)) return true; + } while ((filter = filter._next) != null); + return false; + } + + @SuppressWarnings("unchecked") + public > T removeFilter(Predicate predicate) { + if (this.headFilter == null || predicate == null) return null; + synchronized (filters) { + Filter filter = this.headFilter; + Filter prev = null; + do { + if (predicate.test((T) filter)) break; + prev = filter; + } while ((filter = filter._next) != null); + if (filter != null) { + if (prev == null) { + this.headFilter = filter._next; + } else { + prev._next = filter._next; + } + filter._next = null; + this.filters.remove(filter); + } + return (T) filter; + } + } + + @SuppressWarnings("unchecked") + public > List getFilters() { + return (List) new ArrayList<>(filters); + } + + @SuppressWarnings("unchecked") + public abstract void addServlet(S servlet, Object attachment, AnyValue conf, K... mappings); + + public final void prepare(final R request, final P response) { + try { + request.prepare(); + response.filter = this.headFilter; + response.servlet = this; + response.nextEvent(); + } catch (Throwable t) { + response.context.logger.log(Level.WARNING, "prepare servlet abort, force to close channel ", t); + response.finish(true); + } + } + + protected AnyValue getServletConf(Servlet servlet) { + return servlet._conf; + } + + protected void setServletConf(Servlet servlet, AnyValue conf) { + servlet._conf = conf; + } + + public List getServlets() { + return new ArrayList<>(servlets); + } + + protected Stream servletStream() { + return servlets.stream(); + } +} diff --git a/src/main/java/org/redkale/net/ProtocolCodec.java b/src/main/java/org/redkale/net/ProtocolCodec.java index a8fa7559c..ef7c113d1 100644 --- a/src/main/java/org/redkale/net/ProtocolCodec.java +++ b/src/main/java/org/redkale/net/ProtocolCodec.java @@ -1,197 +1,197 @@ -/* - * 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; - -import java.net.SocketException; -import java.nio.ByteBuffer; -import java.nio.channels.CompletionHandler; -import java.util.concurrent.atomic.LongAdder; -import java.util.function.*; -import java.util.logging.Level; - -/** - * - * @author zhangjx - */ -class ProtocolCodec implements CompletionHandler { - - private final AsyncConnection channel; - - private final Context context; - - private Supplier responseSupplier; - - private Consumer responseConsumer; - - private Response resp; - - public ProtocolCodec(Context context, Supplier responseSupplier, - Consumer responseConsumer, AsyncConnection channel) { - this.context = context; - this.channel = channel; - this.responseSupplier = responseSupplier; - this.responseConsumer = responseConsumer; - } - - public ProtocolCodec response(Response resp) { - this.resp = resp; - return this; - } - - private Response createResponse() { - Response response = resp; - if (response == null) { - response = responseSupplier.get(); - } else { - response.prepare(); - } - response.responseSupplier = responseSupplier; - response.responseConsumer = responseConsumer; - return response; - } - - @Override - public void completed(Integer count, ByteBuffer buffer) { - if (count < 1) { - channel.offerBuffer(buffer); - channel.dispose(); // response.init(channel); 鍦ㄨ皟鐢ㄤ箣鍓嶅紓甯 - return; - } -// { //娴嬭瘯 -// buffer.flip(); -// byte[] bs = new byte[buffer.remaining()]; -// buffer.get(bs); -// System.println(new String(bs)); -// } - buffer.flip(); - final Response response = createResponse(); - try { - decode(buffer, response, 0, null); - } catch (Throwable t) { //姝ゅ涓嶅彲 context.offerBuffer(buffer); 浠ュ厤prepare.prepare鍐呴儴寮傚父瀵艰嚧閲嶅 offerBuffer - context.logger.log(Level.WARNING, "prepare servlet abort, force to close channel ", t); - response.finish(true); - } - } - - @Override - public void failed(Throwable exc, ByteBuffer buffer) { - channel.offerBuffer(buffer); - channel.dispose();// response.init(channel); 鍦ㄨ皟鐢ㄤ箣鍓嶅紓甯 - if (exc != null && context.logger.isLoggable(Level.FINEST) - && !(exc instanceof SocketException && "Connection reset".equals(exc.getMessage()))) { - context.logger.log(Level.FINEST, "Servlet Handler read channel erroneous, force to close channel ", exc); - } - } - - public void start(final ByteBuffer data) { - if (data != null) { //pipeline妯″紡鎴朥DP杩炴帴鍒涘缓AsyncConnection鏃跺凡缁忚幏鍙栧埌ByteBuffer鏁版嵁浜 - final Response response = createResponse(); - try { - decode(data, response, 0, null); - } catch (Throwable t) { - context.logger.log(Level.WARNING, "prepare servlet abort, force to close channel ", t); - response.finish(true); - } - return; - } - try { - channel.startRead(this); - } catch (Exception te) { - channel.dispose();// response.init(channel); 鍦ㄨ皟鐢ㄤ箣鍓嶅紓甯 - if (context.logger.isLoggable(Level.FINEST)) { - context.logger.log(Level.FINEST, "Servlet read channel erroneous, force to close channel ", te); - } - } - } - - public void run(final ByteBuffer data) { - if (data != null) { //pipeline妯″紡鎴朥DP杩炴帴鍒涘缓AsyncConnection鏃跺凡缁忚幏鍙栧埌ByteBuffer鏁版嵁浜 - final Response response = createResponse(); - try { - decode(data, response, 0, null); - } catch (Throwable t) { - context.logger.log(Level.WARNING, "prepare servlet abort, force to close channel ", t); - response.finish(true); - } - return; - } - try { - channel.read(this); - } catch (Exception te) { - channel.dispose();// response.init(channel); 鍦ㄨ皟鐢ㄤ箣鍓嶅紓甯 - if (context.logger.isLoggable(Level.FINEST)) { - context.logger.log(Level.FINEST, "Servlet read channel erroneous, force to close channel ", te); - } - } - } - - protected void decode(final ByteBuffer buffer, final Response response, final int pipelineIndex, final Request lastreq) { - response.init(channel); - final Request request = response.request; - final int rs = request.readHeader(buffer, lastreq); - if (rs < 0) { //琛ㄧず鏁版嵁鏍煎紡涓嶆纭 - final PrepareServlet preparer = context.prepare; - LongAdder ec = preparer.executeCounter; - if (ec != null) ec.increment(); - channel.offerBuffer(buffer); - if (rs != Integer.MIN_VALUE && preparer.illRequestCounter != null) preparer.illRequestCounter.increment(); - response.finish(true); - if (context.logger.isLoggable(Level.FINEST)) { - context.logger.log(Level.FINEST, "request.readHeader erroneous (" + rs + "), force to close channel "); - } - } else if (rs == 0) { - final PrepareServlet preparer = context.prepare; - LongAdder ec = preparer.executeCounter; - if (ec != null) ec.increment(); - int pindex = pipelineIndex; - boolean pipeline = false; - Request hreq = lastreq; - if (buffer.hasRemaining()) { - pipeline = true; - if (pindex == 0) pindex++; - request.pipeline(pindex, pindex + 1); - if (hreq == null) hreq = request.copyHeader(); - } else { - request.pipeline(pindex, pindex); - channel.setReadBuffer((ByteBuffer) buffer.clear()); - } - context.executePrepareServlet(request, response); - if (pipeline) { - final Response pipelineResponse = createResponse(); - try { - decode(buffer, pipelineResponse, pindex + 1, hreq); - } catch (Throwable t) { //姝ゅ涓嶅彲 offerBuffer(buffer); 浠ュ厤prepare.prepare鍐呴儴寮傚父瀵艰嚧閲嶅 offerBuffer - context.logger.log(Level.WARNING, "prepare pipeline servlet abort, force to close channel ", t); - pipelineResponse.finish(true); - } - } - } else { - channel.setReadBuffer(buffer); - channel.read(new CompletionHandler() { - - @Override - public void completed(Integer count, ByteBuffer attachment) { - if (count < 1) { - channel.offerBuffer(attachment); - channel.dispose(); - return; - } - attachment.flip(); - decode(attachment, response, pipelineIndex, lastreq); - } - - @Override - public void failed(Throwable exc, ByteBuffer attachment) { - if (context.prepare.illRequestCounter != null) context.prepare.illRequestCounter.increment(); - channel.offerBuffer(attachment); - response.finish(true); - if (exc != null) request.context.logger.log(Level.FINER, "Servlet read channel erroneous, force to close channel ", exc); - } - }); - } - } - -} +/* + * 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; + +import java.net.SocketException; +import java.nio.ByteBuffer; +import java.nio.channels.CompletionHandler; +import java.util.concurrent.atomic.LongAdder; +import java.util.function.*; +import java.util.logging.Level; + +/** + * + * @author zhangjx + */ +class ProtocolCodec implements CompletionHandler { + + private final AsyncConnection channel; + + private final Context context; + + private Supplier responseSupplier; + + private Consumer responseConsumer; + + private Response resp; + + public ProtocolCodec(Context context, Supplier responseSupplier, + Consumer responseConsumer, AsyncConnection channel) { + this.context = context; + this.channel = channel; + this.responseSupplier = responseSupplier; + this.responseConsumer = responseConsumer; + } + + public ProtocolCodec response(Response resp) { + this.resp = resp; + return this; + } + + private Response createResponse() { + Response response = resp; + if (response == null) { + response = responseSupplier.get(); + } else { + response.prepare(); + } + response.responseSupplier = responseSupplier; + response.responseConsumer = responseConsumer; + return response; + } + + @Override + public void completed(Integer count, ByteBuffer buffer) { + if (count < 1) { + channel.offerBuffer(buffer); + channel.dispose(); // response.init(channel); 鍦ㄨ皟鐢ㄤ箣鍓嶅紓甯 + return; + } +// { //娴嬭瘯 +// buffer.flip(); +// byte[] bs = new byte[buffer.remaining()]; +// buffer.get(bs); +// System.println(new String(bs)); +// } + buffer.flip(); + final Response response = createResponse(); + try { + decode(buffer, response, 0, null); + } catch (Throwable t) { //姝ゅ涓嶅彲 context.offerBuffer(buffer); 浠ュ厤prepare.prepare鍐呴儴寮傚父瀵艰嚧閲嶅 offerBuffer + context.logger.log(Level.WARNING, "prepare servlet abort, force to close channel ", t); + response.finish(true); + } + } + + @Override + public void failed(Throwable exc, ByteBuffer buffer) { + channel.offerBuffer(buffer); + channel.dispose();// response.init(channel); 鍦ㄨ皟鐢ㄤ箣鍓嶅紓甯 + if (exc != null && context.logger.isLoggable(Level.FINEST) + && !(exc instanceof SocketException && "Connection reset".equals(exc.getMessage()))) { + context.logger.log(Level.FINEST, "Servlet Handler read channel erroneous, force to close channel ", exc); + } + } + + public void start(final ByteBuffer data) { + if (data != null) { //pipeline妯″紡鎴朥DP杩炴帴鍒涘缓AsyncConnection鏃跺凡缁忚幏鍙栧埌ByteBuffer鏁版嵁浜 + final Response response = createResponse(); + try { + decode(data, response, 0, null); + } catch (Throwable t) { + context.logger.log(Level.WARNING, "prepare servlet abort, force to close channel ", t); + response.finish(true); + } + return; + } + try { + channel.startRead(this); + } catch (Exception te) { + channel.dispose();// response.init(channel); 鍦ㄨ皟鐢ㄤ箣鍓嶅紓甯 + if (context.logger.isLoggable(Level.FINEST)) { + context.logger.log(Level.FINEST, "Servlet read channel erroneous, force to close channel ", te); + } + } + } + + public void run(final ByteBuffer data) { + if (data != null) { //pipeline妯″紡鎴朥DP杩炴帴鍒涘缓AsyncConnection鏃跺凡缁忚幏鍙栧埌ByteBuffer鏁版嵁浜 + final Response response = createResponse(); + try { + decode(data, response, 0, null); + } catch (Throwable t) { + context.logger.log(Level.WARNING, "prepare servlet abort, force to close channel ", t); + response.finish(true); + } + return; + } + try { + channel.read(this); + } catch (Exception te) { + channel.dispose();// response.init(channel); 鍦ㄨ皟鐢ㄤ箣鍓嶅紓甯 + if (context.logger.isLoggable(Level.FINEST)) { + context.logger.log(Level.FINEST, "Servlet read channel erroneous, force to close channel ", te); + } + } + } + + protected void decode(final ByteBuffer buffer, final Response response, final int pipelineIndex, final Request lastreq) { + response.init(channel); + final Request request = response.request; + final int rs = request.readHeader(buffer, lastreq); + if (rs < 0) { //琛ㄧず鏁版嵁鏍煎紡涓嶆纭 + final PrepareServlet preparer = context.prepare; + LongAdder ec = preparer.executeCounter; + if (ec != null) ec.increment(); + channel.offerBuffer(buffer); + if (rs != Integer.MIN_VALUE && preparer.illRequestCounter != null) preparer.illRequestCounter.increment(); + response.finish(true); + if (context.logger.isLoggable(Level.FINEST)) { + context.logger.log(Level.FINEST, "request.readHeader erroneous (" + rs + "), force to close channel "); + } + } else if (rs == 0) { + final PrepareServlet preparer = context.prepare; + LongAdder ec = preparer.executeCounter; + if (ec != null) ec.increment(); + int pindex = pipelineIndex; + boolean pipeline = false; + Request hreq = lastreq; + if (buffer.hasRemaining()) { + pipeline = true; + if (pindex == 0) pindex++; + request.pipeline(pindex, pindex + 1); + if (hreq == null) hreq = request.copyHeader(); + } else { + request.pipeline(pindex, pindex); + channel.setReadBuffer((ByteBuffer) buffer.clear()); + } + context.executePrepareServlet(request, response); + if (pipeline) { + final Response pipelineResponse = createResponse(); + try { + decode(buffer, pipelineResponse, pindex + 1, hreq); + } catch (Throwable t) { //姝ゅ涓嶅彲 offerBuffer(buffer); 浠ュ厤prepare.prepare鍐呴儴寮傚父瀵艰嚧閲嶅 offerBuffer + context.logger.log(Level.WARNING, "prepare pipeline servlet abort, force to close channel ", t); + pipelineResponse.finish(true); + } + } + } else { + channel.setReadBuffer(buffer); + channel.read(new CompletionHandler() { + + @Override + public void completed(Integer count, ByteBuffer attachment) { + if (count < 1) { + channel.offerBuffer(attachment); + channel.dispose(); + return; + } + attachment.flip(); + decode(attachment, response, pipelineIndex, lastreq); + } + + @Override + public void failed(Throwable exc, ByteBuffer attachment) { + if (context.prepare.illRequestCounter != null) context.prepare.illRequestCounter.increment(); + channel.offerBuffer(attachment); + response.finish(true); + if (exc != null) request.context.logger.log(Level.FINER, "Servlet read channel erroneous, force to close channel ", exc); + } + }); + } + } + +} diff --git a/src/main/java/org/redkale/net/ProtocolServer.java b/src/main/java/org/redkale/net/ProtocolServer.java index 0dcc9b5a5..47e4fbd8e 100644 --- a/src/main/java/org/redkale/net/ProtocolServer.java +++ b/src/main/java/org/redkale/net/ProtocolServer.java @@ -1,68 +1,68 @@ -/* - * 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; - -import java.io.IOException; -import java.net.*; -import java.util.*; -import javax.annotation.Resource; -import org.redkale.boot.Application; -import org.redkale.util.AnyValue; - -/** - * 鍗忚搴曞眰Server - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public abstract class ProtocolServer { - - protected final Context context; - - //鏈澶ц繛鎺ユ暟锛屽皬浜1琛ㄧず鏃犻檺鍒 - protected int maxconns; - - @Resource - protected Application application; - - public abstract void open(AnyValue config) throws IOException; - - public abstract void bind(SocketAddress local, int backlog) throws IOException; - - public abstract Set> supportedOptions(); - - public abstract void setOption(SocketOption name, T value) throws IOException; - - public abstract void accept(Application application, Server server) throws IOException; - - public abstract void close() throws IOException; - - protected ProtocolServer(Context context) { - this.context = context; - this.maxconns = context.getMaxconns(); - } - - //--------------------------------------------------------------------- - public static ProtocolServer create(String protocol, Context context, ClassLoader classLoader) { - if ("TCP".equalsIgnoreCase(protocol)) { - return new AsyncNioTcpProtocolServer(context); - } else if ("UDP".equalsIgnoreCase(protocol)) { - return new AsyncNioUdpProtocolServer(context); - } else { - throw new RuntimeException(ProtocolServer.class.getSimpleName() + " not support protocol " + protocol); - } - } - - public abstract AsyncGroup getAsyncGroup(); - - public abstract long getCreateConnectionCount(); - - public abstract long getClosedConnectionCount(); - - public abstract long getLivingConnectionCount(); -} +/* + * 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; + +import java.io.IOException; +import java.net.*; +import java.util.*; +import javax.annotation.Resource; +import org.redkale.boot.Application; +import org.redkale.util.AnyValue; + +/** + * 鍗忚搴曞眰Server + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public abstract class ProtocolServer { + + protected final Context context; + + //鏈澶ц繛鎺ユ暟锛屽皬浜1琛ㄧず鏃犻檺鍒 + protected int maxconns; + + @Resource + protected Application application; + + public abstract void open(AnyValue config) throws IOException; + + public abstract void bind(SocketAddress local, int backlog) throws IOException; + + public abstract Set> supportedOptions(); + + public abstract void setOption(SocketOption name, T value) throws IOException; + + public abstract void accept(Application application, Server server) throws IOException; + + public abstract void close() throws IOException; + + protected ProtocolServer(Context context) { + this.context = context; + this.maxconns = context.getMaxconns(); + } + + //--------------------------------------------------------------------- + public static ProtocolServer create(String protocol, Context context, ClassLoader classLoader) { + if ("TCP".equalsIgnoreCase(protocol)) { + return new AsyncNioTcpProtocolServer(context); + } else if ("UDP".equalsIgnoreCase(protocol)) { + return new AsyncNioUdpProtocolServer(context); + } else { + throw new RuntimeException(ProtocolServer.class.getSimpleName() + " not support protocol " + protocol); + } + } + + public abstract AsyncGroup getAsyncGroup(); + + public abstract long getCreateConnectionCount(); + + public abstract long getClosedConnectionCount(); + + public abstract long getLivingConnectionCount(); +} diff --git a/src/main/java/org/redkale/net/Request.java b/src/main/java/org/redkale/net/Request.java index fde648ab3..3a97338f1 100644 --- a/src/main/java/org/redkale/net/Request.java +++ b/src/main/java/org/redkale/net/Request.java @@ -1,155 +1,155 @@ -/* - * 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; - -import java.io.*; -import java.nio.ByteBuffer; -import java.util.*; -import org.redkale.convert.bson.BsonConvert; -import org.redkale.convert.json.JsonConvert; - -/** - * 鍗忚璇锋眰瀵硅薄 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Context瀛愮被鍨 - */ -public abstract class Request { - - protected final C context; - - protected final BsonConvert bsonConvert; - - protected final JsonConvert jsonConvert; - - protected long createtime; - - protected boolean keepAlive; - - protected int pipelineIndex; - - protected int pipelineCount; - - protected boolean pipelineOver; - - protected int hashid; - - protected AsyncConnection channel; - - /** - * properties 涓 attributes 鐨勫尯鍒湪浜庯細璋冪敤recycle鏃讹紝 attributes浼氳娓呯┖鑰宲roperties浼氫繚鐣; - * properties 閫氬父瀛樻斁闇瑕佹案涔呯粦瀹氬湪request閲岀殑涓浜涘璞 - */ - private final Map properties = new HashMap<>(); - - protected final Map attributes = new HashMap<>(); - - protected Request(C context) { - this.context = context; - this.bsonConvert = context.getBsonConvert(); - this.jsonConvert = context.getJsonConvert(); - } - - protected Request copyHeader() { - return null; - } - - protected Request pipeline(int pipelineIndex, int pipelineCount) { - this.pipelineIndex = pipelineIndex; - this.pipelineCount = pipelineCount; - return this; - } - - /** - * 杩斿洖鍊硷細Integer.MIN_VALUE: 甯ф暟鎹紱 -1锛氭暟鎹笉鍚堟硶锛 0锛氳В鏋愬畬姣曪紱 >0: 闇鍐嶈鍙栫殑瀛楄妭鏁般 - * - * @param buffer ByteBuffer瀵硅薄 - * @param last 鍚屼竴Channel鐨勪笂涓涓猂equest - * - * @return 缂哄皯鐨勫瓧鑺傛暟 - */ - protected abstract int readHeader(ByteBuffer buffer, Request last); - - protected abstract void prepare(); - - protected void recycle() { - hashid = 0; - createtime = 0; - pipelineIndex = 0; - pipelineCount = 0; - pipelineOver = false; - keepAlive = false; - attributes.clear(); - channel = null; // close it by response - } - - protected T setProperty(String name, T value) { - properties.put(name, value); - return value; - } - - @SuppressWarnings("unchecked") - protected T getProperty(String name) { - return (T) properties.get(name); - } - - @SuppressWarnings("unchecked") - protected T removeProperty(String name) { - return (T) properties.remove(name); - } - - protected Map getProperties() { - return properties; - } - - protected InputStream newInputStream() { - return ((AsyncNioConnection) channel).newInputStream(); - } - - public T setAttribute(String name, T value) { - attributes.put(name, value); - return value; - } - - @SuppressWarnings("unchecked") - public T getAttribute(String name) { - return (T) attributes.get(name); - } - - @SuppressWarnings("unchecked") - public T removeAttribute(String name) { - return (T) attributes.remove(name); - } - - public Map getAttributes() { - return attributes; - } - - public ChannelContext getChannelContext() { - return channel; - } - - public C getContext() { - return this.context; - } - - public long getCreatetime() { - return createtime; - } - - public int getHashid() { - return hashid; - } - - public Request hashid(int hashid) { - this.hashid = hashid; - return this; - } - -} +/* + * 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; + +import java.io.*; +import java.nio.ByteBuffer; +import java.util.*; +import org.redkale.convert.bson.BsonConvert; +import org.redkale.convert.json.JsonConvert; + +/** + * 鍗忚璇锋眰瀵硅薄 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Context瀛愮被鍨 + */ +public abstract class Request { + + protected final C context; + + protected final BsonConvert bsonConvert; + + protected final JsonConvert jsonConvert; + + protected long createtime; + + protected boolean keepAlive; + + protected int pipelineIndex; + + protected int pipelineCount; + + protected boolean pipelineOver; + + protected int hashid; + + protected AsyncConnection channel; + + /** + * properties 涓 attributes 鐨勫尯鍒湪浜庯細璋冪敤recycle鏃讹紝 attributes浼氳娓呯┖鑰宲roperties浼氫繚鐣; + * properties 閫氬父瀛樻斁闇瑕佹案涔呯粦瀹氬湪request閲岀殑涓浜涘璞 + */ + private final Map properties = new HashMap<>(); + + protected final Map attributes = new HashMap<>(); + + protected Request(C context) { + this.context = context; + this.bsonConvert = context.getBsonConvert(); + this.jsonConvert = context.getJsonConvert(); + } + + protected Request copyHeader() { + return null; + } + + protected Request pipeline(int pipelineIndex, int pipelineCount) { + this.pipelineIndex = pipelineIndex; + this.pipelineCount = pipelineCount; + return this; + } + + /** + * 杩斿洖鍊硷細Integer.MIN_VALUE: 甯ф暟鎹紱 -1锛氭暟鎹笉鍚堟硶锛 0锛氳В鏋愬畬姣曪紱 >0: 闇鍐嶈鍙栫殑瀛楄妭鏁般 + * + * @param buffer ByteBuffer瀵硅薄 + * @param last 鍚屼竴Channel鐨勪笂涓涓猂equest + * + * @return 缂哄皯鐨勫瓧鑺傛暟 + */ + protected abstract int readHeader(ByteBuffer buffer, Request last); + + protected abstract void prepare(); + + protected void recycle() { + hashid = 0; + createtime = 0; + pipelineIndex = 0; + pipelineCount = 0; + pipelineOver = false; + keepAlive = false; + attributes.clear(); + channel = null; // close it by response + } + + protected T setProperty(String name, T value) { + properties.put(name, value); + return value; + } + + @SuppressWarnings("unchecked") + protected T getProperty(String name) { + return (T) properties.get(name); + } + + @SuppressWarnings("unchecked") + protected T removeProperty(String name) { + return (T) properties.remove(name); + } + + protected Map getProperties() { + return properties; + } + + protected InputStream newInputStream() { + return ((AsyncNioConnection) channel).newInputStream(); + } + + public T setAttribute(String name, T value) { + attributes.put(name, value); + return value; + } + + @SuppressWarnings("unchecked") + public T getAttribute(String name) { + return (T) attributes.get(name); + } + + @SuppressWarnings("unchecked") + public T removeAttribute(String name) { + return (T) attributes.remove(name); + } + + public Map getAttributes() { + return attributes; + } + + public ChannelContext getChannelContext() { + return channel; + } + + public C getContext() { + return this.context; + } + + public long getCreatetime() { + return createtime; + } + + public int getHashid() { + return hashid; + } + + public Request hashid(int hashid) { + this.hashid = hashid; + return this; + } + +} diff --git a/src/main/java/org/redkale/net/Response.java b/src/main/java/org/redkale/net/Response.java index 7c402a18f..58e459e21 100644 --- a/src/main/java/org/redkale/net/Response.java +++ b/src/main/java/org/redkale/net/Response.java @@ -1,390 +1,390 @@ -/* - * 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; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.channels.CompletionHandler; -import java.util.function.*; -import java.util.logging.Level; -import org.redkale.util.ByteTuple; - -/** - * 鍗忚鍝嶅簲瀵硅薄 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Context鐨勫瓙绫诲瀷 - * @param Request鐨勫瓙绫诲瀷 - */ -@SuppressWarnings("unchecked") -public abstract class Response> { - - protected final C context; - - protected Supplier responseSupplier; //铏氭嫙鏋勫缓鐨凴esponse鍙兘涓嶅瓨鍦╮esponseSupplier - - protected Consumer responseConsumer; //铏氭嫙鏋勫缓鐨凴esponse鍙兘涓嶅瓨鍦╮esponseConsumer - - protected final R request; - - protected final WorkThread thread; - - protected AsyncConnection channel; - - private volatile boolean inited = true; - - protected Object output; //杈撳嚭鐨勭粨鏋滃璞 - - protected BiConsumer> recycleListener; - - protected Filter> filter; - - protected Servlet> servlet; - - private final CompletionHandler finishBytesHandler = new CompletionHandler() { - - @Override - public void completed(Integer result, Void attachment) { - finish(); - } - - @Override - public void failed(Throwable exc, Void attachment) { - finish(true); - } - - }; - - private final CompletionHandler finishBufferHandler = new CompletionHandler() { - - @Override - public void completed(Integer result, ByteBuffer attachment) { - channel.offerBuffer(attachment); - finish(); - } - - @Override - public void failed(Throwable exc, ByteBuffer attachment) { - channel.offerBuffer(attachment); - finish(true); - } - - }; - - private final CompletionHandler finishBuffersHandler = new CompletionHandler() { - - @Override - public void completed(final Integer result, final ByteBuffer[] attachments) { - if (attachments != null) { - for (ByteBuffer attachment : attachments) { - channel.offerBuffer(attachment); - } - } - finish(); - } - - @Override - public void failed(Throwable exc, final ByteBuffer[] attachments) { - if (attachments != null) { - for (ByteBuffer attachment : attachments) { - channel.offerBuffer(attachment); - } - } - finish(true); - } - - }; - - protected Response(C context, final R request) { - this.context = context; - this.request = request; - this.thread = WorkThread.currWorkThread(); - } - - protected AsyncConnection removeChannel() { - AsyncConnection ch = this.channel; - this.channel = null; - this.request.channel = null; - return ch; - } - - protected void prepare() { - inited = true; - request.prepare(); - } - - protected boolean recycle() { - if (!inited) return false; - this.output = null; - this.filter = null; - this.servlet = null; - boolean notpipeline = request.pipelineIndex == 0 || request.pipelineOver; - request.recycle(); - if (channel != null) { - if (notpipeline) channel.dispose(); - channel = null; - } - this.responseSupplier = null; - this.responseConsumer = null; - this.inited = false; - return true; - } - - protected void refuseAlive() { - this.request.keepAlive = false; - } - - protected void init(AsyncConnection channel) { - this.channel = channel; - this.request.channel = channel; - this.request.createtime = System.currentTimeMillis(); - } - - protected void setFilter(Filter> filter) { - this.filter = filter; - } - - protected void thenEvent(Servlet servlet) { - this.servlet = servlet; - } - - @SuppressWarnings("unchecked") - public void nextEvent() throws IOException { - if (this.filter != null) { - Filter runner = this.filter; - this.filter = this.filter._next; - runner.doFilter(request, this); - return; - } - if (this.servlet != null) { - Servlet s = this.servlet; - this.servlet = null; - s.execute(request, this); - } - } - - public void recycleListener(BiConsumer> recycleListener) { - this.recycleListener = recycleListener; - } - - public Object getOutput() { - return output; - } - - /** - * 鏄惁宸插叧闂 - * - * @return boolean - */ - public boolean isClosed() { - return !this.inited; - } - - public void finish() { - this.finish(false); - } - - public void finish(boolean kill) { - if (!this.inited) return; //閬垮厤閲嶅鍏抽棴 - //System.println("鑰楁椂: " + (System.currentTimeMillis() - request.createtime)); - if (kill) refuseAlive(); - if (this.recycleListener != null) { - try { - this.recycleListener.accept(request, this); - } catch (Exception e) { - context.logger.log(Level.WARNING, "Response.recycleListener error, request = " + request, e); - } - this.recycleListener = null; - } - if (request.keepAlive && (request.pipelineIndex == 0 || request.pipelineOver)) { - AsyncConnection conn = removeChannel(); - if (conn != null && conn.protocolCodec != null) { - this.responseConsumer.accept(this); - conn.read(conn.protocolCodec); - } else { - Supplier poolSupplier = this.responseSupplier; - Consumer poolConsumer = this.responseConsumer; - this.recycle(); - new ProtocolCodec(context, poolSupplier, poolConsumer, conn).response(this).run(null); - } - } else { - this.responseConsumer.accept(this); - } - } - - public final void finish(final byte[] bs) { - finish(false, bs, 0, bs.length); - } - - public final void finish(final byte[] bs, int offset, int length) { - finish(false, bs, offset, length); - } - - public final void finish(final ByteTuple array) { - finish(false, array.content(), array.offset(), array.length()); - } - - public final void finish(boolean kill, final byte[] bs) { - finish(kill, bs, 0, bs.length); - } - - public final void finish(boolean kill, final ByteTuple array) { - finish(kill, array.content(), array.offset(), array.length()); - } - - public void finish(boolean kill, final byte[] bs, int offset, int length) { - if (!this.inited) return; //閬垮厤閲嶅鍏抽棴 - if (kill) refuseAlive(); - if (this.channel.hasPipelineData()) { - this.channel.flushPipelineData(null, new CompletionHandler() { - - @Override - public void completed(Integer result, Void attachment) { - channel.write(bs, offset, length, finishBytesHandler); - } - - @Override - public void failed(Throwable exc, Void attachment) { - finishBytesHandler.failed(exc, attachment); - } - }); - } else { - this.channel.write(bs, offset, length, finishBytesHandler); - } - } - - public void finish(boolean kill, final byte[] bs, int offset, int length, final byte[] bs2, int offset2, int length2, Consumer callback, A attachment) { - if (!this.inited) return; //閬垮厤閲嶅鍏抽棴 - if (kill) refuseAlive(); - if (this.channel.hasPipelineData()) { - this.channel.flushPipelineData(null, new CompletionHandler() { - - @Override - public void completed(Integer result, Void attachment) { - channel.write(bs, offset, length, bs2, offset2, length2, callback, attachment, finishBytesHandler); - } - - @Override - public void failed(Throwable exc, Void attachment) { - finishBytesHandler.failed(exc, attachment); - } - }); - } else { - this.channel.write(bs, offset, length, bs2, offset2, length2, callback, attachment, finishBytesHandler); - } - } - - protected final void finish(ByteBuffer buffer) { - finish(false, buffer); - } - - protected final void finish(ByteBuffer... buffers) { - finish(false, buffers); - } - - protected void finish(boolean kill, ByteBuffer buffer) { - if (!this.inited) return; //閬垮厤閲嶅鍏抽棴 - if (kill) refuseAlive(); - if (this.channel.hasPipelineData()) { - this.channel.flushPipelineData(null, new CompletionHandler() { - - @Override - public void completed(Integer result, Void attachment) { - channel.write(buffer, buffer, finishBufferHandler); - } - - @Override - public void failed(Throwable exc, Void attachment) { - finishBufferHandler.failed(exc, buffer); - } - }); - } else { - this.channel.write(buffer, buffer, finishBufferHandler); - } - } - - protected void finish(boolean kill, ByteBuffer... buffers) { - if (!this.inited) return; //閬垮厤閲嶅鍏抽棴 - if (kill) refuseAlive(); - if (this.channel.hasPipelineData()) { - this.channel.flushPipelineData(null, new CompletionHandler() { - - @Override - public void completed(Integer result, Void attachment) { - channel.write(buffers, buffers, finishBuffersHandler); - } - - @Override - public void failed(Throwable exc, Void attachment) { - finishBuffersHandler.failed(exc, buffers); - } - }); - } else { - this.channel.write(buffers, buffers, finishBuffersHandler); - } - } - - protected void send(final ByteTuple array, final CompletionHandler handler) { - this.channel.write(array, new CompletionHandler() { - - @Override - public void completed(Integer result, Void attachment) { - if (handler != null) handler.completed(result, attachment); - } - - @Override - public void failed(Throwable exc, Void attachment) { - if (handler != null) handler.failed(exc, attachment); - } - - }); - } - - protected void send(final ByteBuffer buffer, final A attachment, final CompletionHandler handler) { - this.channel.write(buffer, attachment, new CompletionHandler() { - - @Override - public void completed(Integer result, A attachment) { - channel.offerBuffer(buffer); - if (handler != null) handler.completed(result, attachment); - } - - @Override - public void failed(Throwable exc, A attachment) { - channel.offerBuffer(buffer); - if (handler != null) handler.failed(exc, attachment); - } - - }); - } - - protected void send(final ByteBuffer[] buffers, A attachment, final CompletionHandler handler) { - this.channel.write(buffers, attachment, new CompletionHandler() { - - @Override - public void completed(Integer result, A attachment) { - channel.offerBuffer(buffers); - if (handler != null) handler.completed(result, attachment); - } - - @Override - public void failed(Throwable exc, A attachment) { - for (ByteBuffer buffer : buffers) { - channel.offerBuffer(buffer); - } - if (handler != null) handler.failed(exc, attachment); - } - - }); - } - - public C getContext() { - return context; - } -} +/* + * 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; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.CompletionHandler; +import java.util.function.*; +import java.util.logging.Level; +import org.redkale.util.ByteTuple; + +/** + * 鍗忚鍝嶅簲瀵硅薄 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Context鐨勫瓙绫诲瀷 + * @param Request鐨勫瓙绫诲瀷 + */ +@SuppressWarnings("unchecked") +public abstract class Response> { + + protected final C context; + + protected Supplier responseSupplier; //铏氭嫙鏋勫缓鐨凴esponse鍙兘涓嶅瓨鍦╮esponseSupplier + + protected Consumer responseConsumer; //铏氭嫙鏋勫缓鐨凴esponse鍙兘涓嶅瓨鍦╮esponseConsumer + + protected final R request; + + protected final WorkThread thread; + + protected AsyncConnection channel; + + private volatile boolean inited = true; + + protected Object output; //杈撳嚭鐨勭粨鏋滃璞 + + protected BiConsumer> recycleListener; + + protected Filter> filter; + + protected Servlet> servlet; + + private final CompletionHandler finishBytesHandler = new CompletionHandler() { + + @Override + public void completed(Integer result, Void attachment) { + finish(); + } + + @Override + public void failed(Throwable exc, Void attachment) { + finish(true); + } + + }; + + private final CompletionHandler finishBufferHandler = new CompletionHandler() { + + @Override + public void completed(Integer result, ByteBuffer attachment) { + channel.offerBuffer(attachment); + finish(); + } + + @Override + public void failed(Throwable exc, ByteBuffer attachment) { + channel.offerBuffer(attachment); + finish(true); + } + + }; + + private final CompletionHandler finishBuffersHandler = new CompletionHandler() { + + @Override + public void completed(final Integer result, final ByteBuffer[] attachments) { + if (attachments != null) { + for (ByteBuffer attachment : attachments) { + channel.offerBuffer(attachment); + } + } + finish(); + } + + @Override + public void failed(Throwable exc, final ByteBuffer[] attachments) { + if (attachments != null) { + for (ByteBuffer attachment : attachments) { + channel.offerBuffer(attachment); + } + } + finish(true); + } + + }; + + protected Response(C context, final R request) { + this.context = context; + this.request = request; + this.thread = WorkThread.currWorkThread(); + } + + protected AsyncConnection removeChannel() { + AsyncConnection ch = this.channel; + this.channel = null; + this.request.channel = null; + return ch; + } + + protected void prepare() { + inited = true; + request.prepare(); + } + + protected boolean recycle() { + if (!inited) return false; + this.output = null; + this.filter = null; + this.servlet = null; + boolean notpipeline = request.pipelineIndex == 0 || request.pipelineOver; + request.recycle(); + if (channel != null) { + if (notpipeline) channel.dispose(); + channel = null; + } + this.responseSupplier = null; + this.responseConsumer = null; + this.inited = false; + return true; + } + + protected void refuseAlive() { + this.request.keepAlive = false; + } + + protected void init(AsyncConnection channel) { + this.channel = channel; + this.request.channel = channel; + this.request.createtime = System.currentTimeMillis(); + } + + protected void setFilter(Filter> filter) { + this.filter = filter; + } + + protected void thenEvent(Servlet servlet) { + this.servlet = servlet; + } + + @SuppressWarnings("unchecked") + public void nextEvent() throws IOException { + if (this.filter != null) { + Filter runner = this.filter; + this.filter = this.filter._next; + runner.doFilter(request, this); + return; + } + if (this.servlet != null) { + Servlet s = this.servlet; + this.servlet = null; + s.execute(request, this); + } + } + + public void recycleListener(BiConsumer> recycleListener) { + this.recycleListener = recycleListener; + } + + public Object getOutput() { + return output; + } + + /** + * 鏄惁宸插叧闂 + * + * @return boolean + */ + public boolean isClosed() { + return !this.inited; + } + + public void finish() { + this.finish(false); + } + + public void finish(boolean kill) { + if (!this.inited) return; //閬垮厤閲嶅鍏抽棴 + //System.println("鑰楁椂: " + (System.currentTimeMillis() - request.createtime)); + if (kill) refuseAlive(); + if (this.recycleListener != null) { + try { + this.recycleListener.accept(request, this); + } catch (Exception e) { + context.logger.log(Level.WARNING, "Response.recycleListener error, request = " + request, e); + } + this.recycleListener = null; + } + if (request.keepAlive && (request.pipelineIndex == 0 || request.pipelineOver)) { + AsyncConnection conn = removeChannel(); + if (conn != null && conn.protocolCodec != null) { + this.responseConsumer.accept(this); + conn.read(conn.protocolCodec); + } else { + Supplier poolSupplier = this.responseSupplier; + Consumer poolConsumer = this.responseConsumer; + this.recycle(); + new ProtocolCodec(context, poolSupplier, poolConsumer, conn).response(this).run(null); + } + } else { + this.responseConsumer.accept(this); + } + } + + public final void finish(final byte[] bs) { + finish(false, bs, 0, bs.length); + } + + public final void finish(final byte[] bs, int offset, int length) { + finish(false, bs, offset, length); + } + + public final void finish(final ByteTuple array) { + finish(false, array.content(), array.offset(), array.length()); + } + + public final void finish(boolean kill, final byte[] bs) { + finish(kill, bs, 0, bs.length); + } + + public final void finish(boolean kill, final ByteTuple array) { + finish(kill, array.content(), array.offset(), array.length()); + } + + public void finish(boolean kill, final byte[] bs, int offset, int length) { + if (!this.inited) return; //閬垮厤閲嶅鍏抽棴 + if (kill) refuseAlive(); + if (this.channel.hasPipelineData()) { + this.channel.flushPipelineData(null, new CompletionHandler() { + + @Override + public void completed(Integer result, Void attachment) { + channel.write(bs, offset, length, finishBytesHandler); + } + + @Override + public void failed(Throwable exc, Void attachment) { + finishBytesHandler.failed(exc, attachment); + } + }); + } else { + this.channel.write(bs, offset, length, finishBytesHandler); + } + } + + public void finish(boolean kill, final byte[] bs, int offset, int length, final byte[] bs2, int offset2, int length2, Consumer callback, A attachment) { + if (!this.inited) return; //閬垮厤閲嶅鍏抽棴 + if (kill) refuseAlive(); + if (this.channel.hasPipelineData()) { + this.channel.flushPipelineData(null, new CompletionHandler() { + + @Override + public void completed(Integer result, Void attachment) { + channel.write(bs, offset, length, bs2, offset2, length2, callback, attachment, finishBytesHandler); + } + + @Override + public void failed(Throwable exc, Void attachment) { + finishBytesHandler.failed(exc, attachment); + } + }); + } else { + this.channel.write(bs, offset, length, bs2, offset2, length2, callback, attachment, finishBytesHandler); + } + } + + protected final void finish(ByteBuffer buffer) { + finish(false, buffer); + } + + protected final void finish(ByteBuffer... buffers) { + finish(false, buffers); + } + + protected void finish(boolean kill, ByteBuffer buffer) { + if (!this.inited) return; //閬垮厤閲嶅鍏抽棴 + if (kill) refuseAlive(); + if (this.channel.hasPipelineData()) { + this.channel.flushPipelineData(null, new CompletionHandler() { + + @Override + public void completed(Integer result, Void attachment) { + channel.write(buffer, buffer, finishBufferHandler); + } + + @Override + public void failed(Throwable exc, Void attachment) { + finishBufferHandler.failed(exc, buffer); + } + }); + } else { + this.channel.write(buffer, buffer, finishBufferHandler); + } + } + + protected void finish(boolean kill, ByteBuffer... buffers) { + if (!this.inited) return; //閬垮厤閲嶅鍏抽棴 + if (kill) refuseAlive(); + if (this.channel.hasPipelineData()) { + this.channel.flushPipelineData(null, new CompletionHandler() { + + @Override + public void completed(Integer result, Void attachment) { + channel.write(buffers, buffers, finishBuffersHandler); + } + + @Override + public void failed(Throwable exc, Void attachment) { + finishBuffersHandler.failed(exc, buffers); + } + }); + } else { + this.channel.write(buffers, buffers, finishBuffersHandler); + } + } + + protected void send(final ByteTuple array, final CompletionHandler handler) { + this.channel.write(array, new CompletionHandler() { + + @Override + public void completed(Integer result, Void attachment) { + if (handler != null) handler.completed(result, attachment); + } + + @Override + public void failed(Throwable exc, Void attachment) { + if (handler != null) handler.failed(exc, attachment); + } + + }); + } + + protected void send(final ByteBuffer buffer, final A attachment, final CompletionHandler handler) { + this.channel.write(buffer, attachment, new CompletionHandler() { + + @Override + public void completed(Integer result, A attachment) { + channel.offerBuffer(buffer); + if (handler != null) handler.completed(result, attachment); + } + + @Override + public void failed(Throwable exc, A attachment) { + channel.offerBuffer(buffer); + if (handler != null) handler.failed(exc, attachment); + } + + }); + } + + protected void send(final ByteBuffer[] buffers, A attachment, final CompletionHandler handler) { + this.channel.write(buffers, attachment, new CompletionHandler() { + + @Override + public void completed(Integer result, A attachment) { + channel.offerBuffer(buffers); + if (handler != null) handler.completed(result, attachment); + } + + @Override + public void failed(Throwable exc, A attachment) { + for (ByteBuffer buffer : buffers) { + channel.offerBuffer(buffer); + } + if (handler != null) handler.failed(exc, attachment); + } + + }); + } + + public C getContext() { + return context; + } +} diff --git a/src/main/java/org/redkale/net/SSLBuilder.java b/src/main/java/org/redkale/net/SSLBuilder.java index 0020f7198..1679529d7 100644 --- a/src/main/java/org/redkale/net/SSLBuilder.java +++ b/src/main/java/org/redkale/net/SSLBuilder.java @@ -1,168 +1,168 @@ -/* - * 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; - -import java.io.*; -import java.security.*; -import java.security.cert.*; -import java.util.*; -import java.util.logging.*; -import javax.net.ssl.*; -import org.redkale.util.*; - -/** - * 鏍规嵁閰嶇疆鐢熸垚SSLContext - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public class SSLBuilder { - - protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); - - protected String[] ciphers; - - protected String[] protocols; - - protected boolean wantClientAuth; - - protected boolean needClientAuth; - - public SSLContext createSSLContext(Server server, AnyValue sslConf) throws Exception { - String protocol = sslConf.getValue("protocol", "TLS"); - String clientauth = sslConf.getValue("clientAuth", "none"); - String sslProviderImpl = sslConf.getValue("sslProvider"); - String jsseProviderImpl = sslConf.getValue("jsseProvider"); - String enabledProtocols = sslConf.getValue("protocols", "").replaceAll("\\s+", "") - .replace(';', ',').replace(':', ',').replaceAll(",+", ",").replaceAll(",$", ""); - String enabledCiphers = sslConf.getValue("ciphers", "").replaceAll("\\s+", "") - .replace(';', ',').replace(':', ',').replaceAll(",+", ",").replaceAll(",$", ""); - - String keyfile = sslConf.getValue("keystoreFile"); - String keypass = sslConf.getValue("keystorePass", ""); - String keyType = sslConf.getValue("keystoreType", "JKS"); - String keyAlgorithm = sslConf.getValue("keystoreAlgorithm", "SunX509"); - - String trustfile = sslConf.getValue("truststoreFile"); - String trustpass = sslConf.getValue("truststorePass", ""); - String trustType = sslConf.getValue("truststoreType", "JKS"); - String trustAlgorithm = sslConf.getValue("truststoreAlgorithm", "SunX509"); - - Provider sslProvider = null; - Provider jsseProvider = null; - if (sslProviderImpl != null) { - Class providerClass = (Class) Thread.currentThread().getContextClassLoader().loadClass(sslProviderImpl); - sslProvider = providerClass.getConstructor().newInstance(); - } - if (jsseProviderImpl != null) { - Class providerClass = (Class) Thread.currentThread().getContextClassLoader().loadClass(jsseProviderImpl); - jsseProvider = providerClass.getConstructor().newInstance(); - } - - KeyManager[] keyManagers = null; - if (keyfile != null) { - KeyManagerFactory kmf = jsseProvider == null ? KeyManagerFactory.getInstance(keyAlgorithm) : KeyManagerFactory.getInstance(keyAlgorithm, jsseProvider); - KeyStore ks = jsseProvider == null ? KeyStore.getInstance(keyType) : KeyStore.getInstance(keyType, jsseProvider); - ks.load(new FileInputStream(keyfile), keypass.toCharArray()); - kmf.init(ks, keypass.toCharArray()); - keyManagers = kmf.getKeyManagers(); - } - - if ("WANT".equalsIgnoreCase(clientauth)) { - this.wantClientAuth = true; - } else if ("NEED".equalsIgnoreCase(clientauth)) { - this.needClientAuth = true; - } - - TrustManager[] trustManagers; - if (trustfile != null) { - KeyStore ts = jsseProvider == null ? KeyStore.getInstance(trustType) : KeyStore.getInstance(trustType, jsseProvider); - ts.load(new FileInputStream(trustfile), trustpass.toCharArray()); - TrustManagerFactory tmf = jsseProvider == null ? TrustManagerFactory.getInstance(trustAlgorithm) : TrustManagerFactory.getInstance(trustAlgorithm, jsseProvider); - tmf.init(ts); - trustManagers = tmf.getTrustManagers(); - } else { - trustManagers = new TrustManager[]{new X509TrustManager() { - @Override - public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { - } - - @Override - public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { - } - - @Override - public X509Certificate[] getAcceptedIssuers() { - return new X509Certificate[0]; - } - }}; - } - - SSLContext sslContext; - if (sslProvider == null) { - sslContext = SSLContext.getInstance(protocol); - } else { - sslContext = SSLContext.getInstance(protocol, sslProvider); - } - sslContext.init(keyManagers, trustManagers, new SecureRandom()); - if (!enabledProtocols.isEmpty()) { - HashSet set = new HashSet<>(); - HashSet unset = new HashSet<>(); - String[] protocolArray = sslContext.getSupportedSSLParameters().getProtocols(); - for (String p : enabledProtocols.split(",")) { - if (Utility.contains(protocolArray, p)) { - set.add(p); - } else { - unset.add(p); - } - } - if (!set.isEmpty()) { - this.protocols = set.toArray(new String[set.size()]); - } - if (!unset.isEmpty()) { - logger.log(Level.WARNING, "protocols " + unset + " is not supported, only support: " + Arrays.toString(protocolArray)); - } - } - if (!enabledCiphers.isEmpty()) { - HashSet set = new HashSet<>(); - HashSet unset = new HashSet<>(); - String[] cipherArray = sslContext.getSupportedSSLParameters().getCipherSuites(); - for (String c : enabledCiphers.split(",")) { - if (Utility.contains(cipherArray, c)) { - set.add(c); - } else { - unset.add(c); - } - } - if (!set.isEmpty()) { - this.ciphers = set.toArray(new String[set.size()]); - } - if (!unset.isEmpty()) { - logger.log(Level.WARNING, "cipherSuites " + unset + " is not supported, only support: " + Arrays.toString(cipherArray)); - } - } - return sslContext; - } - - public SSLEngine createSSLEngine(SSLContext sslContext, boolean client) { - SSLEngine engine = sslContext.createSSLEngine(); - if (protocols != null) { - engine.setEnabledProtocols(protocols); - } - if (ciphers != null) { - engine.setEnabledCipherSuites(ciphers); - } - engine.setUseClientMode(client); - if (wantClientAuth) { - engine.setWantClientAuth(true); - } else if (needClientAuth) { - engine.setNeedClientAuth(true); - } - return engine; - } -} +/* + * 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; + +import java.io.*; +import java.security.*; +import java.security.cert.*; +import java.util.*; +import java.util.logging.*; +import javax.net.ssl.*; +import org.redkale.util.*; + +/** + * 鏍规嵁閰嶇疆鐢熸垚SSLContext + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public class SSLBuilder { + + protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); + + protected String[] ciphers; + + protected String[] protocols; + + protected boolean wantClientAuth; + + protected boolean needClientAuth; + + public SSLContext createSSLContext(Server server, AnyValue sslConf) throws Exception { + String protocol = sslConf.getValue("protocol", "TLS"); + String clientauth = sslConf.getValue("clientAuth", "none"); + String sslProviderImpl = sslConf.getValue("sslProvider"); + String jsseProviderImpl = sslConf.getValue("jsseProvider"); + String enabledProtocols = sslConf.getValue("protocols", "").replaceAll("\\s+", "") + .replace(';', ',').replace(':', ',').replaceAll(",+", ",").replaceAll(",$", ""); + String enabledCiphers = sslConf.getValue("ciphers", "").replaceAll("\\s+", "") + .replace(';', ',').replace(':', ',').replaceAll(",+", ",").replaceAll(",$", ""); + + String keyfile = sslConf.getValue("keystoreFile"); + String keypass = sslConf.getValue("keystorePass", ""); + String keyType = sslConf.getValue("keystoreType", "JKS"); + String keyAlgorithm = sslConf.getValue("keystoreAlgorithm", "SunX509"); + + String trustfile = sslConf.getValue("truststoreFile"); + String trustpass = sslConf.getValue("truststorePass", ""); + String trustType = sslConf.getValue("truststoreType", "JKS"); + String trustAlgorithm = sslConf.getValue("truststoreAlgorithm", "SunX509"); + + Provider sslProvider = null; + Provider jsseProvider = null; + if (sslProviderImpl != null) { + Class providerClass = (Class) Thread.currentThread().getContextClassLoader().loadClass(sslProviderImpl); + sslProvider = providerClass.getConstructor().newInstance(); + } + if (jsseProviderImpl != null) { + Class providerClass = (Class) Thread.currentThread().getContextClassLoader().loadClass(jsseProviderImpl); + jsseProvider = providerClass.getConstructor().newInstance(); + } + + KeyManager[] keyManagers = null; + if (keyfile != null) { + KeyManagerFactory kmf = jsseProvider == null ? KeyManagerFactory.getInstance(keyAlgorithm) : KeyManagerFactory.getInstance(keyAlgorithm, jsseProvider); + KeyStore ks = jsseProvider == null ? KeyStore.getInstance(keyType) : KeyStore.getInstance(keyType, jsseProvider); + ks.load(new FileInputStream(keyfile), keypass.toCharArray()); + kmf.init(ks, keypass.toCharArray()); + keyManagers = kmf.getKeyManagers(); + } + + if ("WANT".equalsIgnoreCase(clientauth)) { + this.wantClientAuth = true; + } else if ("NEED".equalsIgnoreCase(clientauth)) { + this.needClientAuth = true; + } + + TrustManager[] trustManagers; + if (trustfile != null) { + KeyStore ts = jsseProvider == null ? KeyStore.getInstance(trustType) : KeyStore.getInstance(trustType, jsseProvider); + ts.load(new FileInputStream(trustfile), trustpass.toCharArray()); + TrustManagerFactory tmf = jsseProvider == null ? TrustManagerFactory.getInstance(trustAlgorithm) : TrustManagerFactory.getInstance(trustAlgorithm, jsseProvider); + tmf.init(ts); + trustManagers = tmf.getTrustManagers(); + } else { + trustManagers = new TrustManager[]{new X509TrustManager() { + @Override + public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { + } + + @Override + public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; + } + }}; + } + + SSLContext sslContext; + if (sslProvider == null) { + sslContext = SSLContext.getInstance(protocol); + } else { + sslContext = SSLContext.getInstance(protocol, sslProvider); + } + sslContext.init(keyManagers, trustManagers, new SecureRandom()); + if (!enabledProtocols.isEmpty()) { + HashSet set = new HashSet<>(); + HashSet unset = new HashSet<>(); + String[] protocolArray = sslContext.getSupportedSSLParameters().getProtocols(); + for (String p : enabledProtocols.split(",")) { + if (Utility.contains(protocolArray, p)) { + set.add(p); + } else { + unset.add(p); + } + } + if (!set.isEmpty()) { + this.protocols = set.toArray(new String[set.size()]); + } + if (!unset.isEmpty()) { + logger.log(Level.WARNING, "protocols " + unset + " is not supported, only support: " + Arrays.toString(protocolArray)); + } + } + if (!enabledCiphers.isEmpty()) { + HashSet set = new HashSet<>(); + HashSet unset = new HashSet<>(); + String[] cipherArray = sslContext.getSupportedSSLParameters().getCipherSuites(); + for (String c : enabledCiphers.split(",")) { + if (Utility.contains(cipherArray, c)) { + set.add(c); + } else { + unset.add(c); + } + } + if (!set.isEmpty()) { + this.ciphers = set.toArray(new String[set.size()]); + } + if (!unset.isEmpty()) { + logger.log(Level.WARNING, "cipherSuites " + unset + " is not supported, only support: " + Arrays.toString(cipherArray)); + } + } + return sslContext; + } + + public SSLEngine createSSLEngine(SSLContext sslContext, boolean client) { + SSLEngine engine = sslContext.createSSLEngine(); + if (protocols != null) { + engine.setEnabledProtocols(protocols); + } + if (ciphers != null) { + engine.setEnabledCipherSuites(ciphers); + } + engine.setUseClientMode(client); + if (wantClientAuth) { + engine.setWantClientAuth(true); + } else if (needClientAuth) { + engine.setNeedClientAuth(true); + } + return engine; + } +} diff --git a/src/main/java/org/redkale/net/Server.java b/src/main/java/org/redkale/net/Server.java index 85ce99881..b74710247 100644 --- a/src/main/java/org/redkale/net/Server.java +++ b/src/main/java/org/redkale/net/Server.java @@ -1,503 +1,503 @@ -/* - * 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; - -import java.io.*; -import java.net.*; -import java.nio.ByteBuffer; -import java.nio.charset.Charset; -import java.util.*; -import java.util.concurrent.atomic.*; -import java.util.logging.*; -import javax.net.ssl.*; -import org.redkale.boot.Application; -import org.redkale.util.*; - -/** - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param 璇锋眰ID鐨勬暟鎹被鍨嬶紝 渚嬪HTTP鍗忚璇锋眰鏍囪瘑涓簎rl锛岃姹侷D鐨勬暟鎹被鍨嬪氨鏄疭tring - * @param Context - * @param Request - * @param

Response - * @param Servlet - */ -public abstract class Server, P extends Response, S extends Servlet> { - - public static final String RESNAME_SERVER_ROOT = "SERVER_ROOT"; - - //@Deprecated //@deprecated 2.3.0 浣跨敤RESNAME_APP_EXECUTOR - //public static final String RESNAME_SERVER_EXECUTOR2 = "SERVER_EXECUTOR"; - public static final String RESNAME_SERVER_RESFACTORY = "SERVER_RESFACTORY"; - - protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); - - //------------------------------------------------------------- - //Application - protected Application application; - - //鏈嶅姟鐨勫惎鍔ㄦ椂闂 - protected final long serverStartTime; - - //鏈嶅姟鐨勫悕绉 - protected String name; - - //搴旂敤灞傚崗璁悕 - protected final String netprotocol; - - //渚濊禆娉ㄥ叆宸ュ巶绫 - protected final ResourceFactory resourceFactory; - - //鏈嶅姟鐨勬牴Servlet - protected final PrepareServlet prepare; - - //ClassLoader - protected RedkaleClassLoader serverClassLoader; - - //SSL - protected SSLBuilder sslBuilder; - - //SSL - protected SSLContext sslContext; - - //鏈嶅姟鐨勪笂涓嬫枃瀵硅薄 - protected C context; - - //鏈嶅姟鐨勯厤缃俊鎭 - protected AnyValue config; - - //鏈嶅姟鏁版嵁鐨勭紪瑙g爜锛宯ull瑙嗕负UTF-8 - protected Charset charset; - - //鏈嶅姟鐨勭洃鍚鍙 - protected InetSocketAddress address; - - //杩炴帴闃熷垪澶у皬 - protected int backlog; - - //浼犺緭灞傚崗璁殑鏈嶅姟 - protected ProtocolServer serverChannel; - - //ByteBuffer鐨勫閲忓ぇ灏 - protected int bufferCapacity; - - //ByteBuffer姹犲ぇ灏 - protected int bufferPoolSize; - - //Response姹犲ぇ灏 - protected int responsePoolSize; - - //鏈澶ц繛鎺ユ暟, 涓0琛ㄧず娌¢檺鍒 - protected int maxconns; - - //璇锋眰鍖呭ぇ灏忕殑涓婇檺锛屽崟浣:瀛楄妭 - protected int maxbody; - - //Keep-Alive IO璇诲彇鐨勮秴鏃剁鏁帮紝灏忎簬1瑙嗕负涓嶈缃 - protected int aliveTimeoutSeconds; - - //IO璇诲彇鐨勮秴鏃剁鏁帮紝灏忎簬1瑙嗕负涓嶈缃 - protected int readTimeoutSeconds; - - //IO鍐欏叆 鐨勮秴鏃剁鏁帮紝灏忎簬1瑙嗕负涓嶈缃 - protected int writeTimeoutSeconds; - - protected Server(Application application, long serverStartTime, String netprotocol, ResourceFactory resourceFactory, PrepareServlet servlet) { - this.application = application; - this.serverStartTime = serverStartTime; - this.netprotocol = netprotocol; - this.resourceFactory = resourceFactory; - this.prepare = servlet; - this.prepare.application = application; - } - - public void init(final AnyValue config) throws Exception { - Objects.requireNonNull(config); - this.config = config; - this.address = new InetSocketAddress(config.getValue("host", "0.0.0.0"), config.getIntValue("port", 80)); - this.charset = Charset.forName(config.getValue("charset", "UTF-8")); - this.maxconns = config.getIntValue("maxconns", 0); - this.aliveTimeoutSeconds = config.getIntValue("aliveTimeoutSeconds", 30); - this.readTimeoutSeconds = config.getIntValue("readTimeoutSeconds", 0); - this.writeTimeoutSeconds = config.getIntValue("writeTimeoutSeconds", 0); - this.backlog = parseLenth(config.getValue("backlog"), 1024); - this.maxbody = parseLenth(config.getValue("maxbody"), 64 * 1024); - int bufCapacity = parseLenth(config.getValue("bufferCapacity"), "UDP".equalsIgnoreCase(netprotocol) ? 1350 : 32 * 1024); - this.bufferCapacity = "UDP".equalsIgnoreCase(netprotocol) ? bufCapacity : (bufCapacity < 1024 ? 1024 : bufCapacity); - this.bufferPoolSize = config.getIntValue("bufferPoolSize", Utility.cpus() * 8); - this.responsePoolSize = config.getIntValue("responsePoolSize", 1024); - this.name = config.getValue("name", "Server-" + config.getValue("protocol", netprotocol).replaceFirst("\\..+", "").toUpperCase() + "-" + this.address.getPort()); - if (!this.name.matches("^[a-zA-Z][\\w_-]{1,64}$")) throw new RuntimeException("server.name (" + this.name + ") is illegal"); - AnyValue sslConf = config.getAnyValue("ssl"); - if (sslConf != null) { - String builderClass = sslConf.getValue("builder", SSLBuilder.class.getName()); - SSLBuilder builder = null; - if (SSLBuilder.class.getName().equals(builderClass) || builderClass.isEmpty()) { - builder = new SSLBuilder(); - } else { - ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); - Class clazz = classLoader.loadClass(builderClass); - RedkaleClassLoader.putReflectionDeclaredConstructors(clazz, clazz.getName()); - builder = ((SSLBuilder) classLoader.loadClass(builderClass).getDeclaredConstructor().newInstance()); - } - this.resourceFactory.inject(builder); - SSLContext sslc = builder.createSSLContext(this, sslConf); - if (sslc != null) { - this.sslBuilder = builder; - this.sslContext = sslc; - final boolean dtls = sslc.getProtocol().toUpperCase().startsWith("DTLS"); - //SSL妯″紡涓嬶紝 size蹇呴』澶т簬 5+16+16384+256+48+(isDTLS?0:16384) = 16k*1/2+325 = 16709/33093 瑙: sun.security.ssl.SSLRecord.maxLargeRecordSize - int maxLen = dtls ? 16709 : 33093; - if (maxLen > this.bufferCapacity) { - final String threadName = "[" + Thread.currentThread().getName() + "] "; - int newLen = dtls ? (17 * 1024) : (33 * 1024); //鍙栦釜1024鐨勬暣鍊嶆暟 - logger.info(threadName + this.getClass().getSimpleName() + " change bufferCapacity " + this.bufferCapacity + " to " + newLen + " for SSL size " + maxLen); - this.bufferCapacity = newLen; - } - } - } - this.context = this.createContext(); - } - - protected static int parseLenth(String value, int defValue) { - return (int) parseLenth(value, defValue + 0L); - } - - protected static long parseLenth(String value, long defValue) { - if (value == null) return defValue; - value = value.toUpperCase().replace("B", ""); - if (value.endsWith("G")) return Long.decode(value.replace("G", "")) * 1024 * 1024 * 1024; - if (value.endsWith("M")) return Long.decode(value.replace("M", "")) * 1024 * 1024; - if (value.endsWith("K")) return Long.decode(value.replace("K", "")) * 1024; - return Long.decode(value); - } - - protected static String formatLenth(long value) { - if (value < 1) return "" + value; - if (value % (1024 * 1024 * 1024) == 0) return value / (1024 * 1024 * 1024) + "G"; - if (value % (1024 * 1024) == 0) return value / (1024 * 1024) + "M"; - if (value % 1024 == 0) return value / (1024) + "K"; - return value + "B"; - } - - public void destroy(final AnyValue config) throws Exception { - this.prepare.destroy(context, config); - } - - public ResourceFactory getResourceFactory() { - return resourceFactory; - } - - public InetSocketAddress getSocketAddress() { - return address; - } - - public String getName() { - return name; - } - - public String getNetprotocol() { - return netprotocol; - } - - public Logger getLogger() { - return this.logger; - } - - public PrepareServlet getPrepareServlet() { - return this.prepare; - } - - public C getContext() { - return this.context; - } - - public long getServerStartTime() { - return serverStartTime; - } - - public Charset getCharset() { - return charset; - } - - public int getBacklog() { - return backlog; - } - - public int getBufferCapacity() { - return bufferCapacity; - } - - public int getBufferPoolSize() { - return bufferPoolSize; - } - - public int getResponsePoolSize() { - return responsePoolSize; - } - - public int getMaxbody() { - return maxbody; - } - - public int getAliveTimeoutSeconds() { - return aliveTimeoutSeconds; - } - - public int getReadTimeoutSeconds() { - return readTimeoutSeconds; - } - - public int getWriteTimeoutSeconds() { - return writeTimeoutSeconds; - } - - public int getMaxconns() { - return maxconns; - } - - @SuppressWarnings("unchecked") - public void addServlet(S servlet, final Object attachment, AnyValue conf, K... mappings) { - this.prepare.addServlet(servlet, attachment, conf, mappings); - } - - public void start() throws IOException { - this.prepare.init(this.context, config); //涓嶈兘鍦╥nit鏂规硶鍐呮墽琛岋紝鍥燬erver.init鎵ц鍚庝細璋冪敤loadService,loadServlet, 鍐嶆墽琛孲erver.start - this.serverChannel = ProtocolServer.create(this.netprotocol, context, this.serverClassLoader); - if (application != null) { //main鍑芥暟璋冭瘯鏃跺彲鑳戒负nulli - application.getResourceFactory().inject(this.serverChannel); - } - this.serverChannel.open(config); - serverChannel.bind(address, backlog); - serverChannel.accept(application, this); - final String threadName = "[" + Thread.currentThread().getName() + "] "; - postStart(); - logger.info(threadName + this.getClass().getSimpleName() + ("TCP".equalsIgnoreCase(netprotocol) ? "" : ("." + netprotocol)) + " listen: " + (address.getHostString() + ":" + address.getPort()) - + ", cpu: " + Utility.cpus() + ", responsePoolSize: " + responsePoolSize + ", bufferPoolSize: " + bufferPoolSize - + ", bufferCapacity: " + formatLenth(bufferCapacity) + ", maxbody: " + formatLenth(context.maxbody) - + ", started in " + (System.currentTimeMillis() - context.getServerStartTime()) + " ms"); - } - - protected void postStart() { - } - - public void changeAddress(Application application, final InetSocketAddress addr) throws IOException { - long s = System.currentTimeMillis(); - Objects.requireNonNull(addr); - final InetSocketAddress oldAddress = context.address; - final ProtocolServer oldServerChannel = this.serverChannel; - context.address = addr; - ProtocolServer newServerChannel = null; - try { - newServerChannel = ProtocolServer.create(this.netprotocol, context, this.serverClassLoader); - newServerChannel.open(config); - newServerChannel.bind(addr, backlog); - newServerChannel.accept(application, this); - } catch (IOException e) { - context.address = oldAddress; - throw e; - } - this.address = context.address; - this.serverChannel = newServerChannel; - final String threadName = "[" + Thread.currentThread().getName() + "] "; - logger.info(threadName + this.getClass().getSimpleName() + ("TCP".equalsIgnoreCase(netprotocol) ? "" : ("." + netprotocol)) - + " change address listen: " + address + ", started in " + (System.currentTimeMillis() - s) + " ms"); - if (oldServerChannel != null) { - new Thread() { - - @Override - public void run() { - try { - Thread.sleep(10_000); - oldServerChannel.close(); - } catch (Exception e) { - logger.log(Level.WARNING, "Server.changeInetSocketAddress(addr=" + addr + ") error", e); - } - } - }.start(); - } - } - - public void changeMaxconns(final int newmaxconns) { - this.maxconns = newmaxconns; - if (this.context != null) this.context.maxconns = newmaxconns; - if (this.serverChannel != null) this.serverChannel.maxconns = newmaxconns; - } - - public void changeCharset(final Charset newcharset) { - this.charset = newcharset; - if (this.context != null) this.context.charset = newcharset; - } - - public void changeMaxbody(final int newmaxbody) { - this.maxbody = newmaxbody; - if (this.context != null) this.context.maxbody = newmaxbody; - } - - public void changeReadTimeoutSeconds(final int newReadTimeoutSeconds) { - this.readTimeoutSeconds = newReadTimeoutSeconds; - if (this.context != null) this.context.readTimeoutSeconds = newReadTimeoutSeconds; - } - - public void changeWriteTimeoutSeconds(final int newWriteTimeoutSeconds) { - this.writeTimeoutSeconds = newWriteTimeoutSeconds; - if (this.context != null) this.context.writeTimeoutSeconds = newWriteTimeoutSeconds; - } - - public void changeAliveTimeoutSeconds(final int newAliveTimeoutSeconds) { - this.aliveTimeoutSeconds = newAliveTimeoutSeconds; - if (this.context != null) this.context.aliveTimeoutSeconds = newAliveTimeoutSeconds; - } - - protected abstract C createContext(); - - protected void initContextConfig(Context.ContextConfig contextConfig) { - if (application != null) contextConfig.workExecutor = application.getWorkExecutor(); - contextConfig.serverStartTime = this.serverStartTime; - contextConfig.logger = this.logger; - contextConfig.sslBuilder = this.sslBuilder; - contextConfig.sslContext = this.sslContext; - contextConfig.bufferCapacity = this.bufferCapacity; - contextConfig.maxconns = this.maxconns; - contextConfig.maxbody = this.maxbody; - contextConfig.charset = this.charset; - contextConfig.address = this.address; - contextConfig.prepare = this.prepare; - contextConfig.resourceFactory = this.resourceFactory; - contextConfig.aliveTimeoutSeconds = this.aliveTimeoutSeconds; - contextConfig.readTimeoutSeconds = this.readTimeoutSeconds; - contextConfig.writeTimeoutSeconds = this.writeTimeoutSeconds; - } - - //蹇呴』鍦 createContext()涔嬪悗璋冪敤 - protected abstract ObjectPool createBufferPool(LongAdder createCounter, LongAdder cycleCounter, int bufferPoolSize); - - //蹇呴』鍦 createContext()涔嬪悗璋冪敤 - protected abstract ObjectPool createResponsePool(LongAdder createCounter, LongAdder cycleCounter, int responsePoolSize); - - public void shutdown() throws IOException { - long s = System.currentTimeMillis(); - logger.info(this.getClass().getSimpleName() + "-" + this.netprotocol + " shutdowning"); - try { - this.serverChannel.close(); - } catch (Exception e) { - } - logger.info(this.getClass().getSimpleName() + "-" + this.netprotocol + " shutdow prepare servlet"); - this.prepare.destroy(this.context, config); - long e = System.currentTimeMillis() - s; - logger.info(this.getClass().getSimpleName() + "-" + this.netprotocol + " shutdown in " + e + " ms"); - } - - public RedkaleClassLoader getServerClassLoader() { - return serverClassLoader; - } - - public void setServerClassLoader(RedkaleClassLoader serverClassLoader) { - this.serverClassLoader = serverClassLoader; - } - - /** - * 鍒ゆ柇鏄惁瀛樺湪Filter - * - * @param 娉涘瀷 - * @param filterClass Filter绫 - * - * @return boolean - */ - public boolean containsFilter(Class filterClass) { - return this.prepare.containsFilter(filterClass); - } - - /** - * 鍒ゆ柇鏄惁瀛樺湪Filter - * - * @param 娉涘瀷 - * @param filterClassName Filter绫 - * - * @return boolean - */ - public boolean containsFilter(String filterClassName) { - return this.prepare.containsFilter(filterClassName); - } - - /** - * 鍒ゆ柇鏄惁瀛樺湪Servlet - * - * @param servletClass Servlet绫 - * - * @return boolean - */ - public boolean containsServlet(Class servletClass) { - return this.prepare.containsServlet(servletClass); - } - - /** - * 鍒ゆ柇鏄惁瀛樺湪Servlet - * - * @param servletClassName Servlet绫 - * - * @return boolean - */ - public boolean containsServlet(String servletClassName) { - return this.prepare.containsServlet(servletClassName); - } - - /** - * 閿姣丼ervlet - * - * @param servlet Servlet - */ - public void destroyServlet(S servlet) { - servlet.destroy(context, this.prepare.getServletConf(servlet)); - } - - //鍒涘缓鏁 - public long getCreateConnectionCount() { - return serverChannel == null ? -1 : serverChannel.getCreateConnectionCount(); - } - - //鍏抽棴鏁 - public long getClosedConnectionCount() { - return serverChannel == null ? -1 : serverChannel.getClosedConnectionCount(); - } - - //鍦ㄧ嚎鏁 - public long getLivingConnectionCount() { - return serverChannel == null ? -1 : serverChannel.getLivingConnectionCount(); - } - - public static URL[] loadLib(final RedkaleClassLoader classLoader, final Logger logger, final String lib) throws Exception { - if (lib == null || lib.isEmpty()) return new URL[0]; - final Set set = new HashSet<>(); - for (String s : lib.split(";")) { - if (s.isEmpty()) continue; - if (s.endsWith("*")) { - File root = new File(s.substring(0, s.length() - 1)); - if (root.isDirectory()) { - File[] lfs = root.listFiles(); - if (lfs == null) throw new RuntimeException("File(" + root + ") cannot listFiles()"); - for (File f : lfs) { - set.add(f.toURI().toURL()); - } - } - } else { - File f = new File(s); - if (f.canRead()) set.add(f.toURI().toURL()); - } - } - if (set.isEmpty()) return new URL[0]; - for (URL url : set) { - classLoader.addURL(url); - } - List list = new ArrayList<>(set); - list.sort((URL o1, URL o2) -> o1.getFile().compareTo(o2.getFile())); - return list.toArray(new URL[list.size()]); - } - -} +/* + * 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; + +import java.io.*; +import java.net.*; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.util.*; +import java.util.concurrent.atomic.*; +import java.util.logging.*; +import javax.net.ssl.*; +import org.redkale.boot.Application; +import org.redkale.util.*; + +/** + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param 璇锋眰ID鐨勬暟鎹被鍨嬶紝 渚嬪HTTP鍗忚璇锋眰鏍囪瘑涓簎rl锛岃姹侷D鐨勬暟鎹被鍨嬪氨鏄疭tring + * @param Context + * @param Request + * @param

Response + * @param Servlet + */ +public abstract class Server, P extends Response, S extends Servlet> { + + public static final String RESNAME_SERVER_ROOT = "SERVER_ROOT"; + + //@Deprecated //@deprecated 2.3.0 浣跨敤RESNAME_APP_EXECUTOR + //public static final String RESNAME_SERVER_EXECUTOR2 = "SERVER_EXECUTOR"; + public static final String RESNAME_SERVER_RESFACTORY = "SERVER_RESFACTORY"; + + protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); + + //------------------------------------------------------------- + //Application + protected Application application; + + //鏈嶅姟鐨勫惎鍔ㄦ椂闂 + protected final long serverStartTime; + + //鏈嶅姟鐨勫悕绉 + protected String name; + + //搴旂敤灞傚崗璁悕 + protected final String netprotocol; + + //渚濊禆娉ㄥ叆宸ュ巶绫 + protected final ResourceFactory resourceFactory; + + //鏈嶅姟鐨勬牴Servlet + protected final PrepareServlet prepare; + + //ClassLoader + protected RedkaleClassLoader serverClassLoader; + + //SSL + protected SSLBuilder sslBuilder; + + //SSL + protected SSLContext sslContext; + + //鏈嶅姟鐨勪笂涓嬫枃瀵硅薄 + protected C context; + + //鏈嶅姟鐨勯厤缃俊鎭 + protected AnyValue config; + + //鏈嶅姟鏁版嵁鐨勭紪瑙g爜锛宯ull瑙嗕负UTF-8 + protected Charset charset; + + //鏈嶅姟鐨勭洃鍚鍙 + protected InetSocketAddress address; + + //杩炴帴闃熷垪澶у皬 + protected int backlog; + + //浼犺緭灞傚崗璁殑鏈嶅姟 + protected ProtocolServer serverChannel; + + //ByteBuffer鐨勫閲忓ぇ灏 + protected int bufferCapacity; + + //ByteBuffer姹犲ぇ灏 + protected int bufferPoolSize; + + //Response姹犲ぇ灏 + protected int responsePoolSize; + + //鏈澶ц繛鎺ユ暟, 涓0琛ㄧず娌¢檺鍒 + protected int maxconns; + + //璇锋眰鍖呭ぇ灏忕殑涓婇檺锛屽崟浣:瀛楄妭 + protected int maxbody; + + //Keep-Alive IO璇诲彇鐨勮秴鏃剁鏁帮紝灏忎簬1瑙嗕负涓嶈缃 + protected int aliveTimeoutSeconds; + + //IO璇诲彇鐨勮秴鏃剁鏁帮紝灏忎簬1瑙嗕负涓嶈缃 + protected int readTimeoutSeconds; + + //IO鍐欏叆 鐨勮秴鏃剁鏁帮紝灏忎簬1瑙嗕负涓嶈缃 + protected int writeTimeoutSeconds; + + protected Server(Application application, long serverStartTime, String netprotocol, ResourceFactory resourceFactory, PrepareServlet servlet) { + this.application = application; + this.serverStartTime = serverStartTime; + this.netprotocol = netprotocol; + this.resourceFactory = resourceFactory; + this.prepare = servlet; + this.prepare.application = application; + } + + public void init(final AnyValue config) throws Exception { + Objects.requireNonNull(config); + this.config = config; + this.address = new InetSocketAddress(config.getValue("host", "0.0.0.0"), config.getIntValue("port", 80)); + this.charset = Charset.forName(config.getValue("charset", "UTF-8")); + this.maxconns = config.getIntValue("maxconns", 0); + this.aliveTimeoutSeconds = config.getIntValue("aliveTimeoutSeconds", 30); + this.readTimeoutSeconds = config.getIntValue("readTimeoutSeconds", 0); + this.writeTimeoutSeconds = config.getIntValue("writeTimeoutSeconds", 0); + this.backlog = parseLenth(config.getValue("backlog"), 1024); + this.maxbody = parseLenth(config.getValue("maxbody"), 64 * 1024); + int bufCapacity = parseLenth(config.getValue("bufferCapacity"), "UDP".equalsIgnoreCase(netprotocol) ? 1350 : 32 * 1024); + this.bufferCapacity = "UDP".equalsIgnoreCase(netprotocol) ? bufCapacity : (bufCapacity < 1024 ? 1024 : bufCapacity); + this.bufferPoolSize = config.getIntValue("bufferPoolSize", Utility.cpus() * 8); + this.responsePoolSize = config.getIntValue("responsePoolSize", 1024); + this.name = config.getValue("name", "Server-" + config.getValue("protocol", netprotocol).replaceFirst("\\..+", "").toUpperCase() + "-" + this.address.getPort()); + if (!this.name.matches("^[a-zA-Z][\\w_-]{1,64}$")) throw new RuntimeException("server.name (" + this.name + ") is illegal"); + AnyValue sslConf = config.getAnyValue("ssl"); + if (sslConf != null) { + String builderClass = sslConf.getValue("builder", SSLBuilder.class.getName()); + SSLBuilder builder = null; + if (SSLBuilder.class.getName().equals(builderClass) || builderClass.isEmpty()) { + builder = new SSLBuilder(); + } else { + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + Class clazz = classLoader.loadClass(builderClass); + RedkaleClassLoader.putReflectionDeclaredConstructors(clazz, clazz.getName()); + builder = ((SSLBuilder) classLoader.loadClass(builderClass).getDeclaredConstructor().newInstance()); + } + this.resourceFactory.inject(builder); + SSLContext sslc = builder.createSSLContext(this, sslConf); + if (sslc != null) { + this.sslBuilder = builder; + this.sslContext = sslc; + final boolean dtls = sslc.getProtocol().toUpperCase().startsWith("DTLS"); + //SSL妯″紡涓嬶紝 size蹇呴』澶т簬 5+16+16384+256+48+(isDTLS?0:16384) = 16k*1/2+325 = 16709/33093 瑙: sun.security.ssl.SSLRecord.maxLargeRecordSize + int maxLen = dtls ? 16709 : 33093; + if (maxLen > this.bufferCapacity) { + final String threadName = "[" + Thread.currentThread().getName() + "] "; + int newLen = dtls ? (17 * 1024) : (33 * 1024); //鍙栦釜1024鐨勬暣鍊嶆暟 + logger.info(threadName + this.getClass().getSimpleName() + " change bufferCapacity " + this.bufferCapacity + " to " + newLen + " for SSL size " + maxLen); + this.bufferCapacity = newLen; + } + } + } + this.context = this.createContext(); + } + + protected static int parseLenth(String value, int defValue) { + return (int) parseLenth(value, defValue + 0L); + } + + protected static long parseLenth(String value, long defValue) { + if (value == null) return defValue; + value = value.toUpperCase().replace("B", ""); + if (value.endsWith("G")) return Long.decode(value.replace("G", "")) * 1024 * 1024 * 1024; + if (value.endsWith("M")) return Long.decode(value.replace("M", "")) * 1024 * 1024; + if (value.endsWith("K")) return Long.decode(value.replace("K", "")) * 1024; + return Long.decode(value); + } + + protected static String formatLenth(long value) { + if (value < 1) return "" + value; + if (value % (1024 * 1024 * 1024) == 0) return value / (1024 * 1024 * 1024) + "G"; + if (value % (1024 * 1024) == 0) return value / (1024 * 1024) + "M"; + if (value % 1024 == 0) return value / (1024) + "K"; + return value + "B"; + } + + public void destroy(final AnyValue config) throws Exception { + this.prepare.destroy(context, config); + } + + public ResourceFactory getResourceFactory() { + return resourceFactory; + } + + public InetSocketAddress getSocketAddress() { + return address; + } + + public String getName() { + return name; + } + + public String getNetprotocol() { + return netprotocol; + } + + public Logger getLogger() { + return this.logger; + } + + public PrepareServlet getPrepareServlet() { + return this.prepare; + } + + public C getContext() { + return this.context; + } + + public long getServerStartTime() { + return serverStartTime; + } + + public Charset getCharset() { + return charset; + } + + public int getBacklog() { + return backlog; + } + + public int getBufferCapacity() { + return bufferCapacity; + } + + public int getBufferPoolSize() { + return bufferPoolSize; + } + + public int getResponsePoolSize() { + return responsePoolSize; + } + + public int getMaxbody() { + return maxbody; + } + + public int getAliveTimeoutSeconds() { + return aliveTimeoutSeconds; + } + + public int getReadTimeoutSeconds() { + return readTimeoutSeconds; + } + + public int getWriteTimeoutSeconds() { + return writeTimeoutSeconds; + } + + public int getMaxconns() { + return maxconns; + } + + @SuppressWarnings("unchecked") + public void addServlet(S servlet, final Object attachment, AnyValue conf, K... mappings) { + this.prepare.addServlet(servlet, attachment, conf, mappings); + } + + public void start() throws IOException { + this.prepare.init(this.context, config); //涓嶈兘鍦╥nit鏂规硶鍐呮墽琛岋紝鍥燬erver.init鎵ц鍚庝細璋冪敤loadService,loadServlet, 鍐嶆墽琛孲erver.start + this.serverChannel = ProtocolServer.create(this.netprotocol, context, this.serverClassLoader); + if (application != null) { //main鍑芥暟璋冭瘯鏃跺彲鑳戒负nulli + application.getResourceFactory().inject(this.serverChannel); + } + this.serverChannel.open(config); + serverChannel.bind(address, backlog); + serverChannel.accept(application, this); + final String threadName = "[" + Thread.currentThread().getName() + "] "; + postStart(); + logger.info(threadName + this.getClass().getSimpleName() + ("TCP".equalsIgnoreCase(netprotocol) ? "" : ("." + netprotocol)) + " listen: " + (address.getHostString() + ":" + address.getPort()) + + ", cpu: " + Utility.cpus() + ", responsePoolSize: " + responsePoolSize + ", bufferPoolSize: " + bufferPoolSize + + ", bufferCapacity: " + formatLenth(bufferCapacity) + ", maxbody: " + formatLenth(context.maxbody) + + ", started in " + (System.currentTimeMillis() - context.getServerStartTime()) + " ms"); + } + + protected void postStart() { + } + + public void changeAddress(Application application, final InetSocketAddress addr) throws IOException { + long s = System.currentTimeMillis(); + Objects.requireNonNull(addr); + final InetSocketAddress oldAddress = context.address; + final ProtocolServer oldServerChannel = this.serverChannel; + context.address = addr; + ProtocolServer newServerChannel = null; + try { + newServerChannel = ProtocolServer.create(this.netprotocol, context, this.serverClassLoader); + newServerChannel.open(config); + newServerChannel.bind(addr, backlog); + newServerChannel.accept(application, this); + } catch (IOException e) { + context.address = oldAddress; + throw e; + } + this.address = context.address; + this.serverChannel = newServerChannel; + final String threadName = "[" + Thread.currentThread().getName() + "] "; + logger.info(threadName + this.getClass().getSimpleName() + ("TCP".equalsIgnoreCase(netprotocol) ? "" : ("." + netprotocol)) + + " change address listen: " + address + ", started in " + (System.currentTimeMillis() - s) + " ms"); + if (oldServerChannel != null) { + new Thread() { + + @Override + public void run() { + try { + Thread.sleep(10_000); + oldServerChannel.close(); + } catch (Exception e) { + logger.log(Level.WARNING, "Server.changeInetSocketAddress(addr=" + addr + ") error", e); + } + } + }.start(); + } + } + + public void changeMaxconns(final int newmaxconns) { + this.maxconns = newmaxconns; + if (this.context != null) this.context.maxconns = newmaxconns; + if (this.serverChannel != null) this.serverChannel.maxconns = newmaxconns; + } + + public void changeCharset(final Charset newcharset) { + this.charset = newcharset; + if (this.context != null) this.context.charset = newcharset; + } + + public void changeMaxbody(final int newmaxbody) { + this.maxbody = newmaxbody; + if (this.context != null) this.context.maxbody = newmaxbody; + } + + public void changeReadTimeoutSeconds(final int newReadTimeoutSeconds) { + this.readTimeoutSeconds = newReadTimeoutSeconds; + if (this.context != null) this.context.readTimeoutSeconds = newReadTimeoutSeconds; + } + + public void changeWriteTimeoutSeconds(final int newWriteTimeoutSeconds) { + this.writeTimeoutSeconds = newWriteTimeoutSeconds; + if (this.context != null) this.context.writeTimeoutSeconds = newWriteTimeoutSeconds; + } + + public void changeAliveTimeoutSeconds(final int newAliveTimeoutSeconds) { + this.aliveTimeoutSeconds = newAliveTimeoutSeconds; + if (this.context != null) this.context.aliveTimeoutSeconds = newAliveTimeoutSeconds; + } + + protected abstract C createContext(); + + protected void initContextConfig(Context.ContextConfig contextConfig) { + if (application != null) contextConfig.workExecutor = application.getWorkExecutor(); + contextConfig.serverStartTime = this.serverStartTime; + contextConfig.logger = this.logger; + contextConfig.sslBuilder = this.sslBuilder; + contextConfig.sslContext = this.sslContext; + contextConfig.bufferCapacity = this.bufferCapacity; + contextConfig.maxconns = this.maxconns; + contextConfig.maxbody = this.maxbody; + contextConfig.charset = this.charset; + contextConfig.address = this.address; + contextConfig.prepare = this.prepare; + contextConfig.resourceFactory = this.resourceFactory; + contextConfig.aliveTimeoutSeconds = this.aliveTimeoutSeconds; + contextConfig.readTimeoutSeconds = this.readTimeoutSeconds; + contextConfig.writeTimeoutSeconds = this.writeTimeoutSeconds; + } + + //蹇呴』鍦 createContext()涔嬪悗璋冪敤 + protected abstract ObjectPool createBufferPool(LongAdder createCounter, LongAdder cycleCounter, int bufferPoolSize); + + //蹇呴』鍦 createContext()涔嬪悗璋冪敤 + protected abstract ObjectPool createResponsePool(LongAdder createCounter, LongAdder cycleCounter, int responsePoolSize); + + public void shutdown() throws IOException { + long s = System.currentTimeMillis(); + logger.info(this.getClass().getSimpleName() + "-" + this.netprotocol + " shutdowning"); + try { + this.serverChannel.close(); + } catch (Exception e) { + } + logger.info(this.getClass().getSimpleName() + "-" + this.netprotocol + " shutdow prepare servlet"); + this.prepare.destroy(this.context, config); + long e = System.currentTimeMillis() - s; + logger.info(this.getClass().getSimpleName() + "-" + this.netprotocol + " shutdown in " + e + " ms"); + } + + public RedkaleClassLoader getServerClassLoader() { + return serverClassLoader; + } + + public void setServerClassLoader(RedkaleClassLoader serverClassLoader) { + this.serverClassLoader = serverClassLoader; + } + + /** + * 鍒ゆ柇鏄惁瀛樺湪Filter + * + * @param 娉涘瀷 + * @param filterClass Filter绫 + * + * @return boolean + */ + public boolean containsFilter(Class filterClass) { + return this.prepare.containsFilter(filterClass); + } + + /** + * 鍒ゆ柇鏄惁瀛樺湪Filter + * + * @param 娉涘瀷 + * @param filterClassName Filter绫 + * + * @return boolean + */ + public boolean containsFilter(String filterClassName) { + return this.prepare.containsFilter(filterClassName); + } + + /** + * 鍒ゆ柇鏄惁瀛樺湪Servlet + * + * @param servletClass Servlet绫 + * + * @return boolean + */ + public boolean containsServlet(Class servletClass) { + return this.prepare.containsServlet(servletClass); + } + + /** + * 鍒ゆ柇鏄惁瀛樺湪Servlet + * + * @param servletClassName Servlet绫 + * + * @return boolean + */ + public boolean containsServlet(String servletClassName) { + return this.prepare.containsServlet(servletClassName); + } + + /** + * 閿姣丼ervlet + * + * @param servlet Servlet + */ + public void destroyServlet(S servlet) { + servlet.destroy(context, this.prepare.getServletConf(servlet)); + } + + //鍒涘缓鏁 + public long getCreateConnectionCount() { + return serverChannel == null ? -1 : serverChannel.getCreateConnectionCount(); + } + + //鍏抽棴鏁 + public long getClosedConnectionCount() { + return serverChannel == null ? -1 : serverChannel.getClosedConnectionCount(); + } + + //鍦ㄧ嚎鏁 + public long getLivingConnectionCount() { + return serverChannel == null ? -1 : serverChannel.getLivingConnectionCount(); + } + + public static URL[] loadLib(final RedkaleClassLoader classLoader, final Logger logger, final String lib) throws Exception { + if (lib == null || lib.isEmpty()) return new URL[0]; + final Set set = new HashSet<>(); + for (String s : lib.split(";")) { + if (s.isEmpty()) continue; + if (s.endsWith("*")) { + File root = new File(s.substring(0, s.length() - 1)); + if (root.isDirectory()) { + File[] lfs = root.listFiles(); + if (lfs == null) throw new RuntimeException("File(" + root + ") cannot listFiles()"); + for (File f : lfs) { + set.add(f.toURI().toURL()); + } + } + } else { + File f = new File(s); + if (f.canRead()) set.add(f.toURI().toURL()); + } + } + if (set.isEmpty()) return new URL[0]; + for (URL url : set) { + classLoader.addURL(url); + } + List list = new ArrayList<>(set); + list.sort((URL o1, URL o2) -> o1.getFile().compareTo(o2.getFile())); + return list.toArray(new URL[list.size()]); + } + +} diff --git a/src/main/java/org/redkale/net/Servlet.java b/src/main/java/org/redkale/net/Servlet.java index 175c73566..0efcf3537 100644 --- a/src/main/java/org/redkale/net/Servlet.java +++ b/src/main/java/org/redkale/net/Servlet.java @@ -1,36 +1,36 @@ -/* - * 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; - -import org.redkale.util.AnyValue; -import java.io.IOException; - -/** - * 鍗忚璇锋眰澶勭悊绫 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Context鐨勫瓙绫诲瀷 - * @param Request鐨勫瓙绫诲瀷 - * @param

Response鐨勫瓙绫诲瀷 - */ -public abstract class Servlet, P extends Response> { - - AnyValue _conf; //褰撳墠Servlet鐨勯厤缃 - - //Server鎵цstart鏃惰繍琛屾鏂规硶 - public void init(C context, AnyValue config) { - } - - public abstract void execute(R request, P response) throws IOException; - - //Server鎵цshutdown鍚庤繍琛屾鏂规硶 - public void destroy(C context, AnyValue config) { - } - -} +/* + * 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; + +import org.redkale.util.AnyValue; +import java.io.IOException; + +/** + * 鍗忚璇锋眰澶勭悊绫 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Context鐨勫瓙绫诲瀷 + * @param Request鐨勫瓙绫诲瀷 + * @param

Response鐨勫瓙绫诲瀷 + */ +public abstract class Servlet, P extends Response> { + + AnyValue _conf; //褰撳墠Servlet鐨勯厤缃 + + //Server鎵цstart鏃惰繍琛屾鏂规硶 + public void init(C context, AnyValue config) { + } + + public abstract void execute(R request, P response) throws IOException; + + //Server鎵цshutdown鍚庤繍琛屾鏂规硶 + public void destroy(C context, AnyValue config) { + } + +} diff --git a/src/main/java/org/redkale/net/Transport.java b/src/main/java/org/redkale/net/Transport.java index fd40674b4..d26ebfcdd 100644 --- a/src/main/java/org/redkale/net/Transport.java +++ b/src/main/java/org/redkale/net/Transport.java @@ -1,444 +1,444 @@ -/* - * 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; - -import java.io.IOException; -import java.lang.ref.WeakReference; -import java.net.*; -import java.nio.ByteBuffer; -import java.nio.channels.*; -import java.util.*; -import java.util.concurrent.*; -import java.util.concurrent.atomic.*; -import java.util.function.Supplier; -import java.util.logging.Level; -import javax.net.ssl.SSLContext; -import org.redkale.convert.*; -import org.redkale.convert.json.JsonConvert; -import org.redkale.util.*; - -/** - * 浼犺緭瀹㈡埛绔 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public final class Transport { - - public static final String DEFAULT_NETPROTOCOL = "TCP"; - - protected final AtomicInteger seq = new AtomicInteger(-1); - - protected final TransportFactory factory; - - protected final String name; //鍗鐨刵ame灞炴 - - protected final boolean tcp; - - protected final String netprotocol; - - //浼犺緭绔殑AsyncGroup - protected final AsyncGroup asyncGroup; - - protected final InetSocketAddress clientAddress; - - //涓嶅彲鑳戒负null - protected TransportNode[] transportNodes = new TransportNode[0]; - - protected final SSLContext sslContext; - - //璐熻浇鍧囪 绛栫暐 - protected final TransportStrategy strategy; - - //杩炴帴涓婇檺锛 涓簄ull琛ㄧず鏃犻檺鍒 - protected Semaphore semaphore; - - protected Transport(String name, TransportFactory factory, final AsyncGroup asyncGroup, final SSLContext sslContext, final InetSocketAddress clientAddress, - final Collection addresses, final TransportStrategy strategy) { - this(name, DEFAULT_NETPROTOCOL, factory, asyncGroup, sslContext, clientAddress, addresses, strategy); - } - - protected Transport(String name, String netprotocol, final TransportFactory factory, final AsyncGroup asyncGroup, final SSLContext sslContext, final InetSocketAddress clientAddress, - final Collection addresses, final TransportStrategy strategy) { - this.name = name; - this.netprotocol = netprotocol; - this.factory = factory; - factory.transportReferences.add(new WeakReference<>(this)); - this.tcp = "TCP".equalsIgnoreCase(netprotocol); - this.asyncGroup = asyncGroup; - this.sslContext = sslContext; - this.clientAddress = clientAddress; - this.strategy = strategy; - updateRemoteAddresses(addresses); - } - - public Semaphore getSemaphore() { - return semaphore; - } - - public void setSemaphore(Semaphore semaphore) { - this.semaphore = semaphore; - } - - public final InetSocketAddress[] updateRemoteAddresses(final Collection addresses) { - final TransportNode[] oldNodes = this.transportNodes; - synchronized (this) { - boolean same = false; - if (this.transportNodes != null && addresses != null && this.transportNodes.length == addresses.size()) { - same = true; - for (TransportNode node : this.transportNodes) { - if (!addresses.contains(node.getAddress())) { - same = false; - break; - } - } - } - if (!same) { - List list = new ArrayList<>(); - if (addresses != null) { - for (InetSocketAddress addr : addresses) { - if (clientAddress != null && clientAddress.equals(addr)) continue; - boolean hasold = false; - for (TransportNode oldAddr : oldNodes) { - if (oldAddr.getAddress().equals(addr)) { - list.add(oldAddr); - hasold = true; - break; - } - } - if (hasold) continue; - list.add(new TransportNode(factory.poolmaxconns, addr)); - } - } - this.transportNodes = list.toArray(new TransportNode[list.size()]); - } - } - InetSocketAddress[] rs = new InetSocketAddress[oldNodes.length]; - for (int i = 0; i < rs.length; i++) { - rs[i] = oldNodes[i].getAddress(); - } - return rs; - } - - public final boolean addRemoteAddresses(final InetSocketAddress addr) { - if (addr == null) return false; - if (clientAddress != null && clientAddress.equals(addr)) return false; - synchronized (this) { - if (this.transportNodes.length == 0) { - this.transportNodes = new TransportNode[]{new TransportNode(factory.poolmaxconns, addr)}; - } else { - for (TransportNode i : this.transportNodes) { - if (addr.equals(i.address)) return false; - } - this.transportNodes = Utility.append(transportNodes, new TransportNode(factory.poolmaxconns, addr)); - } - return true; - } - } - - public final boolean removeRemoteAddresses(InetSocketAddress addr) { - if (addr == null) return false; - synchronized (this) { - this.transportNodes = Utility.remove(transportNodes, new TransportNode(factory.poolmaxconns, addr)); - } - return true; - } - - public String getName() { - return name; - } - - public void close() { - TransportNode[] nodes = this.transportNodes; - if (nodes == null) return; - for (TransportNode node : nodes) { - if (node != null) node.dispose(); - } - } - - public InetSocketAddress getClientAddress() { - return clientAddress; - } - - public TransportNode[] getTransportNodes() { - return transportNodes; - } - - public TransportNode findTransportNode(SocketAddress addr) { - for (TransportNode node : this.transportNodes) { - if (node.address.equals(addr)) return node; - } - return null; - } - - public InetSocketAddress[] getRemoteAddresses() { - InetSocketAddress[] rs = new InetSocketAddress[transportNodes.length]; - for (int i = 0; i < rs.length; i++) { - rs[i] = transportNodes[i].getAddress(); - } - return rs; - } - - @Override - public String toString() { - return Transport.class.getSimpleName() + "{name = " + name + ", protocol = " + netprotocol + ", clientAddress = " + clientAddress + ", remoteNodes = " + Arrays.toString(transportNodes) + "}"; - } - - public String getNetprotocol() { - return netprotocol; - } - - public boolean isTCP() { - return tcp; - } - - protected CompletableFuture pollAsync(TransportNode node, SocketAddress addr, Supplier> func) { - final BlockingQueue queue = node.connQueue; - if (!queue.isEmpty()) { - AsyncConnection conn; - while ((conn = queue.poll()) != null) { - if (conn.isOpen()) { - return CompletableFuture.completedFuture(conn); - } else { - conn.dispose(); - } - } - } - if (semaphore != null && !semaphore.tryAcquire()) { - final CompletableFuture future = Utility.orTimeout(new CompletableFuture<>(), 10, TimeUnit.SECONDS); - future.whenComplete((r, t) -> node.pollQueue.remove(future)); - if (node.pollQueue.offer(future)) return future; - future.completeExceptionally(new IOException("create transport connection error")); - return future; - } - return func.get().thenApply(conn -> { - if (conn != null && semaphore != null) conn.beforeCloseListener((c) -> semaphore.release()); - return conn; - }); - } - - public CompletableFuture pollConnection(SocketAddress addr0) { - if (this.strategy != null) return strategy.pollConnection(addr0, this); - final TransportNode[] nodes = this.transportNodes; - if (addr0 == null && nodes.length == 1) addr0 = nodes[0].address; - final SocketAddress addr = addr0; - final boolean rand = addr == null; //鏄惁闅忔満鍙栧湴鍧 - if (rand && nodes.length < 1) throw new RuntimeException("Transport (" + this.name + ") have no remoteAddress list"); - try { - if (!tcp) { // UDP - SocketAddress udpaddr = rand ? nodes[0].address : addr; - return asyncGroup.createUDPClient(udpaddr, factory.readTimeoutSeconds, factory.writeTimeoutSeconds); - } - if (!rand) { //鎸囧畾鍦板潃 - TransportNode node = findTransportNode(addr); - if (node == null) return asyncGroup.createTCPClient(addr, factory.readTimeoutSeconds, factory.writeTimeoutSeconds); - return pollAsync(node, addr, () -> asyncGroup.createTCPClient(addr, factory.readTimeoutSeconds, factory.writeTimeoutSeconds)); - } - - //---------------------闅忔満鍙栧湴鍧------------------------ - int enablecount = 0; - final TransportNode[] newnodes = new TransportNode[nodes.length]; - for (final TransportNode node : nodes) { - if (node.disabletime > 0) continue; - newnodes[enablecount++] = node; - } - final long now = System.currentTimeMillis(); - if (enablecount > 0) { //瀛樺湪鍙敤鐨勫湴鍧 - final TransportNode one = newnodes[Math.abs(seq.incrementAndGet()) % enablecount]; - final BlockingQueue queue = one.connQueue; - if (!queue.isEmpty()) { - AsyncConnection conn; - while ((conn = queue.poll()) != null) { - if (conn.isOpen()) { - return CompletableFuture.completedFuture(conn); - } else { - conn.dispose(); - } - } - } - return pollAsync(one, one.getAddress(), () -> { - return asyncGroup.createTCPClient(one.address, factory.readTimeoutSeconds, factory.writeTimeoutSeconds) - .whenComplete((c, t) -> { - one.disabletime = t == null ? 0 : System.currentTimeMillis(); - }); - }); - } - return pollConnection0(nodes, null, now); - } catch (Exception ex) { - throw new RuntimeException("transport address = " + addr, ex); - } - } - - private CompletableFuture pollConnection0(TransportNode[] nodes, TransportNode exclude, long now) throws IOException { - //浠庡彲鐢/涓嶅彲鐢ㄧ殑鍦板潃鍒楄〃涓垱寤鸿繛鎺 - CompletableFuture future = new CompletableFuture(); - for (final TransportNode node : nodes) { - if (node == exclude) continue; - if (future.isDone()) return future; - asyncGroup.createTCPClient(node.address, factory.readTimeoutSeconds, factory.writeTimeoutSeconds) - .whenComplete((c, t) -> { - if (c != null && !future.complete(c)) node.connQueue.offer(c); - node.disabletime = t == null ? 0 : System.currentTimeMillis(); - }); - } - return future; - } - - public void offerConnection(final boolean forceClose, AsyncConnection conn) { - if (this.strategy != null && strategy.offerConnection(forceClose, conn)) return; - if (!forceClose && conn.isTCP()) { - if (conn.isOpen()) { - TransportNode node = findTransportNode(conn.getRemoteAddress()); - if (node == null || !node.connQueue.offer(conn)) conn.dispose(); - } else { - conn.dispose(); - } - } else { - conn.dispose(); - } - } - - public void async(SocketAddress addr, final ByteBuffer buffer, A att, final CompletionHandler handler) { - pollConnection(addr).whenComplete((conn, ex) -> { - if (ex != null) { - factory.getLogger().log(Level.WARNING, Transport.class.getSimpleName() + " async error", ex); - return; - } - conn.write(buffer, buffer, new CompletionHandler() { - - @Override - public void completed(Integer result, ByteBuffer attachment) { - buffer.clear(); - conn.setReadBuffer(buffer); - conn.read(new CompletionHandler() { - - @Override - public void completed(Integer result, ByteBuffer attachment) { - if (handler != null) handler.completed(result, att); - conn.offerBuffer(attachment); - offerConnection(false, conn); - } - - @Override - public void failed(Throwable exc, ByteBuffer attachment) { - conn.offerBuffer(attachment); - offerConnection(true, conn); - } - }); - - } - - @Override - public void failed(Throwable exc, ByteBuffer attachment) { - conn.offerBuffer(attachment); - offerConnection(true, conn); - } - }); - }); - } - - public static class TransportNode { - - protected InetSocketAddress address; - - protected volatile long disabletime; //涓嶅彲鐢ㄦ椂鐨勬椂闂, 涓0琛ㄧず鍙敤 - - protected final BlockingQueue connQueue; - - protected final ArrayBlockingQueue> pollQueue; - - protected final ConcurrentHashMap attributes = new ConcurrentHashMap<>(); - - public TransportNode(int poolmaxconns, InetSocketAddress address) { - this.address = address; - this.disabletime = 0; - this.connQueue = new ArrayBlockingQueue<>(poolmaxconns); - this.pollQueue = new ArrayBlockingQueue(this.connQueue.remainingCapacity() * 100); - } - - @ConstructorParameters({"poolmaxconns", "address", "disabletime"}) - public TransportNode(int poolmaxconns, InetSocketAddress address, long disabletime) { - this.address = address; - this.disabletime = disabletime; - this.connQueue = new LinkedBlockingQueue<>(poolmaxconns); - this.pollQueue = new ArrayBlockingQueue(this.connQueue.remainingCapacity() * 100); - } - - public int getPoolmaxconns() { - return this.connQueue.remainingCapacity() + this.connQueue.size(); - } - - public T setAttribute(String name, T value) { - attributes.put(name, value); - return value; - } - - @SuppressWarnings("unchecked") - public T getAttribute(String name) { - return (T) attributes.get(name); - } - - @SuppressWarnings("unchecked") - public T removeAttribute(String name) { - return (T) attributes.remove(name); - } - - public TransportNode clearAttributes() { - attributes.clear(); - return this; - } - - public ConcurrentHashMap getAttributes() { - return attributes; - } - - public void setAttributes(ConcurrentHashMap map) { - attributes.clear(); - if (map != null) attributes.putAll(map); - } - - public InetSocketAddress getAddress() { - return address; - } - - public long getDisabletime() { - return disabletime; - } - - @ConvertDisabled - public BlockingQueue getConnQueue() { - return connQueue; - } - - public void dispose() { - AsyncConnection conn; - while ((conn = connQueue.poll()) != null) { - conn.dispose(); - } - } - - @Override - public int hashCode() { - return this.address.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; - final TransportNode other = (TransportNode) obj; - return this.address.equals(other.address); - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - } -} +/* + * 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; + +import java.io.IOException; +import java.lang.ref.WeakReference; +import java.net.*; +import java.nio.ByteBuffer; +import java.nio.channels.*; +import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.*; +import java.util.function.Supplier; +import java.util.logging.Level; +import javax.net.ssl.SSLContext; +import org.redkale.convert.*; +import org.redkale.convert.json.JsonConvert; +import org.redkale.util.*; + +/** + * 浼犺緭瀹㈡埛绔 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public final class Transport { + + public static final String DEFAULT_NETPROTOCOL = "TCP"; + + protected final AtomicInteger seq = new AtomicInteger(-1); + + protected final TransportFactory factory; + + protected final String name; //鍗鐨刵ame灞炴 + + protected final boolean tcp; + + protected final String netprotocol; + + //浼犺緭绔殑AsyncGroup + protected final AsyncGroup asyncGroup; + + protected final InetSocketAddress clientAddress; + + //涓嶅彲鑳戒负null + protected TransportNode[] transportNodes = new TransportNode[0]; + + protected final SSLContext sslContext; + + //璐熻浇鍧囪 绛栫暐 + protected final TransportStrategy strategy; + + //杩炴帴涓婇檺锛 涓簄ull琛ㄧず鏃犻檺鍒 + protected Semaphore semaphore; + + protected Transport(String name, TransportFactory factory, final AsyncGroup asyncGroup, final SSLContext sslContext, final InetSocketAddress clientAddress, + final Collection addresses, final TransportStrategy strategy) { + this(name, DEFAULT_NETPROTOCOL, factory, asyncGroup, sslContext, clientAddress, addresses, strategy); + } + + protected Transport(String name, String netprotocol, final TransportFactory factory, final AsyncGroup asyncGroup, final SSLContext sslContext, final InetSocketAddress clientAddress, + final Collection addresses, final TransportStrategy strategy) { + this.name = name; + this.netprotocol = netprotocol; + this.factory = factory; + factory.transportReferences.add(new WeakReference<>(this)); + this.tcp = "TCP".equalsIgnoreCase(netprotocol); + this.asyncGroup = asyncGroup; + this.sslContext = sslContext; + this.clientAddress = clientAddress; + this.strategy = strategy; + updateRemoteAddresses(addresses); + } + + public Semaphore getSemaphore() { + return semaphore; + } + + public void setSemaphore(Semaphore semaphore) { + this.semaphore = semaphore; + } + + public final InetSocketAddress[] updateRemoteAddresses(final Collection addresses) { + final TransportNode[] oldNodes = this.transportNodes; + synchronized (this) { + boolean same = false; + if (this.transportNodes != null && addresses != null && this.transportNodes.length == addresses.size()) { + same = true; + for (TransportNode node : this.transportNodes) { + if (!addresses.contains(node.getAddress())) { + same = false; + break; + } + } + } + if (!same) { + List list = new ArrayList<>(); + if (addresses != null) { + for (InetSocketAddress addr : addresses) { + if (clientAddress != null && clientAddress.equals(addr)) continue; + boolean hasold = false; + for (TransportNode oldAddr : oldNodes) { + if (oldAddr.getAddress().equals(addr)) { + list.add(oldAddr); + hasold = true; + break; + } + } + if (hasold) continue; + list.add(new TransportNode(factory.poolmaxconns, addr)); + } + } + this.transportNodes = list.toArray(new TransportNode[list.size()]); + } + } + InetSocketAddress[] rs = new InetSocketAddress[oldNodes.length]; + for (int i = 0; i < rs.length; i++) { + rs[i] = oldNodes[i].getAddress(); + } + return rs; + } + + public final boolean addRemoteAddresses(final InetSocketAddress addr) { + if (addr == null) return false; + if (clientAddress != null && clientAddress.equals(addr)) return false; + synchronized (this) { + if (this.transportNodes.length == 0) { + this.transportNodes = new TransportNode[]{new TransportNode(factory.poolmaxconns, addr)}; + } else { + for (TransportNode i : this.transportNodes) { + if (addr.equals(i.address)) return false; + } + this.transportNodes = Utility.append(transportNodes, new TransportNode(factory.poolmaxconns, addr)); + } + return true; + } + } + + public final boolean removeRemoteAddresses(InetSocketAddress addr) { + if (addr == null) return false; + synchronized (this) { + this.transportNodes = Utility.remove(transportNodes, new TransportNode(factory.poolmaxconns, addr)); + } + return true; + } + + public String getName() { + return name; + } + + public void close() { + TransportNode[] nodes = this.transportNodes; + if (nodes == null) return; + for (TransportNode node : nodes) { + if (node != null) node.dispose(); + } + } + + public InetSocketAddress getClientAddress() { + return clientAddress; + } + + public TransportNode[] getTransportNodes() { + return transportNodes; + } + + public TransportNode findTransportNode(SocketAddress addr) { + for (TransportNode node : this.transportNodes) { + if (node.address.equals(addr)) return node; + } + return null; + } + + public InetSocketAddress[] getRemoteAddresses() { + InetSocketAddress[] rs = new InetSocketAddress[transportNodes.length]; + for (int i = 0; i < rs.length; i++) { + rs[i] = transportNodes[i].getAddress(); + } + return rs; + } + + @Override + public String toString() { + return Transport.class.getSimpleName() + "{name = " + name + ", protocol = " + netprotocol + ", clientAddress = " + clientAddress + ", remoteNodes = " + Arrays.toString(transportNodes) + "}"; + } + + public String getNetprotocol() { + return netprotocol; + } + + public boolean isTCP() { + return tcp; + } + + protected CompletableFuture pollAsync(TransportNode node, SocketAddress addr, Supplier> func) { + final BlockingQueue queue = node.connQueue; + if (!queue.isEmpty()) { + AsyncConnection conn; + while ((conn = queue.poll()) != null) { + if (conn.isOpen()) { + return CompletableFuture.completedFuture(conn); + } else { + conn.dispose(); + } + } + } + if (semaphore != null && !semaphore.tryAcquire()) { + final CompletableFuture future = Utility.orTimeout(new CompletableFuture<>(), 10, TimeUnit.SECONDS); + future.whenComplete((r, t) -> node.pollQueue.remove(future)); + if (node.pollQueue.offer(future)) return future; + future.completeExceptionally(new IOException("create transport connection error")); + return future; + } + return func.get().thenApply(conn -> { + if (conn != null && semaphore != null) conn.beforeCloseListener((c) -> semaphore.release()); + return conn; + }); + } + + public CompletableFuture pollConnection(SocketAddress addr0) { + if (this.strategy != null) return strategy.pollConnection(addr0, this); + final TransportNode[] nodes = this.transportNodes; + if (addr0 == null && nodes.length == 1) addr0 = nodes[0].address; + final SocketAddress addr = addr0; + final boolean rand = addr == null; //鏄惁闅忔満鍙栧湴鍧 + if (rand && nodes.length < 1) throw new RuntimeException("Transport (" + this.name + ") have no remoteAddress list"); + try { + if (!tcp) { // UDP + SocketAddress udpaddr = rand ? nodes[0].address : addr; + return asyncGroup.createUDPClient(udpaddr, factory.readTimeoutSeconds, factory.writeTimeoutSeconds); + } + if (!rand) { //鎸囧畾鍦板潃 + TransportNode node = findTransportNode(addr); + if (node == null) return asyncGroup.createTCPClient(addr, factory.readTimeoutSeconds, factory.writeTimeoutSeconds); + return pollAsync(node, addr, () -> asyncGroup.createTCPClient(addr, factory.readTimeoutSeconds, factory.writeTimeoutSeconds)); + } + + //---------------------闅忔満鍙栧湴鍧------------------------ + int enablecount = 0; + final TransportNode[] newnodes = new TransportNode[nodes.length]; + for (final TransportNode node : nodes) { + if (node.disabletime > 0) continue; + newnodes[enablecount++] = node; + } + final long now = System.currentTimeMillis(); + if (enablecount > 0) { //瀛樺湪鍙敤鐨勫湴鍧 + final TransportNode one = newnodes[Math.abs(seq.incrementAndGet()) % enablecount]; + final BlockingQueue queue = one.connQueue; + if (!queue.isEmpty()) { + AsyncConnection conn; + while ((conn = queue.poll()) != null) { + if (conn.isOpen()) { + return CompletableFuture.completedFuture(conn); + } else { + conn.dispose(); + } + } + } + return pollAsync(one, one.getAddress(), () -> { + return asyncGroup.createTCPClient(one.address, factory.readTimeoutSeconds, factory.writeTimeoutSeconds) + .whenComplete((c, t) -> { + one.disabletime = t == null ? 0 : System.currentTimeMillis(); + }); + }); + } + return pollConnection0(nodes, null, now); + } catch (Exception ex) { + throw new RuntimeException("transport address = " + addr, ex); + } + } + + private CompletableFuture pollConnection0(TransportNode[] nodes, TransportNode exclude, long now) throws IOException { + //浠庡彲鐢/涓嶅彲鐢ㄧ殑鍦板潃鍒楄〃涓垱寤鸿繛鎺 + CompletableFuture future = new CompletableFuture(); + for (final TransportNode node : nodes) { + if (node == exclude) continue; + if (future.isDone()) return future; + asyncGroup.createTCPClient(node.address, factory.readTimeoutSeconds, factory.writeTimeoutSeconds) + .whenComplete((c, t) -> { + if (c != null && !future.complete(c)) node.connQueue.offer(c); + node.disabletime = t == null ? 0 : System.currentTimeMillis(); + }); + } + return future; + } + + public void offerConnection(final boolean forceClose, AsyncConnection conn) { + if (this.strategy != null && strategy.offerConnection(forceClose, conn)) return; + if (!forceClose && conn.isTCP()) { + if (conn.isOpen()) { + TransportNode node = findTransportNode(conn.getRemoteAddress()); + if (node == null || !node.connQueue.offer(conn)) conn.dispose(); + } else { + conn.dispose(); + } + } else { + conn.dispose(); + } + } + + public void async(SocketAddress addr, final ByteBuffer buffer, A att, final CompletionHandler handler) { + pollConnection(addr).whenComplete((conn, ex) -> { + if (ex != null) { + factory.getLogger().log(Level.WARNING, Transport.class.getSimpleName() + " async error", ex); + return; + } + conn.write(buffer, buffer, new CompletionHandler() { + + @Override + public void completed(Integer result, ByteBuffer attachment) { + buffer.clear(); + conn.setReadBuffer(buffer); + conn.read(new CompletionHandler() { + + @Override + public void completed(Integer result, ByteBuffer attachment) { + if (handler != null) handler.completed(result, att); + conn.offerBuffer(attachment); + offerConnection(false, conn); + } + + @Override + public void failed(Throwable exc, ByteBuffer attachment) { + conn.offerBuffer(attachment); + offerConnection(true, conn); + } + }); + + } + + @Override + public void failed(Throwable exc, ByteBuffer attachment) { + conn.offerBuffer(attachment); + offerConnection(true, conn); + } + }); + }); + } + + public static class TransportNode { + + protected InetSocketAddress address; + + protected volatile long disabletime; //涓嶅彲鐢ㄦ椂鐨勬椂闂, 涓0琛ㄧず鍙敤 + + protected final BlockingQueue connQueue; + + protected final ArrayBlockingQueue> pollQueue; + + protected final ConcurrentHashMap attributes = new ConcurrentHashMap<>(); + + public TransportNode(int poolmaxconns, InetSocketAddress address) { + this.address = address; + this.disabletime = 0; + this.connQueue = new ArrayBlockingQueue<>(poolmaxconns); + this.pollQueue = new ArrayBlockingQueue(this.connQueue.remainingCapacity() * 100); + } + + @ConstructorParameters({"poolmaxconns", "address", "disabletime"}) + public TransportNode(int poolmaxconns, InetSocketAddress address, long disabletime) { + this.address = address; + this.disabletime = disabletime; + this.connQueue = new LinkedBlockingQueue<>(poolmaxconns); + this.pollQueue = new ArrayBlockingQueue(this.connQueue.remainingCapacity() * 100); + } + + public int getPoolmaxconns() { + return this.connQueue.remainingCapacity() + this.connQueue.size(); + } + + public T setAttribute(String name, T value) { + attributes.put(name, value); + return value; + } + + @SuppressWarnings("unchecked") + public T getAttribute(String name) { + return (T) attributes.get(name); + } + + @SuppressWarnings("unchecked") + public T removeAttribute(String name) { + return (T) attributes.remove(name); + } + + public TransportNode clearAttributes() { + attributes.clear(); + return this; + } + + public ConcurrentHashMap getAttributes() { + return attributes; + } + + public void setAttributes(ConcurrentHashMap map) { + attributes.clear(); + if (map != null) attributes.putAll(map); + } + + public InetSocketAddress getAddress() { + return address; + } + + public long getDisabletime() { + return disabletime; + } + + @ConvertDisabled + public BlockingQueue getConnQueue() { + return connQueue; + } + + public void dispose() { + AsyncConnection conn; + while ((conn = connQueue.poll()) != null) { + conn.dispose(); + } + } + + @Override + public int hashCode() { + return this.address.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + final TransportNode other = (TransportNode) obj; + return this.address.equals(other.address); + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + } +} diff --git a/src/main/java/org/redkale/net/TransportFactory.java b/src/main/java/org/redkale/net/TransportFactory.java index b44e7d270..4bdd9c839 100644 --- a/src/main/java/org/redkale/net/TransportFactory.java +++ b/src/main/java/org/redkale/net/TransportFactory.java @@ -1,348 +1,348 @@ -/* - * 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; - -import java.lang.ref.WeakReference; -import java.net.*; -import java.nio.ByteBuffer; -import java.nio.channels.*; -import java.util.*; -import java.util.concurrent.*; -import java.util.logging.*; -import java.util.stream.Collectors; -import javax.net.ssl.SSLContext; -import org.redkale.service.Service; -import org.redkale.util.*; - -/** - * System.getProperty("redkale.net.transport.ping.interval", "30") 蹇冭烦鍛ㄦ湡锛岄粯璁30绉 - * System.getProperty("redkale.net.transport.check.interval", "30") 妫鏌ヤ笉鍙敤鍦板潃鍛ㄦ湡锛岄粯璁30绉 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public class TransportFactory { - - @Comment("榛樿TCP璇诲彇瓒呮椂绉掓暟") - public static int DEFAULT_READTIMEOUTSECONDS = 6; - - @Comment("榛樿TCP鍐欏叆瓒呮椂绉掓暟") - public static int DEFAULT_WRITETIMEOUTSECONDS = 6; - - public static final String NAME_POOLMAXCONNS = "poolmaxconns"; - - public static final String NAME_PINGINTERVAL = "pinginterval"; - - public static final String NAME_CHECKINTERVAL = "checkinterval"; - - protected static final Logger logger = Logger.getLogger(TransportFactory.class.getSimpleName()); - - //浼犺緭绔殑AsyncGroup - protected final AsyncGroup asyncGroup; - - //姣忎釜鍦板潃瀵瑰簲鐨凣roup鍚 - protected final Map groupAddrs = new HashMap<>(); - - //鍗忚鍦板潃鐨凣roup闆嗗悎 - protected final Map groupInfos = new HashMap<>(); - - protected final List> services = new CopyOnWriteArrayList<>(); - - protected final List> transportReferences = new CopyOnWriteArrayList<>(); - - //杩炴帴姹犲ぇ灏 - protected int poolmaxconns = Integer.getInteger("redkale.net.transport.pool.maxconns", Math.max(100, Utility.cpus() * 16)); //鏈灏戞槸wsthreads鐨勪袱鍊 - - //妫鏌ヤ笉鍙敤鍦板潃鍛ㄦ湡锛 鍗曚綅锛氱 - protected int checkinterval = Integer.getInteger("redkale.net.transport.check.interval", 30); - - //蹇冭烦鍛ㄦ湡锛 鍗曚綅锛氱 - protected int pinginterval; - - //TCP璇诲彇瓒呮椂绉掓暟 - protected int readTimeoutSeconds; - - //TCP鍐欏叆瓒呮椂绉掓暟 - protected int writeTimeoutSeconds; - - //ping鍜屾鏌ョ殑瀹氭椂鍣 - private ScheduledThreadPoolExecutor scheduler; - - protected SSLContext sslContext; - - //ping鐨勫唴瀹 - private ByteBuffer pingBuffer; - - //pong鐨勬暟鎹暱搴, 灏忎簬0琛ㄧず涓嶈繘琛屽垽鏂 - protected int pongLength; - - //鏄惁TCP - protected String netprotocol = "TCP"; - - //璐熻浇鍧囪 绛栫暐 - protected final TransportStrategy strategy; - - protected TransportFactory(AsyncGroup asyncGroup, SSLContext sslContext, String netprotocol, - int readTimeoutSeconds, int writeTimeoutSeconds, final TransportStrategy strategy) { - this.asyncGroup = asyncGroup; - this.sslContext = sslContext; - this.netprotocol = netprotocol; - this.readTimeoutSeconds = readTimeoutSeconds; - this.writeTimeoutSeconds = writeTimeoutSeconds; - this.strategy = strategy; - } - - protected TransportFactory(AsyncGroup asyncGroup, SSLContext sslContext, String netprotocol, - int readTimeoutSeconds, int writeTimeoutSeconds) { - this(asyncGroup, sslContext, netprotocol, readTimeoutSeconds, writeTimeoutSeconds, null); - } - - public void init(AnyValue conf, ByteBuffer pingBuffer, int pongLength) { - if (conf != null) { - this.poolmaxconns = conf.getIntValue(NAME_POOLMAXCONNS, this.poolmaxconns); - this.pinginterval = conf.getIntValue(NAME_PINGINTERVAL, this.pinginterval); - this.checkinterval = conf.getIntValue(NAME_CHECKINTERVAL, this.checkinterval); - if (this.poolmaxconns < 2) this.poolmaxconns = 2; - if (this.pinginterval < 2) this.pinginterval = 2; - if (this.checkinterval < 2) this.checkinterval = 2; - } - this.scheduler = new ScheduledThreadPoolExecutor(1, (Runnable r) -> { - final Thread t = new Thread(r, "Redkale-" + this.getClass().getSimpleName() + "-Schedule-Thread"); - t.setDaemon(true); - return t; - }); - this.scheduler.scheduleAtFixedRate(() -> { - try { - checks(); - } catch (Throwable t) { - logger.log(Level.SEVERE, "TransportFactory schedule(interval=" + checkinterval + "s) check error", t); - } - }, checkinterval, checkinterval, TimeUnit.SECONDS); - - if (this.pinginterval > 0) { - if (pingBuffer != null) { - this.pingBuffer = pingBuffer.asReadOnlyBuffer(); - this.pongLength = pongLength; - - scheduler.scheduleAtFixedRate(() -> { - pings(); - }, pinginterval, pinginterval, TimeUnit.SECONDS); - } - } - } - - public static TransportFactory create(AsyncGroup asyncGroup, int readTimeoutSeconds, int writeTimeoutSeconds) { - return new TransportFactory(asyncGroup, null, "TCP", readTimeoutSeconds, writeTimeoutSeconds, null); - } - - public static TransportFactory create(AsyncGroup asyncGroup, SSLContext sslContext, int readTimeoutSeconds, int writeTimeoutSeconds, final TransportStrategy strategy) { - return new TransportFactory(asyncGroup, sslContext, "TCP", readTimeoutSeconds, writeTimeoutSeconds, strategy); - } - - public static TransportFactory create(AsyncGroup asyncGroup, String netprotocol, int readTimeoutSeconds, int writeTimeoutSeconds) { - return new TransportFactory(asyncGroup, null, netprotocol, readTimeoutSeconds, writeTimeoutSeconds, null); - } - - public static TransportFactory create(AsyncGroup asyncGroup, SSLContext sslContext, String netprotocol, int readTimeoutSeconds, int writeTimeoutSeconds, final TransportStrategy strategy) { - return new TransportFactory(asyncGroup, sslContext, netprotocol, readTimeoutSeconds, writeTimeoutSeconds, strategy); - } - - public Transport createTransportTCP(String name, final InetSocketAddress clientAddress, final Collection addresses) { - return new Transport(name, "TCP", this, this.asyncGroup, this.sslContext, clientAddress, addresses, strategy); - } - - public Transport createTransport(String name, String netprotocol, final InetSocketAddress clientAddress, final Collection addresses) { - return new Transport(name, netprotocol, this, this.asyncGroup, this.sslContext, clientAddress, addresses, strategy); - } - - public String findGroupName(InetSocketAddress addr) { - if (addr == null) return null; - return groupAddrs.get(addr); - } - - public TransportGroupInfo findGroupInfo(String group) { - if (group == null) return null; - return groupInfos.get(group); - } - - public boolean addGroupInfo(String groupName, InetSocketAddress... addrs) { - addGroupInfo(new TransportGroupInfo(groupName, addrs)); - return true; - } - - public boolean removeGroupInfo(String groupName, InetSocketAddress addr) { - if (groupName == null || groupName.isEmpty() || addr == null) return false; - if (!groupName.equals(groupAddrs.get(addr))) return false; - TransportGroupInfo group = groupInfos.get(groupName); - if (group == null) return false; - group.removeAddress(addr); - groupAddrs.remove(addr); - return true; - } - - public TransportFactory addGroupInfo(String name, Set addrs) { - addGroupInfo(new TransportGroupInfo(name, addrs)); - return this; - } - - public boolean addGroupInfo(TransportGroupInfo info) { - if (info == null) throw new RuntimeException("TransportGroupInfo can not null"); - if (info.addresses == null) throw new RuntimeException("TransportGroupInfo.addresses can not null"); - if (!checkName(info.name)) throw new RuntimeException("Transport.group.name only 0-9 a-z A-Z _ cannot begin 0-9"); - TransportGroupInfo old = groupInfos.get(info.name); - if (old != null && !old.protocol.equals(info.protocol)) throw new RuntimeException("Transport.group.name repeat but protocol is different"); - for (InetSocketAddress addr : info.addresses) { - if (!groupAddrs.getOrDefault(addr, info.name).equals(info.name)) throw new RuntimeException(addr + " repeat but different group.name"); - } - if (old == null) { - groupInfos.put(info.name, info); - } else { - old.putAddress(info.addresses); - } - for (InetSocketAddress addr : info.addresses) { - groupAddrs.put(addr, info.name); - } - return true; - } - - public Transport loadTransport(InetSocketAddress sncpAddress, final Set groups) { - if (groups == null) return null; - Set addresses = new HashSet<>(); - TransportGroupInfo info = null; - for (String group : groups) { - info = groupInfos.get(group); - if (info == null) continue; - addresses.addAll(info.addresses); - } - if (info == null) { - info = new TransportGroupInfo(netprotocol); - } else { - info.protocol = netprotocol; - } - if (sncpAddress != null) addresses.remove(sncpAddress); - return new Transport(groups.stream().sorted().collect(Collectors.joining(";")), info.protocol, this, this.asyncGroup, this.sslContext, sncpAddress, addresses, this.strategy); - } - - public List getGroupInfos() { - return new ArrayList<>(this.groupInfos.values()); - } - - public Logger getLogger() { - return logger; - } - - public void addSncpService(Service service) { - if (service == null) return; - services.add(new WeakReference<>(service)); - } - - public List getServices() { - List rs = new ArrayList<>(); - for (WeakReference ref : services) { - Service service = ref.get(); - if (service != null) rs.add(service); - } - return rs; - } - - public void shutdownNow() { - if (this.scheduler != null) this.scheduler.shutdownNow(); - } - - private void checks() { - List nulllist = new ArrayList<>(); - for (WeakReference ref : transportReferences) { - Transport transport = ref.get(); - if (transport == null) { - nulllist.add(ref); - continue; - } - Transport.TransportNode[] nodes = transport.getTransportNodes(); - for (final Transport.TransportNode node : nodes) { - if (node.disabletime < 1) continue; //鍙敤 - CompletableFuture future = Utility.orTimeout(asyncGroup.createTCPClient(node.address), 2, TimeUnit.SECONDS); - future.whenComplete((r, t) -> { - node.disabletime = t == null ? 0 : System.currentTimeMillis(); - if (r != null) r.dispose(); - }); - } - } - for (WeakReference ref : nulllist) { - transportReferences.remove(ref); - } - } - - private void pings() { - long timex = System.currentTimeMillis() - (this.pinginterval < 15 ? this.pinginterval : (this.pinginterval - 3)) * 1000; - for (WeakReference ref : transportReferences) { - Transport transport = ref.get(); - if (transport == null) continue; - Transport.TransportNode[] nodes = transport.getTransportNodes(); - for (final Transport.TransportNode node : nodes) { - final BlockingQueue queue = node.connQueue; - AsyncConnection conn; - while ((conn = queue.poll()) != null) { - if (conn.getLastWriteTime() > timex && false) { //鏈杩戝嚑绉掑唴宸茬粡杩涜杩嘔O鎿嶄綔 - queue.offer(conn); - } else { //瓒呰繃涓瀹氭椂闂寸殑杩炴帴闇瑕佽繘琛宲ing澶勭悊 - ByteBuffer sendBuffer = pingBuffer.duplicate(); - final AsyncConnection localconn = conn; - final BlockingQueue localqueue = queue; - localconn.write(sendBuffer, sendBuffer, new CompletionHandler() { - @Override - public void completed(Integer result, ByteBuffer wbuffer) { - localconn.read(new CompletionHandler() { - int counter = 0; - - @Override - public void completed(Integer result, ByteBuffer pongBuffer) { - if (counter > 3) { - localconn.offerBuffer(pongBuffer); - localconn.dispose(); - return; - } - if (pongLength > 0 && pongBuffer.position() < pongLength) { - counter++; - localconn.setReadBuffer(pongBuffer); - localconn.read(this); - return; - } - localconn.offerBuffer(pongBuffer); - localqueue.offer(localconn); - } - - @Override - public void failed(Throwable exc, ByteBuffer pongBuffer) { - localconn.offerBuffer(pongBuffer); - localconn.dispose(); - } - }); - } - - @Override - public void failed(Throwable exc, ByteBuffer buffer) { - localconn.dispose(); - } - }); - } - } - } - } - } - - private static boolean checkName(String name) { //涓嶈兘鍚壒娈婂瓧绗 - if (name.isEmpty()) return false; - if (name.charAt(0) >= '0' && name.charAt(0) <= '9') return false; - for (char ch : name.toCharArray()) { - if (!((ch >= '0' && ch <= '9') || ch == '_' || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))) { //涓嶈兘鍚壒娈婂瓧绗 - return false; - } - } - return true; - } -} +/* + * 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; + +import java.lang.ref.WeakReference; +import java.net.*; +import java.nio.ByteBuffer; +import java.nio.channels.*; +import java.util.*; +import java.util.concurrent.*; +import java.util.logging.*; +import java.util.stream.Collectors; +import javax.net.ssl.SSLContext; +import org.redkale.service.Service; +import org.redkale.util.*; + +/** + * System.getProperty("redkale.net.transport.ping.interval", "30") 蹇冭烦鍛ㄦ湡锛岄粯璁30绉 + * System.getProperty("redkale.net.transport.check.interval", "30") 妫鏌ヤ笉鍙敤鍦板潃鍛ㄦ湡锛岄粯璁30绉 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public class TransportFactory { + + @Comment("榛樿TCP璇诲彇瓒呮椂绉掓暟") + public static int DEFAULT_READTIMEOUTSECONDS = 6; + + @Comment("榛樿TCP鍐欏叆瓒呮椂绉掓暟") + public static int DEFAULT_WRITETIMEOUTSECONDS = 6; + + public static final String NAME_POOLMAXCONNS = "poolmaxconns"; + + public static final String NAME_PINGINTERVAL = "pinginterval"; + + public static final String NAME_CHECKINTERVAL = "checkinterval"; + + protected static final Logger logger = Logger.getLogger(TransportFactory.class.getSimpleName()); + + //浼犺緭绔殑AsyncGroup + protected final AsyncGroup asyncGroup; + + //姣忎釜鍦板潃瀵瑰簲鐨凣roup鍚 + protected final Map groupAddrs = new HashMap<>(); + + //鍗忚鍦板潃鐨凣roup闆嗗悎 + protected final Map groupInfos = new HashMap<>(); + + protected final List> services = new CopyOnWriteArrayList<>(); + + protected final List> transportReferences = new CopyOnWriteArrayList<>(); + + //杩炴帴姹犲ぇ灏 + protected int poolmaxconns = Integer.getInteger("redkale.net.transport.pool.maxconns", Math.max(100, Utility.cpus() * 16)); //鏈灏戞槸wsthreads鐨勪袱鍊 + + //妫鏌ヤ笉鍙敤鍦板潃鍛ㄦ湡锛 鍗曚綅锛氱 + protected int checkinterval = Integer.getInteger("redkale.net.transport.check.interval", 30); + + //蹇冭烦鍛ㄦ湡锛 鍗曚綅锛氱 + protected int pinginterval; + + //TCP璇诲彇瓒呮椂绉掓暟 + protected int readTimeoutSeconds; + + //TCP鍐欏叆瓒呮椂绉掓暟 + protected int writeTimeoutSeconds; + + //ping鍜屾鏌ョ殑瀹氭椂鍣 + private ScheduledThreadPoolExecutor scheduler; + + protected SSLContext sslContext; + + //ping鐨勫唴瀹 + private ByteBuffer pingBuffer; + + //pong鐨勬暟鎹暱搴, 灏忎簬0琛ㄧず涓嶈繘琛屽垽鏂 + protected int pongLength; + + //鏄惁TCP + protected String netprotocol = "TCP"; + + //璐熻浇鍧囪 绛栫暐 + protected final TransportStrategy strategy; + + protected TransportFactory(AsyncGroup asyncGroup, SSLContext sslContext, String netprotocol, + int readTimeoutSeconds, int writeTimeoutSeconds, final TransportStrategy strategy) { + this.asyncGroup = asyncGroup; + this.sslContext = sslContext; + this.netprotocol = netprotocol; + this.readTimeoutSeconds = readTimeoutSeconds; + this.writeTimeoutSeconds = writeTimeoutSeconds; + this.strategy = strategy; + } + + protected TransportFactory(AsyncGroup asyncGroup, SSLContext sslContext, String netprotocol, + int readTimeoutSeconds, int writeTimeoutSeconds) { + this(asyncGroup, sslContext, netprotocol, readTimeoutSeconds, writeTimeoutSeconds, null); + } + + public void init(AnyValue conf, ByteBuffer pingBuffer, int pongLength) { + if (conf != null) { + this.poolmaxconns = conf.getIntValue(NAME_POOLMAXCONNS, this.poolmaxconns); + this.pinginterval = conf.getIntValue(NAME_PINGINTERVAL, this.pinginterval); + this.checkinterval = conf.getIntValue(NAME_CHECKINTERVAL, this.checkinterval); + if (this.poolmaxconns < 2) this.poolmaxconns = 2; + if (this.pinginterval < 2) this.pinginterval = 2; + if (this.checkinterval < 2) this.checkinterval = 2; + } + this.scheduler = new ScheduledThreadPoolExecutor(1, (Runnable r) -> { + final Thread t = new Thread(r, "Redkale-" + this.getClass().getSimpleName() + "-Schedule-Thread"); + t.setDaemon(true); + return t; + }); + this.scheduler.scheduleAtFixedRate(() -> { + try { + checks(); + } catch (Throwable t) { + logger.log(Level.SEVERE, "TransportFactory schedule(interval=" + checkinterval + "s) check error", t); + } + }, checkinterval, checkinterval, TimeUnit.SECONDS); + + if (this.pinginterval > 0) { + if (pingBuffer != null) { + this.pingBuffer = pingBuffer.asReadOnlyBuffer(); + this.pongLength = pongLength; + + scheduler.scheduleAtFixedRate(() -> { + pings(); + }, pinginterval, pinginterval, TimeUnit.SECONDS); + } + } + } + + public static TransportFactory create(AsyncGroup asyncGroup, int readTimeoutSeconds, int writeTimeoutSeconds) { + return new TransportFactory(asyncGroup, null, "TCP", readTimeoutSeconds, writeTimeoutSeconds, null); + } + + public static TransportFactory create(AsyncGroup asyncGroup, SSLContext sslContext, int readTimeoutSeconds, int writeTimeoutSeconds, final TransportStrategy strategy) { + return new TransportFactory(asyncGroup, sslContext, "TCP", readTimeoutSeconds, writeTimeoutSeconds, strategy); + } + + public static TransportFactory create(AsyncGroup asyncGroup, String netprotocol, int readTimeoutSeconds, int writeTimeoutSeconds) { + return new TransportFactory(asyncGroup, null, netprotocol, readTimeoutSeconds, writeTimeoutSeconds, null); + } + + public static TransportFactory create(AsyncGroup asyncGroup, SSLContext sslContext, String netprotocol, int readTimeoutSeconds, int writeTimeoutSeconds, final TransportStrategy strategy) { + return new TransportFactory(asyncGroup, sslContext, netprotocol, readTimeoutSeconds, writeTimeoutSeconds, strategy); + } + + public Transport createTransportTCP(String name, final InetSocketAddress clientAddress, final Collection addresses) { + return new Transport(name, "TCP", this, this.asyncGroup, this.sslContext, clientAddress, addresses, strategy); + } + + public Transport createTransport(String name, String netprotocol, final InetSocketAddress clientAddress, final Collection addresses) { + return new Transport(name, netprotocol, this, this.asyncGroup, this.sslContext, clientAddress, addresses, strategy); + } + + public String findGroupName(InetSocketAddress addr) { + if (addr == null) return null; + return groupAddrs.get(addr); + } + + public TransportGroupInfo findGroupInfo(String group) { + if (group == null) return null; + return groupInfos.get(group); + } + + public boolean addGroupInfo(String groupName, InetSocketAddress... addrs) { + addGroupInfo(new TransportGroupInfo(groupName, addrs)); + return true; + } + + public boolean removeGroupInfo(String groupName, InetSocketAddress addr) { + if (groupName == null || groupName.isEmpty() || addr == null) return false; + if (!groupName.equals(groupAddrs.get(addr))) return false; + TransportGroupInfo group = groupInfos.get(groupName); + if (group == null) return false; + group.removeAddress(addr); + groupAddrs.remove(addr); + return true; + } + + public TransportFactory addGroupInfo(String name, Set addrs) { + addGroupInfo(new TransportGroupInfo(name, addrs)); + return this; + } + + public boolean addGroupInfo(TransportGroupInfo info) { + if (info == null) throw new RuntimeException("TransportGroupInfo can not null"); + if (info.addresses == null) throw new RuntimeException("TransportGroupInfo.addresses can not null"); + if (!checkName(info.name)) throw new RuntimeException("Transport.group.name only 0-9 a-z A-Z _ cannot begin 0-9"); + TransportGroupInfo old = groupInfos.get(info.name); + if (old != null && !old.protocol.equals(info.protocol)) throw new RuntimeException("Transport.group.name repeat but protocol is different"); + for (InetSocketAddress addr : info.addresses) { + if (!groupAddrs.getOrDefault(addr, info.name).equals(info.name)) throw new RuntimeException(addr + " repeat but different group.name"); + } + if (old == null) { + groupInfos.put(info.name, info); + } else { + old.putAddress(info.addresses); + } + for (InetSocketAddress addr : info.addresses) { + groupAddrs.put(addr, info.name); + } + return true; + } + + public Transport loadTransport(InetSocketAddress sncpAddress, final Set groups) { + if (groups == null) return null; + Set addresses = new HashSet<>(); + TransportGroupInfo info = null; + for (String group : groups) { + info = groupInfos.get(group); + if (info == null) continue; + addresses.addAll(info.addresses); + } + if (info == null) { + info = new TransportGroupInfo(netprotocol); + } else { + info.protocol = netprotocol; + } + if (sncpAddress != null) addresses.remove(sncpAddress); + return new Transport(groups.stream().sorted().collect(Collectors.joining(";")), info.protocol, this, this.asyncGroup, this.sslContext, sncpAddress, addresses, this.strategy); + } + + public List getGroupInfos() { + return new ArrayList<>(this.groupInfos.values()); + } + + public Logger getLogger() { + return logger; + } + + public void addSncpService(Service service) { + if (service == null) return; + services.add(new WeakReference<>(service)); + } + + public List getServices() { + List rs = new ArrayList<>(); + for (WeakReference ref : services) { + Service service = ref.get(); + if (service != null) rs.add(service); + } + return rs; + } + + public void shutdownNow() { + if (this.scheduler != null) this.scheduler.shutdownNow(); + } + + private void checks() { + List nulllist = new ArrayList<>(); + for (WeakReference ref : transportReferences) { + Transport transport = ref.get(); + if (transport == null) { + nulllist.add(ref); + continue; + } + Transport.TransportNode[] nodes = transport.getTransportNodes(); + for (final Transport.TransportNode node : nodes) { + if (node.disabletime < 1) continue; //鍙敤 + CompletableFuture future = Utility.orTimeout(asyncGroup.createTCPClient(node.address), 2, TimeUnit.SECONDS); + future.whenComplete((r, t) -> { + node.disabletime = t == null ? 0 : System.currentTimeMillis(); + if (r != null) r.dispose(); + }); + } + } + for (WeakReference ref : nulllist) { + transportReferences.remove(ref); + } + } + + private void pings() { + long timex = System.currentTimeMillis() - (this.pinginterval < 15 ? this.pinginterval : (this.pinginterval - 3)) * 1000; + for (WeakReference ref : transportReferences) { + Transport transport = ref.get(); + if (transport == null) continue; + Transport.TransportNode[] nodes = transport.getTransportNodes(); + for (final Transport.TransportNode node : nodes) { + final BlockingQueue queue = node.connQueue; + AsyncConnection conn; + while ((conn = queue.poll()) != null) { + if (conn.getLastWriteTime() > timex && false) { //鏈杩戝嚑绉掑唴宸茬粡杩涜杩嘔O鎿嶄綔 + queue.offer(conn); + } else { //瓒呰繃涓瀹氭椂闂寸殑杩炴帴闇瑕佽繘琛宲ing澶勭悊 + ByteBuffer sendBuffer = pingBuffer.duplicate(); + final AsyncConnection localconn = conn; + final BlockingQueue localqueue = queue; + localconn.write(sendBuffer, sendBuffer, new CompletionHandler() { + @Override + public void completed(Integer result, ByteBuffer wbuffer) { + localconn.read(new CompletionHandler() { + int counter = 0; + + @Override + public void completed(Integer result, ByteBuffer pongBuffer) { + if (counter > 3) { + localconn.offerBuffer(pongBuffer); + localconn.dispose(); + return; + } + if (pongLength > 0 && pongBuffer.position() < pongLength) { + counter++; + localconn.setReadBuffer(pongBuffer); + localconn.read(this); + return; + } + localconn.offerBuffer(pongBuffer); + localqueue.offer(localconn); + } + + @Override + public void failed(Throwable exc, ByteBuffer pongBuffer) { + localconn.offerBuffer(pongBuffer); + localconn.dispose(); + } + }); + } + + @Override + public void failed(Throwable exc, ByteBuffer buffer) { + localconn.dispose(); + } + }); + } + } + } + } + } + + private static boolean checkName(String name) { //涓嶈兘鍚壒娈婂瓧绗 + if (name.isEmpty()) return false; + if (name.charAt(0) >= '0' && name.charAt(0) <= '9') return false; + for (char ch : name.toCharArray()) { + if (!((ch >= '0' && ch <= '9') || ch == '_' || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))) { //涓嶈兘鍚壒娈婂瓧绗 + return false; + } + } + return true; + } +} diff --git a/src/main/java/org/redkale/net/TransportGroupInfo.java b/src/main/java/org/redkale/net/TransportGroupInfo.java index 7b409570a..21975af1f 100644 --- a/src/main/java/org/redkale/net/TransportGroupInfo.java +++ b/src/main/java/org/redkale/net/TransportGroupInfo.java @@ -1,115 +1,115 @@ -/* - * 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; - -import java.net.InetSocketAddress; -import java.util.*; -import org.redkale.convert.json.JsonConvert; -import org.redkale.util.Utility; - -/** - * 鍗忚鍦板潃缁勫悎瀵硅薄, 瀵瑰簲application.xml 涓 resources->group 鑺傜偣淇℃伅 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public class TransportGroupInfo { - - protected String name; //鍦板潃 - - protected String protocol; //鍗忚 鍙栧艰寖鍥: TCP銆乁DP - - protected Set addresses; //鍦板潃鍒楄〃锛 瀵瑰簲 resources->group->node鑺傜偣淇℃伅 - - public TransportGroupInfo() { - } - - public TransportGroupInfo(String name, InetSocketAddress... addrs) { - this(name, "TCP", Utility.ofSet(addrs)); - } - - public TransportGroupInfo(String name, Set addrs) { - this(name, "TCP", addrs); - } - - public TransportGroupInfo(String name, String protocol, InetSocketAddress... addrs) { - this(name, protocol, Utility.ofSet(addrs)); - } - - public TransportGroupInfo(String name, String protocol, Set addrs) { - Objects.requireNonNull(name, "Transport.group.name can not null"); - this.name = name; - this.protocol = protocol == null ? "TCP" : protocol; - this.addresses = addrs; - } - - public String getName() { - return name; - } - - public void setName(String name) { - Objects.requireNonNull(name, "Transport.group.name can not null"); - this.name = name; - } - - public String getProtocol() { - return protocol; - } - - public void setProtocol(String protocol) { - this.protocol = protocol == null ? "TCP" : protocol; - } - - public Set getAddresses() { - return addresses; - } - - public Set copyAddresses() { - return addresses == null ? null : new LinkedHashSet<>(addresses); - } - - public void setAddresses(Set addresses) { - this.addresses = addresses; - } - - public boolean containsAddress(InetSocketAddress addr) { - synchronized (this) { - if (this.addresses == null) return false; - return this.addresses.contains(addr); - } - } - - public void removeAddress(InetSocketAddress addr) { - if (addr == null) return; - synchronized (this) { - if (this.addresses == null) return; - this.addresses.remove(addr); - } - } - - public void putAddress(InetSocketAddress addr) { - if (addr == null) return; - synchronized (this) { - if (this.addresses == null) this.addresses = new HashSet<>(); - this.addresses.add(addr); - } - } - - public void putAddress(Set addrs) { - if (addrs == null) return; - synchronized (this) { - if (this.addresses == null) this.addresses = new HashSet<>(); - this.addresses.addAll(addrs); - } - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } -} +/* + * 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; + +import java.net.InetSocketAddress; +import java.util.*; +import org.redkale.convert.json.JsonConvert; +import org.redkale.util.Utility; + +/** + * 鍗忚鍦板潃缁勫悎瀵硅薄, 瀵瑰簲application.xml 涓 resources->group 鑺傜偣淇℃伅 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public class TransportGroupInfo { + + protected String name; //鍦板潃 + + protected String protocol; //鍗忚 鍙栧艰寖鍥: TCP銆乁DP + + protected Set addresses; //鍦板潃鍒楄〃锛 瀵瑰簲 resources->group->node鑺傜偣淇℃伅 + + public TransportGroupInfo() { + } + + public TransportGroupInfo(String name, InetSocketAddress... addrs) { + this(name, "TCP", Utility.ofSet(addrs)); + } + + public TransportGroupInfo(String name, Set addrs) { + this(name, "TCP", addrs); + } + + public TransportGroupInfo(String name, String protocol, InetSocketAddress... addrs) { + this(name, protocol, Utility.ofSet(addrs)); + } + + public TransportGroupInfo(String name, String protocol, Set addrs) { + Objects.requireNonNull(name, "Transport.group.name can not null"); + this.name = name; + this.protocol = protocol == null ? "TCP" : protocol; + this.addresses = addrs; + } + + public String getName() { + return name; + } + + public void setName(String name) { + Objects.requireNonNull(name, "Transport.group.name can not null"); + this.name = name; + } + + public String getProtocol() { + return protocol; + } + + public void setProtocol(String protocol) { + this.protocol = protocol == null ? "TCP" : protocol; + } + + public Set getAddresses() { + return addresses; + } + + public Set copyAddresses() { + return addresses == null ? null : new LinkedHashSet<>(addresses); + } + + public void setAddresses(Set addresses) { + this.addresses = addresses; + } + + public boolean containsAddress(InetSocketAddress addr) { + synchronized (this) { + if (this.addresses == null) return false; + return this.addresses.contains(addr); + } + } + + public void removeAddress(InetSocketAddress addr) { + if (addr == null) return; + synchronized (this) { + if (this.addresses == null) return; + this.addresses.remove(addr); + } + } + + public void putAddress(InetSocketAddress addr) { + if (addr == null) return; + synchronized (this) { + if (this.addresses == null) this.addresses = new HashSet<>(); + this.addresses.add(addr); + } + } + + public void putAddress(Set addrs) { + if (addrs == null) return; + synchronized (this) { + if (this.addresses == null) this.addresses = new HashSet<>(); + this.addresses.addAll(addrs); + } + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } +} diff --git a/src/main/java/org/redkale/net/TransportStrategy.java b/src/main/java/org/redkale/net/TransportStrategy.java index e3f99835c..1464c410f 100644 --- a/src/main/java/org/redkale/net/TransportStrategy.java +++ b/src/main/java/org/redkale/net/TransportStrategy.java @@ -1,42 +1,42 @@ -/* - * 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; - -import java.net.SocketAddress; -import java.util.concurrent.CompletableFuture; - -/** - * 杩滅▼璇锋眰鐨勮礋杞藉潎琛$瓥鐣 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public interface TransportStrategy { - - /** - * 鍒涘缓AsyncConnection - * - * @param addr 鏈嶅姟鍣ㄥ湴鍧 - * @param transport Transport - * - * @return AsyncConnection - */ - public CompletableFuture pollConnection(SocketAddress addr, Transport transport); - - /** - * 鍥炴敹AsyncConnection锛岃繑鍥瀎alse琛ㄧず浣跨敤Transport榛樿鐨勫洖鏀跺疄鐜帮紝 杩斿洖true琛ㄧず鑷畾涔夊洖鏀跺疄鐜 - * - * @param forceClose 鏄惁寮哄埗鍏抽棴 - * @param conn AsyncConnection - * - * @return boolean - */ - default boolean offerConnection(final boolean forceClose, AsyncConnection conn) { - return false; - } -} +/* + * 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; + +import java.net.SocketAddress; +import java.util.concurrent.CompletableFuture; + +/** + * 杩滅▼璇锋眰鐨勮礋杞藉潎琛$瓥鐣 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public interface TransportStrategy { + + /** + * 鍒涘缓AsyncConnection + * + * @param addr 鏈嶅姟鍣ㄥ湴鍧 + * @param transport Transport + * + * @return AsyncConnection + */ + public CompletableFuture pollConnection(SocketAddress addr, Transport transport); + + /** + * 鍥炴敹AsyncConnection锛岃繑鍥瀎alse琛ㄧず浣跨敤Transport榛樿鐨勫洖鏀跺疄鐜帮紝 杩斿洖true琛ㄧず鑷畾涔夊洖鏀跺疄鐜 + * + * @param forceClose 鏄惁寮哄埗鍏抽棴 + * @param conn AsyncConnection + * + * @return boolean + */ + default boolean offerConnection(final boolean forceClose, AsyncConnection conn) { + return false; + } +} diff --git a/src/main/java/org/redkale/net/WorkThread.java b/src/main/java/org/redkale/net/WorkThread.java index 0e1c46b42..7c8fa68fc 100644 --- a/src/main/java/org/redkale/net/WorkThread.java +++ b/src/main/java/org/redkale/net/WorkThread.java @@ -1,115 +1,115 @@ -/* - * 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; - -import java.util.concurrent.*; -import org.redkale.util.ThreadHashExecutor; - -/** - * 鍗忚澶勭悊鐨勮嚜瀹氫箟绾跨▼绫 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public class WorkThread extends Thread implements Executor { - - protected final ExecutorService workExecutor; - - protected final ThreadHashExecutor hashExecutor; - - private int index; //WorkThread涓嬫爣 - - private int threads; //WorkThread涓暟 - - public WorkThread(String name, int index, int threads, ExecutorService workExecutor, Runnable target) { - super(target); - if (name != null) setName(name); - this.index = index; - this.threads = threads; - this.workExecutor = workExecutor; - this.hashExecutor = workExecutor instanceof ThreadHashExecutor ? (ThreadHashExecutor) workExecutor : null; - this.setDaemon(true); - } - - public static WorkThread currWorkThread() { - Thread t = Thread.currentThread(); - return t instanceof WorkThread ? (WorkThread) t : null; - } - - @Override - public void execute(Runnable command) { - if (workExecutor == null) { - command.run(); - } else { - workExecutor.execute(command); - } - } - - public void execute(Runnable... commands) { - if (workExecutor == null) { - for (Runnable command : commands) { - command.run(); - } - } else { - for (Runnable command : commands) { - workExecutor.execute(command); - } - } - } - - public void runAsync(Runnable command) { - if (workExecutor == null) { - ForkJoinPool.commonPool().execute(command); - } else { - workExecutor.execute(command); - } - } - - public void runAsync(int hash, Runnable command) { - if (hashExecutor == null) { - if (workExecutor == null) { - ForkJoinPool.commonPool().execute(command); - } else { - workExecutor.execute(command); - } - } else { - hashExecutor.execute(hash, command); - } - } - - public ExecutorService getWorkExecutor() { - return workExecutor; - } - - public boolean inCurrThread() { - return this == Thread.currentThread(); - } - - public boolean inCurrThread(Thread thread) { - return this == thread; - } - - /** - * 鑾峰彇绾跨▼姹犳暟缁勪笅鏍囷紝 浠0寮濮 - * - * @return int - */ - public int index() { - return index; - } - - /** - * 鑾峰彇绾跨▼姹犳暟缁勫ぇ灏忥紝涓嶅睘浜庝换浣曟暟缁勮繑鍥0 - * - * @return int - */ - public int threads() { - return threads; - } - -} +/* + * 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; + +import java.util.concurrent.*; +import org.redkale.util.ThreadHashExecutor; + +/** + * 鍗忚澶勭悊鐨勮嚜瀹氫箟绾跨▼绫 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public class WorkThread extends Thread implements Executor { + + protected final ExecutorService workExecutor; + + protected final ThreadHashExecutor hashExecutor; + + private int index; //WorkThread涓嬫爣 + + private int threads; //WorkThread涓暟 + + public WorkThread(String name, int index, int threads, ExecutorService workExecutor, Runnable target) { + super(target); + if (name != null) setName(name); + this.index = index; + this.threads = threads; + this.workExecutor = workExecutor; + this.hashExecutor = workExecutor instanceof ThreadHashExecutor ? (ThreadHashExecutor) workExecutor : null; + this.setDaemon(true); + } + + public static WorkThread currWorkThread() { + Thread t = Thread.currentThread(); + return t instanceof WorkThread ? (WorkThread) t : null; + } + + @Override + public void execute(Runnable command) { + if (workExecutor == null) { + command.run(); + } else { + workExecutor.execute(command); + } + } + + public void execute(Runnable... commands) { + if (workExecutor == null) { + for (Runnable command : commands) { + command.run(); + } + } else { + for (Runnable command : commands) { + workExecutor.execute(command); + } + } + } + + public void runAsync(Runnable command) { + if (workExecutor == null) { + ForkJoinPool.commonPool().execute(command); + } else { + workExecutor.execute(command); + } + } + + public void runAsync(int hash, Runnable command) { + if (hashExecutor == null) { + if (workExecutor == null) { + ForkJoinPool.commonPool().execute(command); + } else { + workExecutor.execute(command); + } + } else { + hashExecutor.execute(hash, command); + } + } + + public ExecutorService getWorkExecutor() { + return workExecutor; + } + + public boolean inCurrThread() { + return this == Thread.currentThread(); + } + + public boolean inCurrThread(Thread thread) { + return this == thread; + } + + /** + * 鑾峰彇绾跨▼姹犳暟缁勪笅鏍囷紝 浠0寮濮 + * + * @return int + */ + public int index() { + return index; + } + + /** + * 鑾峰彇绾跨▼姹犳暟缁勫ぇ灏忥紝涓嶅睘浜庝换浣曟暟缁勮繑鍥0 + * + * @return int + */ + public int threads() { + return threads; + } + +} diff --git a/src/main/java/org/redkale/net/client/Client.java b/src/main/java/org/redkale/net/client/Client.java index 0f7fa6d60..81fe6ea00 100644 --- a/src/main/java/org/redkale/net/client/Client.java +++ b/src/main/java/org/redkale/net/client/Client.java @@ -1,300 +1,300 @@ -/* - * 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.client; - -import java.net.SocketAddress; -import java.util.Queue; -import java.util.concurrent.*; -import java.util.concurrent.atomic.*; -import java.util.function.*; -import java.util.logging.*; -import org.redkale.net.*; -import org.redkale.util.*; - -/** - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @since 2.3.0 - * - * @param 璇锋眰瀵硅薄 - * @param

鍝嶅簲瀵硅薄 - */ -public abstract class Client { - - protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); - - protected final boolean finest = logger.isLoggable(Level.FINEST); - - protected final AsyncGroup group; //杩炴帴鏋勯犲櫒 - - protected final boolean tcp; //鏄惁TCP鍗忚 - - protected final SocketAddress address; //杩炴帴鐨勫湴鍧 - - protected final Creator> codecCreator; - - protected final ScheduledThreadPoolExecutor timeoutScheduler; - - protected final LongAdder writeReqCounter = new LongAdder(); - - protected final LongAdder pollRespCounter = new LongAdder(); - - private final AtomicInteger connSeqno = new AtomicInteger(); - - private boolean closed; - - protected ScheduledFuture timeoutFuture; - - protected ClientConnection[] connArray; //杩炴帴姹 - - protected LongAdder[] connResps; //杩炴帴褰撳墠澶勭悊鏁 - - protected AtomicBoolean[] connOpens; //conns鐨勬爣璁扮粍锛屽綋conn涓嶅瓨鍦ㄦ垨closed鐘舵侊紝鏍囪涓篺alse - - protected final Queue>[] connWaits; //杩炴帴绛夊緟姹 - - protected int connLimit = Utility.cpus(); //鏈澶ц繛鎺ユ暟 - - protected int maxPipelines = 16; //鍗曚釜杩炴帴鏈澶у苟琛屽鐞嗘暟 - - protected int readTimeoutSeconds; - - protected int writeTimeoutSeconds; - - protected String connectionContextName; - - //------------------ 鍙夐」 ------------------ - //PING蹇冭烦鐨勮姹傛暟鎹紝涓簄ull涓攑ingInterval<1琛ㄧず涓嶉渶瑕佸畾鏃秔ing - protected R pingRequest; - - //鍏抽棴璇锋眰鐨勬暟鎹紝 涓簄ull琛ㄧず鐩存帴鍏抽棴 - protected R closeRequest; - - //鍒涘缓杩炴帴鍚庤繘琛岀殑鐧诲綍閴存潈鎿嶄綔 - protected Function, CompletableFuture> authenticate; - - protected Client(AsyncGroup group, SocketAddress address, Creator> responseCreator) { - this(group, true, address, Utility.cpus(), 16, responseCreator, null, null, null); - } - - protected Client(AsyncGroup group, boolean tcp, SocketAddress address, Creator> codecCreator) { - this(group, tcp, address, Utility.cpus(), 16, codecCreator, null, null, null); - } - - protected Client(AsyncGroup group, boolean tcp, SocketAddress address, int maxconns, Creator> codecCreator) { - this(group, tcp, address, maxconns, 16, codecCreator, null, null, null); - } - - protected Client(AsyncGroup group, boolean tcp, SocketAddress address, int maxconns, int maxPipelines, Creator> codecCreator) { - this(group, tcp, address, maxconns, maxPipelines, codecCreator, null, null, null); - } - - protected Client(AsyncGroup group, boolean tcp, SocketAddress address, int maxconns, Creator> codecCreator, - Function, CompletableFuture> authenticate) { - this(group, tcp, address, maxconns, 16, codecCreator, null, null, authenticate); - } - - protected Client(AsyncGroup group, boolean tcp, SocketAddress address, int maxconns, Creator> codecCreator, - R closeRequest, Function, CompletableFuture> authenticate) { - this(group, tcp, address, maxconns, 16, codecCreator, null, closeRequest, authenticate); - } - - @SuppressWarnings("OverridableMethodCallInConstructor") - protected Client(AsyncGroup group, boolean tcp, SocketAddress address, int maxconns, - int maxPipelines, Creator> codecCreator, R pingRequest, R closeRequest, - Function, CompletableFuture> authenticate) { - if (maxPipelines < 1) throw new IllegalArgumentException("maxPipelines must bigger 0"); - this.group = group; - this.tcp = tcp; - this.address = address; - this.connLimit = maxconns; - this.maxPipelines = maxPipelines; - this.pingRequest = pingRequest; - this.closeRequest = closeRequest; - this.codecCreator = codecCreator; - this.authenticate = authenticate; - this.connArray = new ClientConnection[connLimit]; - this.connOpens = new AtomicBoolean[connLimit]; - this.connResps = new LongAdder[connLimit]; - this.connWaits = new Queue[connLimit]; - for (int i = 0; i < connOpens.length; i++) { - this.connOpens[i] = new AtomicBoolean(); - this.connResps[i] = new LongAdder(); - this.connWaits[i] = Utility.unsafe() != null ? new MpscGrowableArrayQueue<>(16, 1 << 10) : new ConcurrentLinkedDeque(); - } - //timeoutScheduler 涓嶄粎浠呯粰瓒呮椂鐢紝 杩樼粰write鐢 - this.timeoutScheduler = new ScheduledThreadPoolExecutor(1, (Runnable r) -> { - final Thread t = new Thread(r, "Redkale-" + Client.this.getClass().getSimpleName() + "-Interval-Thread"); - t.setDaemon(true); - return t; - }); - if (pingRequest != null && this.timeoutFuture == null) { - this.timeoutFuture = this.timeoutScheduler.scheduleAtFixedRate(() -> { - try { - R req = pingRequest; - if (req == null) { //鍙兘杩愯涓繘琛岄噸鏂拌祴鍊 - timeoutFuture.cancel(true); - timeoutFuture = null; - return; - } - long now = System.currentTimeMillis(); - for (ClientConnection conn : this.connArray) { - if (conn == null) continue; - if (now - conn.getLastWriteTime() < 10_000) continue; - conn.writeChannel(req).thenAccept(p -> handlePingResult(conn, p)); - } - } catch (Throwable t) { - } - }, pingInterval(), pingInterval(), TimeUnit.SECONDS); - } - } - - protected int pingInterval() { - return 30; - } - - protected void handlePingResult(ClientConnection conn, P result) { - } - - public synchronized void close() { - if (this.closed) return; - this.timeoutScheduler.shutdownNow(); - final R closereq = closeRequest; - for (ClientConnection conn : this.connArray) { - if (conn == null) continue; - if (closereq == null) { - conn.dispose(null); - } else { - try { - conn.writeChannel(closereq).get(1, TimeUnit.SECONDS); - } catch (Exception e) { - } - conn.dispose(null); - } - } - group.close(); - this.closed = true; - } - - public final CompletableFuture

sendAsync(R request) { - if (request.workThread == null) request.workThread = WorkThread.currWorkThread(); - return connect(null).thenCompose(conn -> writeChannel(conn, request)); - } - - public final CompletableFuture

sendAsync(ChannelContext context, R request) { - if (request.workThread == null) request.workThread = WorkThread.currWorkThread(); - return connect(context).thenCompose(conn -> writeChannel(conn, request)); - } - - protected CompletableFuture

writeChannel(ClientConnection conn, R request) { - return conn.writeChannel(request); - } - - protected CompletableFuture connect() { - return connect(null); - } - - protected CompletableFuture connect(final ChannelContext context) { - final boolean cflag = context != null && connectionContextName != null; - if (cflag) { - ClientConnection cc = context.getAttribute(connectionContextName); - if (cc != null && cc.isOpen()) return CompletableFuture.completedFuture(cc); - - } - int connIndex = -1; - final int size = this.connArray.length; - WorkThread workThread = WorkThread.currWorkThread(); - if (workThread != null && workThread.threads() == size) { - connIndex = workThread.index(); - } - if (connIndex >= 0) { - ClientConnection cc = this.connArray[connIndex]; - if (cc != null && cc.isOpen()) { - if (cflag) context.setAttribute(connectionContextName, cc); - return CompletableFuture.completedFuture(cc); - } - final int index = connIndex; - final Queue> waitQueue = this.connWaits[index]; - if (this.connOpens[index].compareAndSet(false, true)) { - CompletableFuture future = group.createClient(tcp, address, readTimeoutSeconds, writeTimeoutSeconds) - .thenApply(c -> createClientConnection(index, c).setMaxPipelines(maxPipelines)); - return (authenticate == null ? future : authenticate.apply(future)).thenApply(c -> { - c.authenticated = true; - this.connArray[index] = c; - CompletableFuture f; - if (cflag) context.setAttribute(connectionContextName, c); - while ((f = waitQueue.poll()) != null) { - f.complete(c); - } - return c; - }).whenComplete((r, t) -> { - if (t != null) this.connOpens[index].set(false); - }); - } else { - CompletableFuture rs = Utility.orTimeout(new CompletableFuture(), 6, TimeUnit.SECONDS); - waitQueue.offer(rs); - return rs; - } - } - ClientConnection minRunningConn = null; - for (int i = 0; i < size; i++) { - final int index = i; - final ClientConnection conn = this.connArray[index]; - if (conn == null || !conn.isOpen()) { - if (this.connOpens[index].compareAndSet(false, true)) { - CompletableFuture future = group.createClient(tcp, address, readTimeoutSeconds, writeTimeoutSeconds) - .thenApply(c -> createClientConnection(index, c).setMaxPipelines(maxPipelines)); - return (authenticate == null ? future : authenticate.apply(future)).thenApply(c -> { - c.authenticated = true; - this.connArray[index] = c; - return c; - }).whenComplete((r, t) -> { - if (t != null) this.connOpens[index].set(false); - }); - } - } else if (conn.runningCount() < 1) { - return CompletableFuture.completedFuture(conn); - } else if (minRunningConn == null || minRunningConn.runningCount() > conn.runningCount()) { - minRunningConn = conn; - } - } - if (minRunningConn != null && minRunningConn.runningCount() < maxPipelines) { - ClientConnection minConn = minRunningConn; - return CompletableFuture.completedFuture(minConn); - } - return waitClientConnection(); - } - - protected CompletableFuture waitClientConnection() { - CompletableFuture rs = Utility.orTimeout(new CompletableFuture(), 6, TimeUnit.SECONDS); - connWaits[connSeqno.getAndIncrement() % this.connLimit].offer(rs); - return rs; - } - - protected ClientConnection createClientConnection(final int index, AsyncConnection channel) { - return new ClientConnection(this, index, channel); - } - - public int getReadTimeoutSeconds() { - return readTimeoutSeconds; - } - - public void setReadTimeoutSeconds(int readTimeoutSeconds) { - this.readTimeoutSeconds = readTimeoutSeconds; - } - - public int getWriteTimeoutSeconds() { - return writeTimeoutSeconds; - } - - public void setWriteTimeoutSeconds(int writeTimeoutSeconds) { - this.writeTimeoutSeconds = writeTimeoutSeconds; - } - -} +/* + * 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.client; + +import java.net.SocketAddress; +import java.util.Queue; +import java.util.concurrent.*; +import java.util.concurrent.atomic.*; +import java.util.function.*; +import java.util.logging.*; +import org.redkale.net.*; +import org.redkale.util.*; + +/** + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @since 2.3.0 + * + * @param 璇锋眰瀵硅薄 + * @param

鍝嶅簲瀵硅薄 + */ +public abstract class Client { + + protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); + + protected final boolean finest = logger.isLoggable(Level.FINEST); + + protected final AsyncGroup group; //杩炴帴鏋勯犲櫒 + + protected final boolean tcp; //鏄惁TCP鍗忚 + + protected final SocketAddress address; //杩炴帴鐨勫湴鍧 + + protected final Creator> codecCreator; + + protected final ScheduledThreadPoolExecutor timeoutScheduler; + + protected final LongAdder writeReqCounter = new LongAdder(); + + protected final LongAdder pollRespCounter = new LongAdder(); + + private final AtomicInteger connSeqno = new AtomicInteger(); + + private boolean closed; + + protected ScheduledFuture timeoutFuture; + + protected ClientConnection[] connArray; //杩炴帴姹 + + protected LongAdder[] connResps; //杩炴帴褰撳墠澶勭悊鏁 + + protected AtomicBoolean[] connOpens; //conns鐨勬爣璁扮粍锛屽綋conn涓嶅瓨鍦ㄦ垨closed鐘舵侊紝鏍囪涓篺alse + + protected final Queue>[] connWaits; //杩炴帴绛夊緟姹 + + protected int connLimit = Utility.cpus(); //鏈澶ц繛鎺ユ暟 + + protected int maxPipelines = 16; //鍗曚釜杩炴帴鏈澶у苟琛屽鐞嗘暟 + + protected int readTimeoutSeconds; + + protected int writeTimeoutSeconds; + + protected String connectionContextName; + + //------------------ 鍙夐」 ------------------ + //PING蹇冭烦鐨勮姹傛暟鎹紝涓簄ull涓攑ingInterval<1琛ㄧず涓嶉渶瑕佸畾鏃秔ing + protected R pingRequest; + + //鍏抽棴璇锋眰鐨勬暟鎹紝 涓簄ull琛ㄧず鐩存帴鍏抽棴 + protected R closeRequest; + + //鍒涘缓杩炴帴鍚庤繘琛岀殑鐧诲綍閴存潈鎿嶄綔 + protected Function, CompletableFuture> authenticate; + + protected Client(AsyncGroup group, SocketAddress address, Creator> responseCreator) { + this(group, true, address, Utility.cpus(), 16, responseCreator, null, null, null); + } + + protected Client(AsyncGroup group, boolean tcp, SocketAddress address, Creator> codecCreator) { + this(group, tcp, address, Utility.cpus(), 16, codecCreator, null, null, null); + } + + protected Client(AsyncGroup group, boolean tcp, SocketAddress address, int maxconns, Creator> codecCreator) { + this(group, tcp, address, maxconns, 16, codecCreator, null, null, null); + } + + protected Client(AsyncGroup group, boolean tcp, SocketAddress address, int maxconns, int maxPipelines, Creator> codecCreator) { + this(group, tcp, address, maxconns, maxPipelines, codecCreator, null, null, null); + } + + protected Client(AsyncGroup group, boolean tcp, SocketAddress address, int maxconns, Creator> codecCreator, + Function, CompletableFuture> authenticate) { + this(group, tcp, address, maxconns, 16, codecCreator, null, null, authenticate); + } + + protected Client(AsyncGroup group, boolean tcp, SocketAddress address, int maxconns, Creator> codecCreator, + R closeRequest, Function, CompletableFuture> authenticate) { + this(group, tcp, address, maxconns, 16, codecCreator, null, closeRequest, authenticate); + } + + @SuppressWarnings("OverridableMethodCallInConstructor") + protected Client(AsyncGroup group, boolean tcp, SocketAddress address, int maxconns, + int maxPipelines, Creator> codecCreator, R pingRequest, R closeRequest, + Function, CompletableFuture> authenticate) { + if (maxPipelines < 1) throw new IllegalArgumentException("maxPipelines must bigger 0"); + this.group = group; + this.tcp = tcp; + this.address = address; + this.connLimit = maxconns; + this.maxPipelines = maxPipelines; + this.pingRequest = pingRequest; + this.closeRequest = closeRequest; + this.codecCreator = codecCreator; + this.authenticate = authenticate; + this.connArray = new ClientConnection[connLimit]; + this.connOpens = new AtomicBoolean[connLimit]; + this.connResps = new LongAdder[connLimit]; + this.connWaits = new Queue[connLimit]; + for (int i = 0; i < connOpens.length; i++) { + this.connOpens[i] = new AtomicBoolean(); + this.connResps[i] = new LongAdder(); + this.connWaits[i] = Utility.unsafe() != null ? new MpscGrowableArrayQueue<>(16, 1 << 10) : new ConcurrentLinkedDeque(); + } + //timeoutScheduler 涓嶄粎浠呯粰瓒呮椂鐢紝 杩樼粰write鐢 + this.timeoutScheduler = new ScheduledThreadPoolExecutor(1, (Runnable r) -> { + final Thread t = new Thread(r, "Redkale-" + Client.this.getClass().getSimpleName() + "-Interval-Thread"); + t.setDaemon(true); + return t; + }); + if (pingRequest != null && this.timeoutFuture == null) { + this.timeoutFuture = this.timeoutScheduler.scheduleAtFixedRate(() -> { + try { + R req = pingRequest; + if (req == null) { //鍙兘杩愯涓繘琛岄噸鏂拌祴鍊 + timeoutFuture.cancel(true); + timeoutFuture = null; + return; + } + long now = System.currentTimeMillis(); + for (ClientConnection conn : this.connArray) { + if (conn == null) continue; + if (now - conn.getLastWriteTime() < 10_000) continue; + conn.writeChannel(req).thenAccept(p -> handlePingResult(conn, p)); + } + } catch (Throwable t) { + } + }, pingInterval(), pingInterval(), TimeUnit.SECONDS); + } + } + + protected int pingInterval() { + return 30; + } + + protected void handlePingResult(ClientConnection conn, P result) { + } + + public synchronized void close() { + if (this.closed) return; + this.timeoutScheduler.shutdownNow(); + final R closereq = closeRequest; + for (ClientConnection conn : this.connArray) { + if (conn == null) continue; + if (closereq == null) { + conn.dispose(null); + } else { + try { + conn.writeChannel(closereq).get(1, TimeUnit.SECONDS); + } catch (Exception e) { + } + conn.dispose(null); + } + } + group.close(); + this.closed = true; + } + + public final CompletableFuture

sendAsync(R request) { + if (request.workThread == null) request.workThread = WorkThread.currWorkThread(); + return connect(null).thenCompose(conn -> writeChannel(conn, request)); + } + + public final CompletableFuture

sendAsync(ChannelContext context, R request) { + if (request.workThread == null) request.workThread = WorkThread.currWorkThread(); + return connect(context).thenCompose(conn -> writeChannel(conn, request)); + } + + protected CompletableFuture

writeChannel(ClientConnection conn, R request) { + return conn.writeChannel(request); + } + + protected CompletableFuture connect() { + return connect(null); + } + + protected CompletableFuture connect(final ChannelContext context) { + final boolean cflag = context != null && connectionContextName != null; + if (cflag) { + ClientConnection cc = context.getAttribute(connectionContextName); + if (cc != null && cc.isOpen()) return CompletableFuture.completedFuture(cc); + + } + int connIndex = -1; + final int size = this.connArray.length; + WorkThread workThread = WorkThread.currWorkThread(); + if (workThread != null && workThread.threads() == size) { + connIndex = workThread.index(); + } + if (connIndex >= 0) { + ClientConnection cc = this.connArray[connIndex]; + if (cc != null && cc.isOpen()) { + if (cflag) context.setAttribute(connectionContextName, cc); + return CompletableFuture.completedFuture(cc); + } + final int index = connIndex; + final Queue> waitQueue = this.connWaits[index]; + if (this.connOpens[index].compareAndSet(false, true)) { + CompletableFuture future = group.createClient(tcp, address, readTimeoutSeconds, writeTimeoutSeconds) + .thenApply(c -> createClientConnection(index, c).setMaxPipelines(maxPipelines)); + return (authenticate == null ? future : authenticate.apply(future)).thenApply(c -> { + c.authenticated = true; + this.connArray[index] = c; + CompletableFuture f; + if (cflag) context.setAttribute(connectionContextName, c); + while ((f = waitQueue.poll()) != null) { + f.complete(c); + } + return c; + }).whenComplete((r, t) -> { + if (t != null) this.connOpens[index].set(false); + }); + } else { + CompletableFuture rs = Utility.orTimeout(new CompletableFuture(), 6, TimeUnit.SECONDS); + waitQueue.offer(rs); + return rs; + } + } + ClientConnection minRunningConn = null; + for (int i = 0; i < size; i++) { + final int index = i; + final ClientConnection conn = this.connArray[index]; + if (conn == null || !conn.isOpen()) { + if (this.connOpens[index].compareAndSet(false, true)) { + CompletableFuture future = group.createClient(tcp, address, readTimeoutSeconds, writeTimeoutSeconds) + .thenApply(c -> createClientConnection(index, c).setMaxPipelines(maxPipelines)); + return (authenticate == null ? future : authenticate.apply(future)).thenApply(c -> { + c.authenticated = true; + this.connArray[index] = c; + return c; + }).whenComplete((r, t) -> { + if (t != null) this.connOpens[index].set(false); + }); + } + } else if (conn.runningCount() < 1) { + return CompletableFuture.completedFuture(conn); + } else if (minRunningConn == null || minRunningConn.runningCount() > conn.runningCount()) { + minRunningConn = conn; + } + } + if (minRunningConn != null && minRunningConn.runningCount() < maxPipelines) { + ClientConnection minConn = minRunningConn; + return CompletableFuture.completedFuture(minConn); + } + return waitClientConnection(); + } + + protected CompletableFuture waitClientConnection() { + CompletableFuture rs = Utility.orTimeout(new CompletableFuture(), 6, TimeUnit.SECONDS); + connWaits[connSeqno.getAndIncrement() % this.connLimit].offer(rs); + return rs; + } + + protected ClientConnection createClientConnection(final int index, AsyncConnection channel) { + return new ClientConnection(this, index, channel); + } + + public int getReadTimeoutSeconds() { + return readTimeoutSeconds; + } + + public void setReadTimeoutSeconds(int readTimeoutSeconds) { + this.readTimeoutSeconds = readTimeoutSeconds; + } + + public int getWriteTimeoutSeconds() { + return writeTimeoutSeconds; + } + + public void setWriteTimeoutSeconds(int writeTimeoutSeconds) { + this.writeTimeoutSeconds = writeTimeoutSeconds; + } + +} diff --git a/src/main/java/org/redkale/net/client/ClientCodec.java b/src/main/java/org/redkale/net/client/ClientCodec.java index cb651402b..97422fc51 100644 --- a/src/main/java/org/redkale/net/client/ClientCodec.java +++ b/src/main/java/org/redkale/net/client/ClientCodec.java @@ -1,62 +1,62 @@ -/* - * 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.client; - -import java.nio.ByteBuffer; -import java.util.*; -import org.redkale.convert.json.JsonConvert; -import org.redkale.util.ByteArray; - -/** - * 姣忎釜ClientConnection缁戝畾涓涓嫭绔嬬殑ClientCodec瀹炰緥 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @since 2.3.0 - * @param ClientRequest - * @param

鍝嶅簲瀵硅薄 - */ -public abstract class ClientCodec { - - private final List> results = new ArrayList<>(); - - public ClientCodec() { - } - - //杩斿洖true: array浼歝lear, 杩斿洖false: buffer浼歝lear - public abstract boolean codecResult(ClientConnection conn, ByteBuffer buffer, ByteArray array); - - protected Queue responseQueue(ClientConnection conn) { - return conn.responseQueue; - } - - public List> removeResults() { - if (results.isEmpty()) return null; - List> rs = new ArrayList<>(results); - this.results.clear(); - return rs; - } - - public void addResult(P result) { - this.results.add(new ClientResult<>(result)); - } - - public void addResult(Throwable exc) { - this.results.add(new ClientResult<>(exc)); - } - - public void reset() { - this.results.clear(); - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - -} +/* + * 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.client; + +import java.nio.ByteBuffer; +import java.util.*; +import org.redkale.convert.json.JsonConvert; +import org.redkale.util.ByteArray; + +/** + * 姣忎釜ClientConnection缁戝畾涓涓嫭绔嬬殑ClientCodec瀹炰緥 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @since 2.3.0 + * @param ClientRequest + * @param

鍝嶅簲瀵硅薄 + */ +public abstract class ClientCodec { + + private final List> results = new ArrayList<>(); + + public ClientCodec() { + } + + //杩斿洖true: array浼歝lear, 杩斿洖false: buffer浼歝lear + public abstract boolean codecResult(ClientConnection conn, ByteBuffer buffer, ByteArray array); + + protected Queue responseQueue(ClientConnection conn) { + return conn.responseQueue; + } + + public List> removeResults() { + if (results.isEmpty()) return null; + List> rs = new ArrayList<>(results); + this.results.clear(); + return rs; + } + + public void addResult(P result) { + this.results.add(new ClientResult<>(result)); + } + + public void addResult(Throwable exc) { + this.results.add(new ClientResult<>(exc)); + } + + public void reset() { + this.results.clear(); + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + +} diff --git a/src/main/java/org/redkale/net/client/ClientConnection.java b/src/main/java/org/redkale/net/client/ClientConnection.java index b144bafc8..8010c5ac7 100644 --- a/src/main/java/org/redkale/net/client/ClientConnection.java +++ b/src/main/java/org/redkale/net/client/ClientConnection.java @@ -1,322 +1,322 @@ -/* - * 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.client; - -import java.nio.ByteBuffer; -import java.nio.channels.*; -import java.util.*; -import java.util.concurrent.*; -import java.util.concurrent.atomic.*; -import java.util.function.*; -import java.util.logging.Level; -import org.redkale.net.*; -import org.redkale.util.*; - -/** - * 娉ㄦ剰: 瑕佺‘淇滱syncConnection鐨勮鍐欒繃绋嬮兘蹇呴』鍦╟hannel.ioThread涓繍琛 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @since 2.3.0 - * - * @param 璇锋眰瀵硅薄 - * @param

鍝嶅簲瀵硅薄 - */ -public class ClientConnection implements Consumer { - - protected final int index; //浠0寮濮嬶紝 connArray鐨勪笅鍧愭爣 - - protected final Client client; - - protected final LongAdder respCounter; - - protected final AsyncConnection channel; - - protected final ByteArray writeArray = new ByteArray(); - - protected final ByteArray readArray = new ByteArray(); - - protected final AtomicBoolean pauseWriting = new AtomicBoolean(); - - protected final AtomicBoolean readPending = new AtomicBoolean(); - - protected final AtomicBoolean writePending = new AtomicBoolean(); - - protected final Queue requestQueue = new ArrayDeque<>(); - - protected final Queue responseQueue = new ArrayDeque<>(); - - protected final CompletionHandler writeHandler = new CompletionHandler() { - - @Override - public void completed(Integer result, Void attachment) { - if (writeLastRequest != null && writeLastRequest == client.closeRequest) { - if (closeFuture != null) closeFuture.complete(null); - closeFuture = null; - return; - } - if (continueWrite(false)) return; - writePending.compareAndSet(true, false); - readChannel(); - } - - @Override - public void failed(Throwable exc, Void attachment) { - dispose(exc); - } - }; - - protected int maxPipelines; //鏈澶у苟琛屽鐞嗘暟 - - protected ClientConnection setMaxPipelines(int maxPipelines) { - this.maxPipelines = maxPipelines; - return this; - } - - protected ClientConnection resetMaxPipelines() { - this.maxPipelines = client.maxPipelines; - return this; - } - - protected void pauseWriting(boolean flag) { - this.pauseWriting.set(flag); - } - - private boolean continueWrite(boolean must) { - writeArray.clear(); - int pipelines = maxPipelines > 1 ? (maxPipelines - responseQueue.size()) : 1; - if (must && pipelines < 1) pipelines = 1; - int c = 0; - AtomicBoolean pw = this.pauseWriting; - for (int i = 0; i < pipelines; i++) { - if (pw.get()) break; - R r = requestQueue.poll(); - if (r == null) break; - writeLastRequest = r; - r.accept(this, writeArray); - c++; - } - if (c > 0) { //褰揅lient杩炴帴Server鏃跺厛浠嶴erver璇诲彇鏁版嵁鏃,浼氬厛鍙戦佷竴涓狤MPTY鐨剅equest锛岃繖鏍穡riteArray.count灏变細涓0 - channel.write(writeArray, writeHandler); - return true; - } - return false; - } - - protected void preComplete(P resp, R req, Throwable exc) { - } - - protected final CompletionHandler readHandler = new CompletionHandler() { - - ClientCodec codec; - - @Override - public void completed(Integer count, ByteBuffer attachment) { - if (count < 1) { - channel.setReadBuffer(attachment); - dispose(new NonReadableChannelException()); - return; - } - try { - if (codec == null) codec = client.codecCreator.create(); - attachment.flip(); - codecResponse(attachment); - } catch (Throwable e) { - channel.setReadBuffer(attachment); - dispose(e); - } - } - - public void codecResponse(ByteBuffer buffer) { - if (codec.codecResult(ClientConnection.this, buffer, readArray)) { //鎴愬姛浜 - readArray.clear(); - List> results = codec.removeResults(); - if (results != null) { - for (ClientResult

rs : results) { - ClientFuture respFuture = responseQueue.poll(); - if (respFuture != null) { - respCounter.decrement(); - if (isAuthenticated() && client.pollRespCounter != null) client.pollRespCounter.increment(); - try { - if (respFuture.timeout != null) respFuture.timeout.cancel(true); - ClientRequest request = respFuture.request; - //if (client.finest) client.logger.log(Level.FINEST, Utility.nowMillis() + ": " + Thread.currentThread().getName() + ": " + ClientConnection.this + ", 鍥炶皟澶勭悊, req=" + request + ", result=" + rs.result); - preComplete(rs.result, (R) request, rs.exc); - WorkThread workThread = null; - if (request != null) { - workThread = request.workThread; - request.workThread = null; - } - if (rs.exc != null) { - if (workThread == null || workThread == Thread.currentThread() - || workThread.getState() == Thread.State.BLOCKED - || workThread.getState() == Thread.State.WAITING) { - respFuture.completeExceptionally(rs.exc); - } else { - workThread.execute(() -> respFuture.completeExceptionally(rs.exc)); - } - } else { - if (workThread == null || workThread == Thread.currentThread() - || workThread.getState() == Thread.State.BLOCKED - || workThread.getState() == Thread.State.WAITING) { - respFuture.complete(rs.result); - } else { - workThread.execute(() -> respFuture.complete(rs.result)); - } - } - } catch (Throwable t) { - client.logger.log(Level.INFO, "complete result error, request: " + respFuture.request, t); - } - } - } - } - - if (buffer.hasRemaining()) { - codecResponse(buffer); - } else if (responseQueue.isEmpty()) { //闃熷垪閮藉凡澶勭悊瀹屼簡 - buffer.clear(); - channel.setReadBuffer(buffer); - if (readPending.compareAndSet(true, false)) { - //鏃犳秷鎭鐞 - } else { - channel.read(this); - } - } else { //杩樻湁娑堟伅闇瑕佽鍙 - if (!requestQueue.isEmpty() && writePending.compareAndSet(false, true)) { - //鍏堝啓鍚庤鍙 - if (!continueWrite(true)) { - writePending.compareAndSet(true, false); - } - } - buffer.clear(); - channel.setReadBuffer(buffer); - channel.read(this); - } - } else { //鏁版嵁涓嶅叏锛 缁х画璇 - buffer.clear(); - channel.setReadBuffer(buffer); - channel.read(this); - } - } - - @Override - public void failed(Throwable t, ByteBuffer attachment) { - dispose(t); - } - }; - - protected boolean authenticated; - - protected ClientFuture closeFuture; - - private R writeLastRequest; - - @SuppressWarnings("LeakingThisInConstructor") - public ClientConnection(Client client, int index, AsyncConnection channel) { - this.client = client; - this.index = index; - this.respCounter = client.connResps[index]; - this.channel = channel.beforeCloseListener(this); - } - - protected CompletableFuture

writeChannel(R request) { - ClientFuture respFuture = createClientFuture(request); - if (request == client.closeRequest) { - respFuture.request = null; - closeFuture = respFuture; - } else { - int rts = this.channel.getReadTimeoutSeconds(); - if (rts > 0 && respFuture.request != null) { - respFuture.responseQueue = responseQueue; - respFuture.timeout = client.timeoutScheduler.schedule(respFuture, rts, TimeUnit.SECONDS); - } - } - if (channel.inCurrThread()) { - writeChannelInThread(request, respFuture); - } else { - channel.execute(() -> writeChannelInThread(request, respFuture)); - } - return respFuture; - } - - private void writeChannelInThread(R request, ClientFuture respFuture) { - { //淇濊瘉椤哄簭涓鑷 - responseQueue.offer(client.closeRequest != null && respFuture.request == client.closeRequest ? ClientFuture.EMPTY : respFuture); - requestQueue.offer(request); - respCounter.increment(); - if (isAuthenticated() && client.writeReqCounter != null) client.writeReqCounter.increment(); - } - if (writePending.compareAndSet(false, true)) { - continueWrite(true); - } - } - - protected ClientFuture createClientFuture(R request) { - return new ClientFuture(request); - } - - protected void readChannel() { - if (readPending.compareAndSet(false, true)) { - readArray.clear(); - channel.read(readHandler); - } - } - - public boolean isAuthenticated() { - return authenticated; - } - - public AsyncConnection getChannel() { - return channel; - } - - @Override //AsyncConnection.beforeCloseListener - public void accept(AsyncConnection t) { - respCounter.reset(); - client.connOpens[index].set(false); - client.connArray[index] = null; //蹇呴』connflags涔嬪悗 - } - - public void dispose(Throwable exc) { - channel.dispose(); - Throwable e = exc; - CompletableFuture f; - respCounter.reset(); - while ((f = responseQueue.poll()) != null) { - if (e == null) e = new ClosedChannelException(); - f.completeExceptionally(e); - } - } - - public int runningCount() { - return respCounter.intValue(); - } - - public long getLastWriteTime() { - return channel.getLastWriteTime(); - } - - public long getLastReadTime() { - return channel.getLastReadTime(); - } - - public boolean isOpen() { - return channel.isOpen(); - } - - @Override - public String toString() { - String s = super.toString(); - int pos = s.lastIndexOf('@'); - if (pos < 1) return s; - int cha = pos + 10 - s.length(); - if (cha < 1) return s; - for (int i = 0; i < cha; i++) s += ' '; - return s; - } -} +/* + * 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.client; + +import java.nio.ByteBuffer; +import java.nio.channels.*; +import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.*; +import java.util.function.*; +import java.util.logging.Level; +import org.redkale.net.*; +import org.redkale.util.*; + +/** + * 娉ㄦ剰: 瑕佺‘淇滱syncConnection鐨勮鍐欒繃绋嬮兘蹇呴』鍦╟hannel.ioThread涓繍琛 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @since 2.3.0 + * + * @param 璇锋眰瀵硅薄 + * @param

鍝嶅簲瀵硅薄 + */ +public class ClientConnection implements Consumer { + + protected final int index; //浠0寮濮嬶紝 connArray鐨勪笅鍧愭爣 + + protected final Client client; + + protected final LongAdder respCounter; + + protected final AsyncConnection channel; + + protected final ByteArray writeArray = new ByteArray(); + + protected final ByteArray readArray = new ByteArray(); + + protected final AtomicBoolean pauseWriting = new AtomicBoolean(); + + protected final AtomicBoolean readPending = new AtomicBoolean(); + + protected final AtomicBoolean writePending = new AtomicBoolean(); + + protected final Queue requestQueue = new ArrayDeque<>(); + + protected final Queue responseQueue = new ArrayDeque<>(); + + protected final CompletionHandler writeHandler = new CompletionHandler() { + + @Override + public void completed(Integer result, Void attachment) { + if (writeLastRequest != null && writeLastRequest == client.closeRequest) { + if (closeFuture != null) closeFuture.complete(null); + closeFuture = null; + return; + } + if (continueWrite(false)) return; + writePending.compareAndSet(true, false); + readChannel(); + } + + @Override + public void failed(Throwable exc, Void attachment) { + dispose(exc); + } + }; + + protected int maxPipelines; //鏈澶у苟琛屽鐞嗘暟 + + protected ClientConnection setMaxPipelines(int maxPipelines) { + this.maxPipelines = maxPipelines; + return this; + } + + protected ClientConnection resetMaxPipelines() { + this.maxPipelines = client.maxPipelines; + return this; + } + + protected void pauseWriting(boolean flag) { + this.pauseWriting.set(flag); + } + + private boolean continueWrite(boolean must) { + writeArray.clear(); + int pipelines = maxPipelines > 1 ? (maxPipelines - responseQueue.size()) : 1; + if (must && pipelines < 1) pipelines = 1; + int c = 0; + AtomicBoolean pw = this.pauseWriting; + for (int i = 0; i < pipelines; i++) { + if (pw.get()) break; + R r = requestQueue.poll(); + if (r == null) break; + writeLastRequest = r; + r.accept(this, writeArray); + c++; + } + if (c > 0) { //褰揅lient杩炴帴Server鏃跺厛浠嶴erver璇诲彇鏁版嵁鏃,浼氬厛鍙戦佷竴涓狤MPTY鐨剅equest锛岃繖鏍穡riteArray.count灏变細涓0 + channel.write(writeArray, writeHandler); + return true; + } + return false; + } + + protected void preComplete(P resp, R req, Throwable exc) { + } + + protected final CompletionHandler readHandler = new CompletionHandler() { + + ClientCodec codec; + + @Override + public void completed(Integer count, ByteBuffer attachment) { + if (count < 1) { + channel.setReadBuffer(attachment); + dispose(new NonReadableChannelException()); + return; + } + try { + if (codec == null) codec = client.codecCreator.create(); + attachment.flip(); + codecResponse(attachment); + } catch (Throwable e) { + channel.setReadBuffer(attachment); + dispose(e); + } + } + + public void codecResponse(ByteBuffer buffer) { + if (codec.codecResult(ClientConnection.this, buffer, readArray)) { //鎴愬姛浜 + readArray.clear(); + List> results = codec.removeResults(); + if (results != null) { + for (ClientResult

rs : results) { + ClientFuture respFuture = responseQueue.poll(); + if (respFuture != null) { + respCounter.decrement(); + if (isAuthenticated() && client.pollRespCounter != null) client.pollRespCounter.increment(); + try { + if (respFuture.timeout != null) respFuture.timeout.cancel(true); + ClientRequest request = respFuture.request; + //if (client.finest) client.logger.log(Level.FINEST, Utility.nowMillis() + ": " + Thread.currentThread().getName() + ": " + ClientConnection.this + ", 鍥炶皟澶勭悊, req=" + request + ", result=" + rs.result); + preComplete(rs.result, (R) request, rs.exc); + WorkThread workThread = null; + if (request != null) { + workThread = request.workThread; + request.workThread = null; + } + if (rs.exc != null) { + if (workThread == null || workThread == Thread.currentThread() + || workThread.getState() == Thread.State.BLOCKED + || workThread.getState() == Thread.State.WAITING) { + respFuture.completeExceptionally(rs.exc); + } else { + workThread.execute(() -> respFuture.completeExceptionally(rs.exc)); + } + } else { + if (workThread == null || workThread == Thread.currentThread() + || workThread.getState() == Thread.State.BLOCKED + || workThread.getState() == Thread.State.WAITING) { + respFuture.complete(rs.result); + } else { + workThread.execute(() -> respFuture.complete(rs.result)); + } + } + } catch (Throwable t) { + client.logger.log(Level.INFO, "complete result error, request: " + respFuture.request, t); + } + } + } + } + + if (buffer.hasRemaining()) { + codecResponse(buffer); + } else if (responseQueue.isEmpty()) { //闃熷垪閮藉凡澶勭悊瀹屼簡 + buffer.clear(); + channel.setReadBuffer(buffer); + if (readPending.compareAndSet(true, false)) { + //鏃犳秷鎭鐞 + } else { + channel.read(this); + } + } else { //杩樻湁娑堟伅闇瑕佽鍙 + if (!requestQueue.isEmpty() && writePending.compareAndSet(false, true)) { + //鍏堝啓鍚庤鍙 + if (!continueWrite(true)) { + writePending.compareAndSet(true, false); + } + } + buffer.clear(); + channel.setReadBuffer(buffer); + channel.read(this); + } + } else { //鏁版嵁涓嶅叏锛 缁х画璇 + buffer.clear(); + channel.setReadBuffer(buffer); + channel.read(this); + } + } + + @Override + public void failed(Throwable t, ByteBuffer attachment) { + dispose(t); + } + }; + + protected boolean authenticated; + + protected ClientFuture closeFuture; + + private R writeLastRequest; + + @SuppressWarnings("LeakingThisInConstructor") + public ClientConnection(Client client, int index, AsyncConnection channel) { + this.client = client; + this.index = index; + this.respCounter = client.connResps[index]; + this.channel = channel.beforeCloseListener(this); + } + + protected CompletableFuture

writeChannel(R request) { + ClientFuture respFuture = createClientFuture(request); + if (request == client.closeRequest) { + respFuture.request = null; + closeFuture = respFuture; + } else { + int rts = this.channel.getReadTimeoutSeconds(); + if (rts > 0 && respFuture.request != null) { + respFuture.responseQueue = responseQueue; + respFuture.timeout = client.timeoutScheduler.schedule(respFuture, rts, TimeUnit.SECONDS); + } + } + if (channel.inCurrThread()) { + writeChannelInThread(request, respFuture); + } else { + channel.execute(() -> writeChannelInThread(request, respFuture)); + } + return respFuture; + } + + private void writeChannelInThread(R request, ClientFuture respFuture) { + { //淇濊瘉椤哄簭涓鑷 + responseQueue.offer(client.closeRequest != null && respFuture.request == client.closeRequest ? ClientFuture.EMPTY : respFuture); + requestQueue.offer(request); + respCounter.increment(); + if (isAuthenticated() && client.writeReqCounter != null) client.writeReqCounter.increment(); + } + if (writePending.compareAndSet(false, true)) { + continueWrite(true); + } + } + + protected ClientFuture createClientFuture(R request) { + return new ClientFuture(request); + } + + protected void readChannel() { + if (readPending.compareAndSet(false, true)) { + readArray.clear(); + channel.read(readHandler); + } + } + + public boolean isAuthenticated() { + return authenticated; + } + + public AsyncConnection getChannel() { + return channel; + } + + @Override //AsyncConnection.beforeCloseListener + public void accept(AsyncConnection t) { + respCounter.reset(); + client.connOpens[index].set(false); + client.connArray[index] = null; //蹇呴』connflags涔嬪悗 + } + + public void dispose(Throwable exc) { + channel.dispose(); + Throwable e = exc; + CompletableFuture f; + respCounter.reset(); + while ((f = responseQueue.poll()) != null) { + if (e == null) e = new ClosedChannelException(); + f.completeExceptionally(e); + } + } + + public int runningCount() { + return respCounter.intValue(); + } + + public long getLastWriteTime() { + return channel.getLastWriteTime(); + } + + public long getLastReadTime() { + return channel.getLastReadTime(); + } + + public boolean isOpen() { + return channel.isOpen(); + } + + @Override + public String toString() { + String s = super.toString(); + int pos = s.lastIndexOf('@'); + if (pos < 1) return s; + int cha = pos + 10 - s.length(); + if (cha < 1) return s; + for (int i = 0; i < cha; i++) s += ' '; + return s; + } +} diff --git a/src/main/java/org/redkale/net/client/ClientFuture.java b/src/main/java/org/redkale/net/client/ClientFuture.java index cc230a7be..2857b83f7 100644 --- a/src/main/java/org/redkale/net/client/ClientFuture.java +++ b/src/main/java/org/redkale/net/client/ClientFuture.java @@ -1,72 +1,72 @@ -/* - * 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.client; - -import java.util.Queue; -import java.util.concurrent.*; -import org.redkale.net.WorkThread; - -/** - * - * @author zhangjx - * @param 娉涘瀷 - */ -public class ClientFuture extends CompletableFuture implements Runnable { - - public static final ClientFuture EMPTY = new ClientFuture() { - @Override - public boolean complete(Object value) { - return true; - } - - @Override - public boolean completeExceptionally(Throwable ex) { - return true; - } - }; - - protected ClientRequest request; - - ScheduledFuture timeout; - - Queue responseQueue; - - public ClientFuture() { - super(); - } - - public ClientFuture(ClientRequest request) { - super(); - this.request = request; - } - - @Override //JDK9+ - public ClientFuture newIncompleteFuture() { - return new ClientFuture<>(); - } - - public R getRequest() { - return (R) request; - } - - @Override - public void run() { - if (responseQueue != null) responseQueue.remove(this); - TimeoutException ex = new TimeoutException(); - WorkThread workThread = null; - if (request != null) { - workThread = request.workThread; - request.workThread = null; - } - if (workThread == null || workThread == Thread.currentThread() - || workThread.getState() == Thread.State.BLOCKED - || workThread.getState() == Thread.State.WAITING) { - this.completeExceptionally(ex); - } else { - workThread.execute(() -> completeExceptionally(ex)); - } - } -} +/* + * 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.client; + +import java.util.Queue; +import java.util.concurrent.*; +import org.redkale.net.WorkThread; + +/** + * + * @author zhangjx + * @param 娉涘瀷 + */ +public class ClientFuture extends CompletableFuture implements Runnable { + + public static final ClientFuture EMPTY = new ClientFuture() { + @Override + public boolean complete(Object value) { + return true; + } + + @Override + public boolean completeExceptionally(Throwable ex) { + return true; + } + }; + + protected ClientRequest request; + + ScheduledFuture timeout; + + Queue responseQueue; + + public ClientFuture() { + super(); + } + + public ClientFuture(ClientRequest request) { + super(); + this.request = request; + } + + @Override //JDK9+ + public ClientFuture newIncompleteFuture() { + return new ClientFuture<>(); + } + + public R getRequest() { + return (R) request; + } + + @Override + public void run() { + if (responseQueue != null) responseQueue.remove(this); + TimeoutException ex = new TimeoutException(); + WorkThread workThread = null; + if (request != null) { + workThread = request.workThread; + request.workThread = null; + } + if (workThread == null || workThread == Thread.currentThread() + || workThread.getState() == Thread.State.BLOCKED + || workThread.getState() == Thread.State.WAITING) { + this.completeExceptionally(ex); + } else { + workThread.execute(() -> completeExceptionally(ex)); + } + } +} diff --git a/src/main/java/org/redkale/net/client/ClientRequest.java b/src/main/java/org/redkale/net/client/ClientRequest.java index 2f51c694c..2256dd797 100644 --- a/src/main/java/org/redkale/net/client/ClientRequest.java +++ b/src/main/java/org/redkale/net/client/ClientRequest.java @@ -1,44 +1,44 @@ -/* - * 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.client; - -import java.util.function.*; -import org.redkale.net.WorkThread; -import org.redkale.util.ByteArray; - -/** - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * - * @since 2.3.0 - */ -public abstract class ClientRequest implements BiConsumer { - - protected long createTime = System.currentTimeMillis(); - - WorkThread workThread; - - public long getCreateTime() { - return createTime; - } - - public T currThread(WorkThread thread) { - this.workThread = thread; - return (T) this; - } - - protected void prepare() { - this.createTime = System.currentTimeMillis(); - } - - protected boolean recycle() { - this.createTime = 0; - return true; - } -} +/* + * 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.client; + +import java.util.function.*; +import org.redkale.net.WorkThread; +import org.redkale.util.ByteArray; + +/** + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.3.0 + */ +public abstract class ClientRequest implements BiConsumer { + + protected long createTime = System.currentTimeMillis(); + + WorkThread workThread; + + public long getCreateTime() { + return createTime; + } + + public T currThread(WorkThread thread) { + this.workThread = thread; + return (T) this; + } + + protected void prepare() { + this.createTime = System.currentTimeMillis(); + } + + protected boolean recycle() { + this.createTime = 0; + return true; + } +} diff --git a/src/main/java/org/redkale/net/client/ClientResult.java b/src/main/java/org/redkale/net/client/ClientResult.java index 60096452c..b62a61db6 100644 --- a/src/main/java/org/redkale/net/client/ClientResult.java +++ b/src/main/java/org/redkale/net/client/ClientResult.java @@ -1,47 +1,47 @@ -/* - * 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.client; - -/** - * - * @author zhangjx - */ -public class ClientResult

{ - - protected P result; - - protected Throwable exc; - - public ClientResult(P result) { - this.result = result; - } - - public ClientResult(Throwable exc) { - this.exc = exc; - } - - public P getResult() { - return result; - } - - public void setResult(P result) { - this.result = result; - } - - public Throwable getExc() { - return exc; - } - - public void setExc(Throwable exc) { - this.exc = exc; - } - - @Override - public String toString() { - if (exc != null) return "{\"exc\":" + exc + "}"; - return "{\"result\":" + result + "}"; - } -} +/* + * 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.client; + +/** + * + * @author zhangjx + */ +public class ClientResult

{ + + protected P result; + + protected Throwable exc; + + public ClientResult(P result) { + this.result = result; + } + + public ClientResult(Throwable exc) { + this.exc = exc; + } + + public P getResult() { + return result; + } + + public void setResult(P result) { + this.result = result; + } + + public Throwable getExc() { + return exc; + } + + public void setExc(Throwable exc) { + this.exc = exc; + } + + @Override + public String toString() { + if (exc != null) return "{\"exc\":" + exc + "}"; + return "{\"result\":" + result + "}"; + } +} diff --git a/src/main/java/org/redkale/net/http/HttpClient.java b/src/main/java/org/redkale/net/http/HttpClient.java index a65156b3d..a0a2e057c 100644 --- a/src/main/java/org/redkale/net/http/HttpClient.java +++ b/src/main/java/org/redkale/net/http/HttpClient.java @@ -1,347 +1,347 @@ -/* - * 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 java.net.*; -import java.nio.ByteBuffer; -import java.nio.channels.CompletionHandler; -import java.nio.charset.*; -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import org.redkale.net.*; -import static org.redkale.net.http.HttpRequest.parseHeaderName; -import org.redkale.util.*; - -/** - * 绠鍗曠殑HttpClient瀹炵幇, 瀛樺湪浠ヤ笅鎯呭喌涓嶈兘浣跨敤姝ょ被:
- * 1銆佷娇鐢℉TTPS锛
- * 2銆佷笂浼犱笅杞芥枃浠讹紱
- * 3銆佽繑鍥炶秴澶у搷搴斿寘锛
- * 绫讳技JDK11鐨 java.net.http.HttpClient
- * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @since 2.3.0 - * - */ -public class HttpClient { - - protected final AsyncGroup asyncGroup; - - protected int readTimeoutSeconds = 6; - - protected int writeTimeoutSeconds = 6; - - protected HttpClient(AsyncGroup asyncGroup) { - this.asyncGroup = asyncGroup; - } - - public static HttpClient create(AsyncGroup asyncGroup) { - return new HttpClient(asyncGroup); - } - - public CompletableFuture> getAsync(String url) { - return sendAsync("GET", url, null, (byte[]) null); - } - - public CompletableFuture> postAsync(String url) { - return sendAsync("POST", url, null, (byte[]) null); - } - - public CompletableFuture> getAsync(String url, String body) { - return sendAsync("GET", url, null, body == null ? null : body.getBytes(StandardCharsets.UTF_8)); - } - - public CompletableFuture> postAsync(String url, String body) { - return sendAsync("POST", url, null, body == null ? null : body.getBytes(StandardCharsets.UTF_8)); - } - - public CompletableFuture> getAsync(String url, byte[] body) { - return sendAsync("GET", url, null, body); - } - - public CompletableFuture> postAsync(String url, byte[] body) { - return sendAsync("POST", url, null, body); - } - - public CompletableFuture> getAsync(String url, Map headers) { - return sendAsync("GET", url, headers, (byte[]) null); - } - - public CompletableFuture> postAsync(String url, Map headers) { - return sendAsync("POST", url, headers, (byte[]) null); - } - - public CompletableFuture> getAsync(String url, Map headers, String body) { - return sendAsync("GET", url, headers, body == null ? null : body.getBytes(StandardCharsets.UTF_8)); - } - - public CompletableFuture> postAsync(String url, Map headers, String body) { - return sendAsync("POST", url, headers, body == null ? null : body.getBytes(StandardCharsets.UTF_8)); - } - - public CompletableFuture> getAsync(String url, Map headers, byte[] body) { - return sendAsync("GET", url, headers, body); - } - - public CompletableFuture> postAsync(String url, Map headers, byte[] body) { - return sendAsync("POST", url, headers, body); - } - - public CompletableFuture> sendAsync(String method, String url, Map headers, byte[] body) { - final URI uri = URI.create(url); - final SocketAddress address = new InetSocketAddress(uri.getHost(), uri.getPort() > 0 ? uri.getPort() : (url.startsWith("https:") ? 443 : 80)); - return asyncGroup.createTCPClient(address, readTimeoutSeconds, writeTimeoutSeconds).thenCompose(conn -> { - final ByteArray array = new ByteArray(); - int urlpos = url.indexOf("/", url.indexOf("//") + 3); - array.put((method + " " + (urlpos > 0 ? url.substring(urlpos) : "/") + " HTTP/1.1\r\n" - + "Host: " + uri.getHost() + "\r\n" - + "Content-Length: " + (body == null ? 0 : body.length) + "\r\n").getBytes(StandardCharsets.UTF_8)); - if (headers == null || !headers.containsKey("User-Agent")) { - array.put(("User-Agent: redkale-httpclient/" + Redkale.getDotedVersion() + "\r\n").getBytes(StandardCharsets.UTF_8)); - } - if (headers == null || !headers.containsKey("Connection")) { - array.put(("Connection: close\r\n").getBytes(StandardCharsets.UTF_8)); - } - if (headers != null) { - headers.forEach((k, v) -> { - array.put((k + ": " + v + "\r\n").getBytes(StandardCharsets.UTF_8)); - }); - } - array.put((byte) '\r', (byte) '\n'); - if (body != null) array.put(body); - System.out.println(array); - final CompletableFuture> future = new CompletableFuture(); - conn.write(array, new CompletionHandler() { - @Override - public void completed(Integer result, Void attachment) { - conn.read(new ClientReadCompletionHandler(conn, array.clear(), future)); - } - - @Override - public void failed(Throwable exc, Void attachment) { - conn.dispose(); - future.completeExceptionally(exc); - } - }); - return future; - }); - } -// -// public static void main(String[] args) throws Throwable { -// final AsyncIOGroup asyncGroup = new AsyncIOGroup(8192, 16); -// asyncGroup.start(); -// String url = "http://redkale.org"; -// HttpClient client = HttpClient.create(asyncGroup); -// System.out.println(client.getAsync(url).join()); -// } - - protected static class ClientReadCompletionHandler implements CompletionHandler { - - protected static final int READ_STATE_ROUTE = 1; - - protected static final int READ_STATE_HEADER = 2; - - protected static final int READ_STATE_BODY = 3; - - protected static final int READ_STATE_END = 4; - - protected final AsyncConnection conn; - - protected final ByteArray array; - - protected final CompletableFuture> future; - - protected HttpResult responseResult; - - protected int readState = READ_STATE_ROUTE; - - protected int contentLength = -1; - - public ClientReadCompletionHandler(AsyncConnection conn, ByteArray array, CompletableFuture> future) { - this.conn = conn; - this.array = array; - this.future = future; - } - - @Override - public void completed(Integer count, ByteBuffer buffer) { - buffer.flip(); - if (this.readState == READ_STATE_ROUTE) { - if (this.responseResult == null) { - this.responseResult = new HttpResult<>(); - } - int rs = readStatusLine(buffer); - if (rs != 0) { - buffer.clear(); - conn.setReadBuffer(buffer); - conn.read(this); - return; - } - this.readState = READ_STATE_HEADER; - } - if (this.readState == READ_STATE_HEADER) { - int rs = readHeaderLines(buffer); - if (rs != 0) { - buffer.clear(); - conn.setReadBuffer(buffer); - conn.read(this); - return; - } - this.readState = READ_STATE_BODY; - } - if (this.readState == READ_STATE_BODY) { - if (this.contentLength > 0) { - array.put(buffer, Math.min((int) this.contentLength, buffer.remaining())); - int lr = (int) this.contentLength - array.length(); - if (lr == 0) { - this.readState = READ_STATE_END; - } else { - buffer.clear(); - conn.setReadBuffer(buffer); - conn.read(this); - return; - } - } - if (buffer.hasRemaining()) array.put(buffer, buffer.remaining()); - this.readState = READ_STATE_END; - } - this.responseResult.setResult(array.getBytes()); - this.future.complete(this.responseResult); - conn.offerBuffer(buffer); - conn.dispose(); - } - - //瑙f瀽 HTTP/1.1 200 OK - private int readStatusLine(final ByteBuffer buffer) { - int remain = buffer.remaining(); - ByteArray bytes = array; - for (;;) { - if (remain-- < 1) { - buffer.clear(); - return 1; - } - byte b = buffer.get(); - if (b == '\r') { - if (remain-- < 1) { - buffer.clear(); - buffer.put((byte) '\r'); - return 1; - } - if (buffer.get() != '\n') return -1; - break; - } - bytes.put(b); - } - String value = bytes.toString(null); - int pos = value.indexOf(' '); - this.responseResult.setStatus(Integer.decode(value.substring(pos + 1, value.indexOf(" ", pos + 2)))); - bytes.clear(); - return 0; - } - - //瑙f瀽Header Connection: keep-alive - private int readHeaderLines(final ByteBuffer buffer) { - int remain = buffer.remaining(); - ByteArray bytes = array; - HttpResult result = responseResult; - for (;;) { - bytes.clear(); - if (remain-- < 2) { - if (remain == 1) { - byte one = buffer.get(); - buffer.clear(); - buffer.put(one); - return 1; - } - buffer.clear(); - return 1; - } - remain--; - byte b1 = buffer.get(); - byte b2 = buffer.get(); - if (b1 == '\r' && b2 == '\n') return 0; - bytes.put(b1, b2); - for (;;) { // name - if (remain-- < 1) { - buffer.clear(); - buffer.put(bytes.content(), 0, bytes.length()); - return 1; - } - byte b = buffer.get(); - if (b == ':') break; - bytes.put(b); - } - String name = parseHeaderName(bytes, null); - bytes.clear(); - boolean first = true; - int space = 0; - for (;;) { // value - if (remain-- < 1) { - buffer.clear(); - buffer.put(name.getBytes()); - buffer.put((byte) ':'); - if (space == 1) { - buffer.put((byte) ' '); - } else if (space > 0) { - for (int i = 0; i < space; i++) buffer.put((byte) ' '); - } - buffer.put(bytes.content(), 0, bytes.length()); - return 1; - } - byte b = buffer.get(); - if (b == '\r') { - if (remain-- < 1) { - buffer.clear(); - buffer.put(name.getBytes()); - buffer.put((byte) ':'); - if (space == 1) { - buffer.put((byte) ' '); - } else if (space > 0) { - for (int i = 0; i < space; i++) buffer.put((byte) ' '); - } - buffer.put(bytes.content(), 0, bytes.length()); - buffer.put((byte) '\r'); - return 1; - } - if (buffer.get() != '\n') return -1; - break; - } - if (first) { - if (b <= ' ') { - space++; - continue; - } - first = false; - } - bytes.put(b); - } - String value; - switch (name) { - case "Content-Length": - case "content-length": - value = bytes.toString(null); - this.contentLength = Integer.decode(value); - result.header(name, value); - break; - default: - value = bytes.toString(null); - result.header(name, value); - } - } - } - - @Override - public void failed(Throwable exc, ByteBuffer attachment) { - conn.offerBuffer(attachment); - conn.dispose(); - future.completeExceptionally(exc); - } - - } -} +/* + * 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 java.net.*; +import java.nio.ByteBuffer; +import java.nio.channels.CompletionHandler; +import java.nio.charset.*; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import org.redkale.net.*; +import static org.redkale.net.http.HttpRequest.parseHeaderName; +import org.redkale.util.*; + +/** + * 绠鍗曠殑HttpClient瀹炵幇, 瀛樺湪浠ヤ笅鎯呭喌涓嶈兘浣跨敤姝ょ被:
+ * 1銆佷娇鐢℉TTPS锛
+ * 2銆佷笂浼犱笅杞芥枃浠讹紱
+ * 3銆佽繑鍥炶秴澶у搷搴斿寘锛
+ * 绫讳技JDK11鐨 java.net.http.HttpClient
+ * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @since 2.3.0 + * + */ +public class HttpClient { + + protected final AsyncGroup asyncGroup; + + protected int readTimeoutSeconds = 6; + + protected int writeTimeoutSeconds = 6; + + protected HttpClient(AsyncGroup asyncGroup) { + this.asyncGroup = asyncGroup; + } + + public static HttpClient create(AsyncGroup asyncGroup) { + return new HttpClient(asyncGroup); + } + + public CompletableFuture> getAsync(String url) { + return sendAsync("GET", url, null, (byte[]) null); + } + + public CompletableFuture> postAsync(String url) { + return sendAsync("POST", url, null, (byte[]) null); + } + + public CompletableFuture> getAsync(String url, String body) { + return sendAsync("GET", url, null, body == null ? null : body.getBytes(StandardCharsets.UTF_8)); + } + + public CompletableFuture> postAsync(String url, String body) { + return sendAsync("POST", url, null, body == null ? null : body.getBytes(StandardCharsets.UTF_8)); + } + + public CompletableFuture> getAsync(String url, byte[] body) { + return sendAsync("GET", url, null, body); + } + + public CompletableFuture> postAsync(String url, byte[] body) { + return sendAsync("POST", url, null, body); + } + + public CompletableFuture> getAsync(String url, Map headers) { + return sendAsync("GET", url, headers, (byte[]) null); + } + + public CompletableFuture> postAsync(String url, Map headers) { + return sendAsync("POST", url, headers, (byte[]) null); + } + + public CompletableFuture> getAsync(String url, Map headers, String body) { + return sendAsync("GET", url, headers, body == null ? null : body.getBytes(StandardCharsets.UTF_8)); + } + + public CompletableFuture> postAsync(String url, Map headers, String body) { + return sendAsync("POST", url, headers, body == null ? null : body.getBytes(StandardCharsets.UTF_8)); + } + + public CompletableFuture> getAsync(String url, Map headers, byte[] body) { + return sendAsync("GET", url, headers, body); + } + + public CompletableFuture> postAsync(String url, Map headers, byte[] body) { + return sendAsync("POST", url, headers, body); + } + + public CompletableFuture> sendAsync(String method, String url, Map headers, byte[] body) { + final URI uri = URI.create(url); + final SocketAddress address = new InetSocketAddress(uri.getHost(), uri.getPort() > 0 ? uri.getPort() : (url.startsWith("https:") ? 443 : 80)); + return asyncGroup.createTCPClient(address, readTimeoutSeconds, writeTimeoutSeconds).thenCompose(conn -> { + final ByteArray array = new ByteArray(); + int urlpos = url.indexOf("/", url.indexOf("//") + 3); + array.put((method + " " + (urlpos > 0 ? url.substring(urlpos) : "/") + " HTTP/1.1\r\n" + + "Host: " + uri.getHost() + "\r\n" + + "Content-Length: " + (body == null ? 0 : body.length) + "\r\n").getBytes(StandardCharsets.UTF_8)); + if (headers == null || !headers.containsKey("User-Agent")) { + array.put(("User-Agent: redkale-httpclient/" + Redkale.getDotedVersion() + "\r\n").getBytes(StandardCharsets.UTF_8)); + } + if (headers == null || !headers.containsKey("Connection")) { + array.put(("Connection: close\r\n").getBytes(StandardCharsets.UTF_8)); + } + if (headers != null) { + headers.forEach((k, v) -> { + array.put((k + ": " + v + "\r\n").getBytes(StandardCharsets.UTF_8)); + }); + } + array.put((byte) '\r', (byte) '\n'); + if (body != null) array.put(body); + System.out.println(array); + final CompletableFuture> future = new CompletableFuture(); + conn.write(array, new CompletionHandler() { + @Override + public void completed(Integer result, Void attachment) { + conn.read(new ClientReadCompletionHandler(conn, array.clear(), future)); + } + + @Override + public void failed(Throwable exc, Void attachment) { + conn.dispose(); + future.completeExceptionally(exc); + } + }); + return future; + }); + } +// +// public static void main(String[] args) throws Throwable { +// final AsyncIOGroup asyncGroup = new AsyncIOGroup(8192, 16); +// asyncGroup.start(); +// String url = "http://redkale.org"; +// HttpClient client = HttpClient.create(asyncGroup); +// System.out.println(client.getAsync(url).join()); +// } + + protected static class ClientReadCompletionHandler implements CompletionHandler { + + protected static final int READ_STATE_ROUTE = 1; + + protected static final int READ_STATE_HEADER = 2; + + protected static final int READ_STATE_BODY = 3; + + protected static final int READ_STATE_END = 4; + + protected final AsyncConnection conn; + + protected final ByteArray array; + + protected final CompletableFuture> future; + + protected HttpResult responseResult; + + protected int readState = READ_STATE_ROUTE; + + protected int contentLength = -1; + + public ClientReadCompletionHandler(AsyncConnection conn, ByteArray array, CompletableFuture> future) { + this.conn = conn; + this.array = array; + this.future = future; + } + + @Override + public void completed(Integer count, ByteBuffer buffer) { + buffer.flip(); + if (this.readState == READ_STATE_ROUTE) { + if (this.responseResult == null) { + this.responseResult = new HttpResult<>(); + } + int rs = readStatusLine(buffer); + if (rs != 0) { + buffer.clear(); + conn.setReadBuffer(buffer); + conn.read(this); + return; + } + this.readState = READ_STATE_HEADER; + } + if (this.readState == READ_STATE_HEADER) { + int rs = readHeaderLines(buffer); + if (rs != 0) { + buffer.clear(); + conn.setReadBuffer(buffer); + conn.read(this); + return; + } + this.readState = READ_STATE_BODY; + } + if (this.readState == READ_STATE_BODY) { + if (this.contentLength > 0) { + array.put(buffer, Math.min((int) this.contentLength, buffer.remaining())); + int lr = (int) this.contentLength - array.length(); + if (lr == 0) { + this.readState = READ_STATE_END; + } else { + buffer.clear(); + conn.setReadBuffer(buffer); + conn.read(this); + return; + } + } + if (buffer.hasRemaining()) array.put(buffer, buffer.remaining()); + this.readState = READ_STATE_END; + } + this.responseResult.setResult(array.getBytes()); + this.future.complete(this.responseResult); + conn.offerBuffer(buffer); + conn.dispose(); + } + + //瑙f瀽 HTTP/1.1 200 OK + private int readStatusLine(final ByteBuffer buffer) { + int remain = buffer.remaining(); + ByteArray bytes = array; + for (;;) { + if (remain-- < 1) { + buffer.clear(); + return 1; + } + byte b = buffer.get(); + if (b == '\r') { + if (remain-- < 1) { + buffer.clear(); + buffer.put((byte) '\r'); + return 1; + } + if (buffer.get() != '\n') return -1; + break; + } + bytes.put(b); + } + String value = bytes.toString(null); + int pos = value.indexOf(' '); + this.responseResult.setStatus(Integer.decode(value.substring(pos + 1, value.indexOf(" ", pos + 2)))); + bytes.clear(); + return 0; + } + + //瑙f瀽Header Connection: keep-alive + private int readHeaderLines(final ByteBuffer buffer) { + int remain = buffer.remaining(); + ByteArray bytes = array; + HttpResult result = responseResult; + for (;;) { + bytes.clear(); + if (remain-- < 2) { + if (remain == 1) { + byte one = buffer.get(); + buffer.clear(); + buffer.put(one); + return 1; + } + buffer.clear(); + return 1; + } + remain--; + byte b1 = buffer.get(); + byte b2 = buffer.get(); + if (b1 == '\r' && b2 == '\n') return 0; + bytes.put(b1, b2); + for (;;) { // name + if (remain-- < 1) { + buffer.clear(); + buffer.put(bytes.content(), 0, bytes.length()); + return 1; + } + byte b = buffer.get(); + if (b == ':') break; + bytes.put(b); + } + String name = parseHeaderName(bytes, null); + bytes.clear(); + boolean first = true; + int space = 0; + for (;;) { // value + if (remain-- < 1) { + buffer.clear(); + buffer.put(name.getBytes()); + buffer.put((byte) ':'); + if (space == 1) { + buffer.put((byte) ' '); + } else if (space > 0) { + for (int i = 0; i < space; i++) buffer.put((byte) ' '); + } + buffer.put(bytes.content(), 0, bytes.length()); + return 1; + } + byte b = buffer.get(); + if (b == '\r') { + if (remain-- < 1) { + buffer.clear(); + buffer.put(name.getBytes()); + buffer.put((byte) ':'); + if (space == 1) { + buffer.put((byte) ' '); + } else if (space > 0) { + for (int i = 0; i < space; i++) buffer.put((byte) ' '); + } + buffer.put(bytes.content(), 0, bytes.length()); + buffer.put((byte) '\r'); + return 1; + } + if (buffer.get() != '\n') return -1; + break; + } + if (first) { + if (b <= ' ') { + space++; + continue; + } + first = false; + } + bytes.put(b); + } + String value; + switch (name) { + case "Content-Length": + case "content-length": + value = bytes.toString(null); + this.contentLength = Integer.decode(value); + result.header(name, value); + break; + default: + value = bytes.toString(null); + result.header(name, value); + } + } + } + + @Override + public void failed(Throwable exc, ByteBuffer attachment) { + conn.offerBuffer(attachment); + conn.dispose(); + future.completeExceptionally(exc); + } + + } +} diff --git a/src/main/java/org/redkale/net/http/HttpContext.java b/src/main/java/org/redkale/net/http/HttpContext.java index 840be9474..d2fedfe19 100644 --- a/src/main/java/org/redkale/net/http/HttpContext.java +++ b/src/main/java/org/redkale/net/http/HttpContext.java @@ -1,206 +1,206 @@ -/* - * 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.asm.MethodDebugVisitor; -import java.nio.channels.CompletionHandler; -import java.security.*; -import java.util.concurrent.*; -import org.redkale.asm.*; -import static org.redkale.asm.Opcodes.*; -import org.redkale.net.*; -import org.redkale.util.*; - -/** - * HTTP鏈嶅姟鐨勪笂涓嬫枃瀵硅薄 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public class HttpContext extends Context { - - protected final SecureRandom random = new SecureRandom(); - - protected final ConcurrentHashMap asyncHandlerCreators = new ConcurrentHashMap<>(); - - protected final String remoteAddrHeader; - - protected boolean lazyHeaders; //瀛樺湪鍔ㄦ佹敼鍊 - -// protected RequestURINode[] uriCacheNodes; - public HttpContext(HttpContextConfig config) { - super(config); - this.remoteAddrHeader = config.remoteAddrHeader; - random.setSeed(Math.abs(System.nanoTime())); - } - -// protected RequestURINode[] getUriCacheNodes() { -// return uriCacheNodes; -// } -// -// protected void addRequestURINode(String path) { -// RequestURINode node = new RequestURINode(path); -// synchronized (this) { -// if (this.uriCacheNodes != null) { -// for (int i = 0; i < uriCacheNodes.length; i++) { -// if (uriCacheNodes[i].path.equals(path)) return; -// } -// } -// this.uriCacheNodes = Utility.append(this.uriCacheNodes, node); -// } -// } - protected String createSessionid() { - byte[] bytes = new byte[16]; - random.nextBytes(bytes); - return new String(Utility.binToHex(bytes)); - } - - @SuppressWarnings("unchecked") - protected Creator loadAsyncHandlerCreator(Class handlerClass) { - Creator creator = asyncHandlerCreators.get(handlerClass); - if (creator == null) { - creator = createAsyncHandlerCreator(handlerClass); - asyncHandlerCreators.put(handlerClass, creator); - } - return creator; - } - - @SuppressWarnings("unchecked") - private static synchronized Creator createAsyncHandlerCreator(Class handlerClass) { - //鐢熸垚瑙勫垯涓嶴ncpAsyncHandler.Factory 寰堢被浼 - //------------------------------------------------------------- - final boolean handlerinterface = handlerClass.isInterface(); - final String cpDesc = Type.getDescriptor(ConstructorParameters.class); - final String handlerClassName = handlerClass.getName().replace('.', '/'); - final String handlerName = CompletionHandler.class.getName().replace('.', '/'); - final String handlerDesc = Type.getDescriptor(CompletionHandler.class); - final String newDynName = "org/redkaledyn/http/handler/_DynHttpAsyncHandler__" + handlerClass.getName().replace('.', '/').replace('$', '_'); - try { - Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); - Class newHandlerClazz = clz == null ? Thread.currentThread().getContextClassLoader().loadClass(newDynName.replace('/', '.')) : clz; - return Creator.create(newHandlerClazz); - } catch (Throwable ex) { - } - // ------------------------------------------------------------------------------ - ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); - FieldVisitor fv; - MethodDebugVisitor mv; - AnnotationVisitor av0; - cw.visit(V11, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, null, handlerinterface ? "java/lang/Object" : handlerClassName, handlerinterface ? new String[]{handlerClassName} : new String[]{handlerName}); - - { //handler 灞炴 - fv = cw.visitField(ACC_PRIVATE, "handler", handlerDesc, null, null); - fv.visitEnd(); - } - {//鏋勯犳柟娉 - mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "", "(" + handlerDesc + ")V", null, null)); - //mv.setDebug(true); - { - av0 = mv.visitAnnotation(cpDesc, true); - { - AnnotationVisitor av1 = av0.visitArray("value"); - av1.visit(null, "handler"); - av1.visitEnd(); - } - av0.visitEnd(); - } - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, handlerinterface ? "java/lang/Object" : handlerClassName, "", "()V", false); - mv.visitVarInsn(ALOAD, 0); - mv.visitVarInsn(ALOAD, 1); - mv.visitFieldInsn(PUTFIELD, newDynName, "handler", handlerDesc); - mv.visitInsn(RETURN); - mv.visitMaxs(2, 2); - mv.visitEnd(); - } - - for (java.lang.reflect.Method method : handlerClass.getMethods()) { // - if ("completed".equals(method.getName()) && method.getParameterCount() == 2) { - mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "completed", Type.getMethodDescriptor(method), null, null)); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, "handler", handlerDesc); - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(ALOAD, 2); - mv.visitMethodInsn(INVOKEINTERFACE, handlerName, "completed", "(Ljava/lang/Object;Ljava/lang/Object;)V", true); - mv.visitInsn(RETURN); - mv.visitMaxs(3, 3); - mv.visitEnd(); - } else if ("failed".equals(method.getName()) && method.getParameterCount() == 2) { - mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "failed", Type.getMethodDescriptor(method), null, null)); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, "handler", handlerDesc); - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(ALOAD, 2); - mv.visitMethodInsn(INVOKEINTERFACE, handlerName, "failed", "(Ljava/lang/Throwable;Ljava/lang/Object;)V", true); - mv.visitInsn(RETURN); - mv.visitMaxs(3, 3); - mv.visitEnd(); - } else if (handlerinterface || java.lang.reflect.Modifier.isAbstract(method.getModifiers())) { - mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, method.getName(), Type.getMethodDescriptor(method), null, null)); - Class returnType = method.getReturnType(); - if (returnType == void.class) { - mv.visitInsn(RETURN); - mv.visitMaxs(0, 1); - } else if (returnType.isPrimitive()) { - mv.visitInsn(ICONST_0); - if (returnType == long.class) { - mv.visitInsn(LRETURN); - mv.visitMaxs(2, 1); - } else if (returnType == float.class) { - mv.visitInsn(FRETURN); - mv.visitMaxs(2, 1); - } else if (returnType == double.class) { - mv.visitInsn(DRETURN); - mv.visitMaxs(2, 1); - } else { - mv.visitInsn(IRETURN); - mv.visitMaxs(1, 1); - } - } else { - mv.visitInsn(ACONST_NULL); - mv.visitInsn(ARETURN); - mv.visitMaxs(1, 1); - } - mv.visitEnd(); - } - } - cw.visitEnd(); - byte[] bytes = cw.toByteArray(); - Class newClazz = (Class) new ClassLoader(handlerClass.getClassLoader()) { - public final Class loadClass(String name, byte[] b) { - return defineClass(name, b, 0, b.length); - } - }.loadClass(newDynName.replace('/', '.'), bytes); - RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, newClazz); - return (Creator) Creator.create(newClazz); - } - - public static class HttpContextConfig extends ContextConfig { - - public String remoteAddrHeader; - - } - - protected static class RequestURINode { - - public final byte[] bytes; - - public final String path; - - public RequestURINode(String path) { - this.path = path; - this.bytes = path.getBytes(); - } - - @Override - public String toString() { - return "RequestURINode{" + "path=" + path + '}'; - } - - } -} +/* + * 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.asm.MethodDebugVisitor; +import java.nio.channels.CompletionHandler; +import java.security.*; +import java.util.concurrent.*; +import org.redkale.asm.*; +import static org.redkale.asm.Opcodes.*; +import org.redkale.net.*; +import org.redkale.util.*; + +/** + * HTTP鏈嶅姟鐨勪笂涓嬫枃瀵硅薄 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public class HttpContext extends Context { + + protected final SecureRandom random = new SecureRandom(); + + protected final ConcurrentHashMap asyncHandlerCreators = new ConcurrentHashMap<>(); + + protected final String remoteAddrHeader; + + protected boolean lazyHeaders; //瀛樺湪鍔ㄦ佹敼鍊 + +// protected RequestURINode[] uriCacheNodes; + public HttpContext(HttpContextConfig config) { + super(config); + this.remoteAddrHeader = config.remoteAddrHeader; + random.setSeed(Math.abs(System.nanoTime())); + } + +// protected RequestURINode[] getUriCacheNodes() { +// return uriCacheNodes; +// } +// +// protected void addRequestURINode(String path) { +// RequestURINode node = new RequestURINode(path); +// synchronized (this) { +// if (this.uriCacheNodes != null) { +// for (int i = 0; i < uriCacheNodes.length; i++) { +// if (uriCacheNodes[i].path.equals(path)) return; +// } +// } +// this.uriCacheNodes = Utility.append(this.uriCacheNodes, node); +// } +// } + protected String createSessionid() { + byte[] bytes = new byte[16]; + random.nextBytes(bytes); + return new String(Utility.binToHex(bytes)); + } + + @SuppressWarnings("unchecked") + protected Creator loadAsyncHandlerCreator(Class handlerClass) { + Creator creator = asyncHandlerCreators.get(handlerClass); + if (creator == null) { + creator = createAsyncHandlerCreator(handlerClass); + asyncHandlerCreators.put(handlerClass, creator); + } + return creator; + } + + @SuppressWarnings("unchecked") + private static synchronized Creator createAsyncHandlerCreator(Class handlerClass) { + //鐢熸垚瑙勫垯涓嶴ncpAsyncHandler.Factory 寰堢被浼 + //------------------------------------------------------------- + final boolean handlerinterface = handlerClass.isInterface(); + final String cpDesc = Type.getDescriptor(ConstructorParameters.class); + final String handlerClassName = handlerClass.getName().replace('.', '/'); + final String handlerName = CompletionHandler.class.getName().replace('.', '/'); + final String handlerDesc = Type.getDescriptor(CompletionHandler.class); + final String newDynName = "org/redkaledyn/http/handler/_DynHttpAsyncHandler__" + handlerClass.getName().replace('.', '/').replace('$', '_'); + try { + Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); + Class newHandlerClazz = clz == null ? Thread.currentThread().getContextClassLoader().loadClass(newDynName.replace('/', '.')) : clz; + return Creator.create(newHandlerClazz); + } catch (Throwable ex) { + } + // ------------------------------------------------------------------------------ + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); + FieldVisitor fv; + MethodDebugVisitor mv; + AnnotationVisitor av0; + cw.visit(V11, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, null, handlerinterface ? "java/lang/Object" : handlerClassName, handlerinterface ? new String[]{handlerClassName} : new String[]{handlerName}); + + { //handler 灞炴 + fv = cw.visitField(ACC_PRIVATE, "handler", handlerDesc, null, null); + fv.visitEnd(); + } + {//鏋勯犳柟娉 + mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "", "(" + handlerDesc + ")V", null, null)); + //mv.setDebug(true); + { + av0 = mv.visitAnnotation(cpDesc, true); + { + AnnotationVisitor av1 = av0.visitArray("value"); + av1.visit(null, "handler"); + av1.visitEnd(); + } + av0.visitEnd(); + } + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, handlerinterface ? "java/lang/Object" : handlerClassName, "", "()V", false); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 1); + mv.visitFieldInsn(PUTFIELD, newDynName, "handler", handlerDesc); + mv.visitInsn(RETURN); + mv.visitMaxs(2, 2); + mv.visitEnd(); + } + + for (java.lang.reflect.Method method : handlerClass.getMethods()) { // + if ("completed".equals(method.getName()) && method.getParameterCount() == 2) { + mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "completed", Type.getMethodDescriptor(method), null, null)); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, "handler", handlerDesc); + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 2); + mv.visitMethodInsn(INVOKEINTERFACE, handlerName, "completed", "(Ljava/lang/Object;Ljava/lang/Object;)V", true); + mv.visitInsn(RETURN); + mv.visitMaxs(3, 3); + mv.visitEnd(); + } else if ("failed".equals(method.getName()) && method.getParameterCount() == 2) { + mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "failed", Type.getMethodDescriptor(method), null, null)); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, "handler", handlerDesc); + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 2); + mv.visitMethodInsn(INVOKEINTERFACE, handlerName, "failed", "(Ljava/lang/Throwable;Ljava/lang/Object;)V", true); + mv.visitInsn(RETURN); + mv.visitMaxs(3, 3); + mv.visitEnd(); + } else if (handlerinterface || java.lang.reflect.Modifier.isAbstract(method.getModifiers())) { + mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, method.getName(), Type.getMethodDescriptor(method), null, null)); + Class returnType = method.getReturnType(); + if (returnType == void.class) { + mv.visitInsn(RETURN); + mv.visitMaxs(0, 1); + } else if (returnType.isPrimitive()) { + mv.visitInsn(ICONST_0); + if (returnType == long.class) { + mv.visitInsn(LRETURN); + mv.visitMaxs(2, 1); + } else if (returnType == float.class) { + mv.visitInsn(FRETURN); + mv.visitMaxs(2, 1); + } else if (returnType == double.class) { + mv.visitInsn(DRETURN); + mv.visitMaxs(2, 1); + } else { + mv.visitInsn(IRETURN); + mv.visitMaxs(1, 1); + } + } else { + mv.visitInsn(ACONST_NULL); + mv.visitInsn(ARETURN); + mv.visitMaxs(1, 1); + } + mv.visitEnd(); + } + } + cw.visitEnd(); + byte[] bytes = cw.toByteArray(); + Class newClazz = (Class) new ClassLoader(handlerClass.getClassLoader()) { + public final Class loadClass(String name, byte[] b) { + return defineClass(name, b, 0, b.length); + } + }.loadClass(newDynName.replace('/', '.'), bytes); + RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, newClazz); + return (Creator) Creator.create(newClazz); + } + + public static class HttpContextConfig extends ContextConfig { + + public String remoteAddrHeader; + + } + + protected static class RequestURINode { + + public final byte[] bytes; + + public final String path; + + public RequestURINode(String path) { + this.path = path; + this.bytes = path.getBytes(); + } + + @Override + public String toString() { + return "RequestURINode{" + "path=" + path + '}'; + } + + } +} diff --git a/src/main/java/org/redkale/net/http/HttpFilter.java b/src/main/java/org/redkale/net/http/HttpFilter.java index 5a16da850..40a72bacd 100644 --- a/src/main/java/org/redkale/net/http/HttpFilter.java +++ b/src/main/java/org/redkale/net/http/HttpFilter.java @@ -1,24 +1,24 @@ -/* - * 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.Filter; -import org.redkale.util.AnyValue; - -/** - * HTTP 杩囨护鍣
- * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public abstract class HttpFilter extends Filter { - - //Server鎵цstart鍚庤繍琛屾鏂规硶 - public void postStart(HttpContext context, AnyValue config) { - } -} +/* + * 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.Filter; +import org.redkale.util.AnyValue; + +/** + * HTTP 杩囨护鍣
+ * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public abstract class HttpFilter extends Filter { + + //Server鎵цstart鍚庤繍琛屾鏂规硶 + public void postStart(HttpContext context, AnyValue config) { + } +} diff --git a/src/main/java/org/redkale/net/http/HttpMapping.java b/src/main/java/org/redkale/net/http/HttpMapping.java index 210e5ced1..6fd1534e1 100644 --- a/src/main/java/org/redkale/net/http/HttpMapping.java +++ b/src/main/java/org/redkale/net/http/HttpMapping.java @@ -1,123 +1,123 @@ -/* - * 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 java.lang.annotation.*; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * 閰嶅悎 HttpServlet 浣跨敤銆 - * 鐢ㄤ簬瀵@WebServlet瀵瑰簲鐨剈rl杩涜缁嗗垎銆 鍏秛rl蹇呴』鏄寘鍚玏ebServlet涓畾涔夌殑鍓嶇紑锛 涓斾笉鑳芥槸姝e垯琛ㄨ揪寮 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@Documented -@Target({METHOD}) -@Retention(RUNTIME) -public @interface HttpMapping { - - /** - * for OpenAPI Specification 3 - * - * @return String - */ - String name() default ""; - - /** - * 鎿嶄綔ID鍊硷紝閴存潈鏃剁敤鍒 - * - * @return int - */ - int actionid() default 0; - - /** - * 璇锋眰鍦板潃 - * - * @return String - */ - String url(); - - /** - * 缁撴灉缂撳瓨鐨勭鏁, 涓0琛ㄧず涓嶇紦瀛
- * * 褰撳煎ぇ浜0锛屽皢琚紦瀛樹竴娈垫椂闂(榛樿鍊 seconds=15绉)銆
- * 閫氬父鎯呭喌涓嬮渶瑕 auth() == true 鎵嶄娇鐢紝娌℃湁鏍囪auth==true鏂规硶涓鑸緭鍑虹殑缁撴灉涓庡綋鍓嶇敤鎴蜂俊鎭湁鍏炽
- * - * @return int - */ - int cacheseconds() default 0; - - /** - * 鏄惁鍙帴鍙桼PC璇锋眰锛 榛樿涓篺alse - * - * @return 榛樿false - */ - boolean rpconly() default false; - - /** - * 鏄惁閴存潈锛岄粯璁ら渶瑕侀壌鏉
- * - * @return boolean - */ - boolean auth() default true; - - /** - * 鍏佽鏂规硶(涓嶅尯鍒嗗ぇ灏忓啓),濡:GET/POST/PUT,涓虹┖琛ㄧず鍏佽鎵鏈夋柟娉 - * - * @return String[] - */ - String[] methods() default {}; - - /** - * 鏄惁鑳借缁ф壙, 褰 HttpServlet 琚户鎵垮悗璇ユ柟娉曟槸鍚﹁兘琚瓙绫荤户鎵 - * - * @return boolean - */ - boolean inherited() default true; - - /** - * 杈撳嚭缁撴灉鐨勬暟鎹被鍨 - * - * @return Class - */ - Class result() default void.class; - - /** - * 杈撳嚭缁撴灉鐨勬硾鍨嬫暟鎹被鍨嬪湪HttpServlet閲岀殑瀛楁鍚,涓斿瓧娈电被鍨嬪繀椤绘槸 java.lang.reflect.Type
- * 濡傛灉杈撳嚭缁撴灉鏁版嵁绫诲瀷涓嶆槸娉涘瀷锛屽垯鍊间负绌 - * - * @since 2.5.0 - * @return String - */ - String resultref() default ""; - - /** - * 杈撳嚭缁撴灉鐨勬暟鎹被鍨嬮泦鍚堬紝鐢变簬缁撴灉绫诲瀷鍙兘鏄硾鍨嬭屾敞瑙g殑鍙傛暟鍊间笉鏀寔娉涘瀷锛屽洜姝ゅ姞鍏ユ槑缁嗘暟鎹被鍨嬮泦鍚 - * - * @deprecated 2.5.0 - * @return Class[] - */ - @Deprecated - Class[] results() default {}; - - /** - * 杩斿洖缁撴灉鐨勬牱渚 - * for OpenAPI Specification 3.1.0 - * - * @return String - */ - String example() default ""; - - /** - * 澶囨敞鎻忚堪 - * - * @return String - */ - String comment() default ""; -} +/* + * 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 java.lang.annotation.*; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * 閰嶅悎 HttpServlet 浣跨敤銆 + * 鐢ㄤ簬瀵@WebServlet瀵瑰簲鐨剈rl杩涜缁嗗垎銆 鍏秛rl蹇呴』鏄寘鍚玏ebServlet涓畾涔夌殑鍓嶇紑锛 涓斾笉鑳芥槸姝e垯琛ㄨ揪寮 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@Documented +@Target({METHOD}) +@Retention(RUNTIME) +public @interface HttpMapping { + + /** + * for OpenAPI Specification 3 + * + * @return String + */ + String name() default ""; + + /** + * 鎿嶄綔ID鍊硷紝閴存潈鏃剁敤鍒 + * + * @return int + */ + int actionid() default 0; + + /** + * 璇锋眰鍦板潃 + * + * @return String + */ + String url(); + + /** + * 缁撴灉缂撳瓨鐨勭鏁, 涓0琛ㄧず涓嶇紦瀛
+ * * 褰撳煎ぇ浜0锛屽皢琚紦瀛樹竴娈垫椂闂(榛樿鍊 seconds=15绉)銆
+ * 閫氬父鎯呭喌涓嬮渶瑕 auth() == true 鎵嶄娇鐢紝娌℃湁鏍囪auth==true鏂规硶涓鑸緭鍑虹殑缁撴灉涓庡綋鍓嶇敤鎴蜂俊鎭湁鍏炽
+ * + * @return int + */ + int cacheseconds() default 0; + + /** + * 鏄惁鍙帴鍙桼PC璇锋眰锛 榛樿涓篺alse + * + * @return 榛樿false + */ + boolean rpconly() default false; + + /** + * 鏄惁閴存潈锛岄粯璁ら渶瑕侀壌鏉
+ * + * @return boolean + */ + boolean auth() default true; + + /** + * 鍏佽鏂规硶(涓嶅尯鍒嗗ぇ灏忓啓),濡:GET/POST/PUT,涓虹┖琛ㄧず鍏佽鎵鏈夋柟娉 + * + * @return String[] + */ + String[] methods() default {}; + + /** + * 鏄惁鑳借缁ф壙, 褰 HttpServlet 琚户鎵垮悗璇ユ柟娉曟槸鍚﹁兘琚瓙绫荤户鎵 + * + * @return boolean + */ + boolean inherited() default true; + + /** + * 杈撳嚭缁撴灉鐨勬暟鎹被鍨 + * + * @return Class + */ + Class result() default void.class; + + /** + * 杈撳嚭缁撴灉鐨勬硾鍨嬫暟鎹被鍨嬪湪HttpServlet閲岀殑瀛楁鍚,涓斿瓧娈电被鍨嬪繀椤绘槸 java.lang.reflect.Type
+ * 濡傛灉杈撳嚭缁撴灉鏁版嵁绫诲瀷涓嶆槸娉涘瀷锛屽垯鍊间负绌 + * + * @since 2.5.0 + * @return String + */ + String resultref() default ""; + + /** + * 杈撳嚭缁撴灉鐨勬暟鎹被鍨嬮泦鍚堬紝鐢变簬缁撴灉绫诲瀷鍙兘鏄硾鍨嬭屾敞瑙g殑鍙傛暟鍊间笉鏀寔娉涘瀷锛屽洜姝ゅ姞鍏ユ槑缁嗘暟鎹被鍨嬮泦鍚 + * + * @deprecated 2.5.0 + * @return Class[] + */ + @Deprecated + Class[] results() default {}; + + /** + * 杩斿洖缁撴灉鐨勬牱渚 + * for OpenAPI Specification 3.1.0 + * + * @return String + */ + String example() default ""; + + /** + * 澶囨敞鎻忚堪 + * + * @return String + */ + String comment() default ""; +} diff --git a/src/main/java/org/redkale/net/http/HttpParam.java b/src/main/java/org/redkale/net/http/HttpParam.java index ebf0f4077..23f8ae068 100644 --- a/src/main/java/org/redkale/net/http/HttpParam.java +++ b/src/main/java/org/redkale/net/http/HttpParam.java @@ -1,115 +1,115 @@ -/* - * 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 java.lang.annotation.*; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * 閰嶅悎 @HttpMapping 浣跨敤銆 - * 鐢ㄤ簬瀵@HttpMapping鏂规硶涓弬鏁版弿杩
- * 浠嶳estService鐢熸垚杩囨潵鐨凥ttpMapping锛屾爣璁颁负@RestUserid銆@RestAddress鐨勫弬鏁颁笉浼氱敓鎴怘ttpParam - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@Documented -@Target({METHOD}) -@Retention(RUNTIME) -@Repeatable(HttpParam.HttpParams.class) -public @interface HttpParam { - - /** - * 鍙傛暟鍚 - * - * @return String - */ - String name(); - - /** - * 鍙傛暟鐨勬暟鎹被鍨 - * - * @return Class - */ - Class type(); - - /** - * 鍙傛暟鐨勬硾鍨嬫暟鎹被鍨嬪湪HttpServlet閲岀殑瀛楁鍚,涓斿瓧娈电被鍨嬪繀椤绘槸 java.lang.reflect.Type
- * 濡傛灉鍙傛暟鏁版嵁绫诲瀷涓嶆槸娉涘瀷锛屽垯鍊间负绌 - * - * @since 2.5.0 - * @return String - */ - String typeref() default ""; - - /** - * 澶囨敞鎻忚堪 - * - * @return String - */ - String comment() default ""; - - /** - * 鍙傛暟鏉ユ簮绫诲瀷 - * - * @return HttpParameterStyle - */ - HttpParameterStyle style() default HttpParameterStyle.QUERY; - - /** - * 杞崲鏁板瓧byte/short/int/long鏃舵墍鐢ㄧ殑杩涘埗鏁帮紝 榛樿10杩涘埗 - * - * @return int - */ - int radix() default 10; - - /** - * 鍙傛暟鏄惁蹇呬紶, 妗嗘灦杩愯涓笉浣滈獙璇, only for OpenAPI Specification 3 - * - * @return boolean - */ - boolean required() default true; - - /** - * 鏄惁杩囨湡瀛楁, only for OpenAPI Specification 3 - * - * @return boolean - */ - boolean deprecated() default false; - - /** - * for OpenAPI Specification 3 - * - * @return String - */ - String example() default ""; - - /** - * 閰嶅悎 @HttpParam 浣跨敤銆 - * 鐢ㄤ簬瀵@HttpParam涓弬鏁扮殑鏉ユ簮绫诲瀷 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ - public static enum HttpParameterStyle { - - QUERY, HEADER, COOKIE, BODY; - } - - @Documented - @Target({METHOD}) - @Retention(RUNTIME) - @interface HttpParams { - - HttpParam[] value(); - } - -} +/* + * 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 java.lang.annotation.*; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * 閰嶅悎 @HttpMapping 浣跨敤銆 + * 鐢ㄤ簬瀵@HttpMapping鏂规硶涓弬鏁版弿杩
+ * 浠嶳estService鐢熸垚杩囨潵鐨凥ttpMapping锛屾爣璁颁负@RestUserid銆@RestAddress鐨勫弬鏁颁笉浼氱敓鎴怘ttpParam + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@Documented +@Target({METHOD}) +@Retention(RUNTIME) +@Repeatable(HttpParam.HttpParams.class) +public @interface HttpParam { + + /** + * 鍙傛暟鍚 + * + * @return String + */ + String name(); + + /** + * 鍙傛暟鐨勬暟鎹被鍨 + * + * @return Class + */ + Class type(); + + /** + * 鍙傛暟鐨勬硾鍨嬫暟鎹被鍨嬪湪HttpServlet閲岀殑瀛楁鍚,涓斿瓧娈电被鍨嬪繀椤绘槸 java.lang.reflect.Type
+ * 濡傛灉鍙傛暟鏁版嵁绫诲瀷涓嶆槸娉涘瀷锛屽垯鍊间负绌 + * + * @since 2.5.0 + * @return String + */ + String typeref() default ""; + + /** + * 澶囨敞鎻忚堪 + * + * @return String + */ + String comment() default ""; + + /** + * 鍙傛暟鏉ユ簮绫诲瀷 + * + * @return HttpParameterStyle + */ + HttpParameterStyle style() default HttpParameterStyle.QUERY; + + /** + * 杞崲鏁板瓧byte/short/int/long鏃舵墍鐢ㄧ殑杩涘埗鏁帮紝 榛樿10杩涘埗 + * + * @return int + */ + int radix() default 10; + + /** + * 鍙傛暟鏄惁蹇呬紶, 妗嗘灦杩愯涓笉浣滈獙璇, only for OpenAPI Specification 3 + * + * @return boolean + */ + boolean required() default true; + + /** + * 鏄惁杩囨湡瀛楁, only for OpenAPI Specification 3 + * + * @return boolean + */ + boolean deprecated() default false; + + /** + * for OpenAPI Specification 3 + * + * @return String + */ + String example() default ""; + + /** + * 閰嶅悎 @HttpParam 浣跨敤銆 + * 鐢ㄤ簬瀵@HttpParam涓弬鏁扮殑鏉ユ簮绫诲瀷 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ + public static enum HttpParameterStyle { + + QUERY, HEADER, COOKIE, BODY; + } + + @Documented + @Target({METHOD}) + @Retention(RUNTIME) + @interface HttpParams { + + HttpParam[] value(); + } + +} diff --git a/src/main/java/org/redkale/net/http/HttpPrepareServlet.java b/src/main/java/org/redkale/net/http/HttpPrepareServlet.java index c3a19ce0b..929870c0b 100644 --- a/src/main/java/org/redkale/net/http/HttpPrepareServlet.java +++ b/src/main/java/org/redkale/net/http/HttpPrepareServlet.java @@ -1,471 +1,471 @@ -/* - * 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.util.AnyValue.DefaultAnyValue; -import java.io.*; -import java.util.*; -import java.util.function.*; -import java.util.logging.*; -import java.util.regex.*; -import java.util.stream.Stream; -import org.redkale.net.*; -import org.redkale.net.http.Rest.RestDynSourceType; -import org.redkale.service.Service; -import org.redkale.util.*; - -/** - * HTTP Servlet鐨勬诲叆鍙o紝璇锋眰鍦℉ttpPrepareServlet涓繘琛屽垎娴併
- * 涓涓狧ttpServer鍙湁涓涓狧ttpPrepareServlet锛 鐢ㄤ簬绠$悊鎵鏈塇ttpServlet銆
- * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public class HttpPrepareServlet extends PrepareServlet { - - protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); - - protected HttpServlet resourceHttpServlet = new HttpResourceServlet(); - - protected MappingEntry[] regxArray = null; //regxArray 鍖呭惈 regxWsArray - - protected MappingEntry[] regxWsArray = null; - - protected Map wsmappings = new HashMap<>(); //super.mappings 鍖呭惈 wsmappings - - protected final Map allMapStrings = new HashMap<>(); - - private final Object excludeLock = new Object(); - - protected HttpContext context; - - protected boolean lazyHeaders = true; - - private Map> forbidURIMaps; //绂佺敤鐨刄RL鐨勬鍒欒〃杈惧紡, 蹇呴』涓 forbidURIPredicates 淇濇寔涓鑷 - - private BiPredicate[] forbidURIPredicates; //绂佺敤鐨刄RL鐨凱redicate, 蹇呴』涓 forbidURIMaps 淇濇寔涓鑷 - - private List removeHttpServlet(final Predicate predicateEntry, final Predicate> predicateFilter) { - List servlets = new ArrayList<>(); - synchronized (allMapStrings) { - List keys = new ArrayList<>(); - if (regxArray != null) { - for (MappingEntry me : regxArray) { - if (predicateEntry.test(me)) { - servlets.add(me.servlet); - keys.add(me.mapping); - } - } - } - if (regxWsArray != null) { - for (MappingEntry me : regxWsArray) { - if (predicateEntry.test(me)) { - servlets.add(me.servlet); - keys.add(me.mapping); - } - } - } - Map newwsmappings = new HashMap<>(); - for (Map.Entry en : wsmappings.entrySet()) { - if (predicateFilter.test(en)) { - servlets.add(en.getValue()); - keys.add(en.getKey()); - } else { - newwsmappings.put(en.getKey(), en.getValue()); - } - } - if (newwsmappings.size() != wsmappings.size()) this.wsmappings = newwsmappings; - if (!keys.isEmpty()) { - this.regxArray = Utility.remove(this.regxArray, predicateEntry); - this.regxWsArray = Utility.remove(this.regxWsArray, predicateEntry); - for (HttpServlet rs : servlets) { - super.removeServlet(rs); - } - for (String key : keys) { - super.removeMapping(key); - allMapStrings.remove(key); - } - } - } - return servlets; - } - - public HttpServlet removeHttpServlet(final HttpServlet servlet) { - Predicate predicateEntry = (t) -> t.servlet == servlet; - Predicate> predicateFilter = (t) -> t.getValue() == servlet; - removeHttpServlet(predicateEntry, predicateFilter); - return servlet; - } - - public HttpServlet removeHttpServlet(Service service) { - Predicate predicateEntry = (t) -> { - if (!Rest.isRestDyn(t.servlet)) return false; - Service s = Rest.getService(t.servlet); - if (s == service) return true; - if (s != null) return false; - Map map = Rest.getServiceMap(t.servlet); - if (map == null) return false; - boolean rs = map.values().contains(service); - if (rs && map.size() == 1) return true; - if (rs && map.size() > 1) { - String key = null; - for (Map.Entry en : map.entrySet()) { - if (en.getValue() == service) { - key = en.getKey(); - break; - } - } - if (key != null) map.remove(key); - return false; //杩樻湁鍏朵粬Resouce.name 鐨凷ervice - } - return rs; - }; - Predicate> predicateFilter = null; - List list = removeHttpServlet(predicateEntry, predicateFilter); - return list == null || list.isEmpty() ? null : list.get(0); - } - - @SuppressWarnings("unchecked") - public HttpServlet removeHttpServlet(Class websocketOrServletType) { - Predicate predicateEntry = (t) -> { - Class type = t.servlet.getClass(); - if (type == websocketOrServletType) return true; - RestDynSourceType rdt = (RestDynSourceType) type.getAnnotation(RestDynSourceType.class); - return (rdt != null && rdt.value() == websocketOrServletType); - }; - Predicate> predicateFilter = (t) -> { - Class type = t.getValue().getClass(); - if (type == websocketOrServletType) return true; - RestDynSourceType rdt = (RestDynSourceType) type.getAnnotation(RestDynSourceType.class); - return (rdt != null && rdt.value() == websocketOrServletType); - }; - List list = removeHttpServlet(predicateEntry, predicateFilter); - return list == null || list.isEmpty() ? null : list.get(0); - } - - @SuppressWarnings("unchecked") - public boolean addForbidURIReg(final String urlreg) { - if (urlreg == null || urlreg.isEmpty()) return false; - synchronized (excludeLock) { - if (forbidURIMaps != null && forbidURIMaps.containsKey(urlreg)) return false; - if (forbidURIMaps == null) forbidURIMaps = new HashMap<>(); - String mapping = urlreg; - if (Utility.contains(mapping, '*', '{', '[', '(', '|', '^', '$', '+', '?', '\\')) { //鏄惁鏄鍒欒〃杈惧紡)) - if (mapping.endsWith("/*")) { - mapping = mapping.substring(0, mapping.length() - 1) + ".*"; - } else { - mapping = mapping + "$"; - } - } - final String reg = mapping; - final boolean begin = mapping.charAt(0) == '^'; - final Predicate regPredicate = Pattern.compile(reg).asPredicate(); - BiPredicate predicate = (prefix, uri) -> { - return begin || prefix.isEmpty() ? regPredicate.test(uri) : uri.matches(prefix + reg); - }; - forbidURIMaps.put(urlreg, predicate); - forbidURIPredicates = Utility.append(forbidURIPredicates, predicate); - return true; - } - } - - @SuppressWarnings("unchecked") - public boolean removeForbidURIReg(final String urlreg) { - if (urlreg == null || urlreg.isEmpty()) return false; - synchronized (excludeLock) { - if (forbidURIMaps == null || forbidURIPredicates == null || !forbidURIMaps.containsKey(urlreg)) return false; - BiPredicate predicate = forbidURIMaps.get(urlreg); - forbidURIMaps.remove(urlreg); - int index = -1; - for (int i = 0; i < forbidURIPredicates.length; i++) { - if (forbidURIPredicates[i] == predicate) { - index = i; - break; - } - } - if (index > -1) { - if (forbidURIPredicates.length == 1) { - forbidURIPredicates = null; - } else { - int newlen = forbidURIPredicates.length - 1; - BiPredicate[] news = new BiPredicate[newlen]; - System.arraycopy(forbidURIPredicates, 0, news, 0, index); - System.arraycopy(forbidURIPredicates, index + 1, news, index, newlen - index); - forbidURIPredicates = news; - } - } - return true; - } - } - - @Override - @SuppressWarnings("unchecked") - public void init(HttpContext context, AnyValue config) { - super.init(context, config); //蹇呴』瑕佹墽琛 - this.context = context; - context.lazyHeaders = lazyHeaders; - Collection servlets = getServlets(); - servlets.forEach(s -> { - s.preInit(application, context, getServletConf(s)); - if (application == null || !application.isCompileMode()) s.init(context, getServletConf(s)); - }); - { //璁剧疆ResourceServlet - AnyValue resConfig = config.getAnyValue("resource-servlet"); - if ((resConfig instanceof DefaultAnyValue) && resConfig.getValue("webroot", "").isEmpty()) { - ((DefaultAnyValue) resConfig).addValue("webroot", config.getValue("root")); - } - if (resConfig == null) { //涓昏鐢ㄤ簬宓屽叆寮忕殑HttpServer鍒濆鍖 - DefaultAnyValue dresConfig = new DefaultAnyValue(); - dresConfig.addValue("webroot", config.getValue("root")); - dresConfig.addValue("ranges", config.getValue("ranges")); - dresConfig.addValue("cache", config.getAnyValue("cache")); - AnyValue[] rewrites = config.getAnyValues("rewrite"); - if (rewrites != null) { - for (AnyValue rewrite : rewrites) { - dresConfig.addValue("rewrite", rewrite); - } - } - resConfig = dresConfig; - } - String resServlet = resConfig.getValue("servlet", HttpResourceServlet.class.getName()); - try { - Class resClazz = Thread.currentThread().getContextClassLoader().loadClass(resServlet); - RedkaleClassLoader.putReflectionDeclaredConstructors(resClazz, resClazz.getName()); - this.resourceHttpServlet = (HttpServlet) resClazz.getDeclaredConstructor().newInstance(); - } catch (Throwable e) { - this.resourceHttpServlet = new HttpResourceServlet(); - logger.log(Level.WARNING, "init HttpResourceSerlvet(" + resServlet + ") error", e); - } - { //鑾峰彇render鐨剆uffixs - AnyValue renderConfig = config.getAnyValue("render"); - if (renderConfig != null) { - String[] suffixs = renderConfig.getValue("suffixs", ".htel").toLowerCase().split(";"); - ((HttpResourceServlet) this.resourceHttpServlet).renderSuffixs = suffixs; - } - } - context.getResourceFactory().inject(this.resourceHttpServlet); - if (application == null || !application.isCompileMode()) this.resourceHttpServlet.init(context, resConfig); - } - } - - @Override - public void execute(HttpRequest request, HttpResponse response) throws IOException { - try { - final String uri = request.getRequestURI(); - HttpServlet servlet; - if (response.isAutoOptions() && "OPTIONS".equals(request.getMethod())) { - response.finish(200, null); - return; - } - if (request.isWebSocket()) { - servlet = wsmappings.get(uri); - if (servlet == null && this.regxWsArray != null) { - for (MappingEntry en : regxWsArray) { - if (en.predicate.test(uri)) { - servlet = en.servlet; - break; - } - } - } - if (servlet == null) { - response.finish(500, null); - return; - } - } else { - servlet = mappingServlet(uri); - if (servlet == null && this.regxArray != null) { - for (MappingEntry en : regxArray) { - if (en.predicate.test(uri)) { - servlet = en.servlet; - break; - } - } - } - //鎵句笉鍒板尮閰嶇殑HttpServlet鍒欎娇鐢ㄩ潤鎬佽祫婧怘ttpResourceServlet - if (servlet == null) servlet = this.resourceHttpServlet; - } - boolean forbid = false; - BiPredicate[] forbidUrlPredicates = this.forbidURIPredicates; - if (forbidUrlPredicates != null && forbidUrlPredicates.length > 0) { - for (BiPredicate predicate : forbidUrlPredicates) { - if (predicate != null && predicate.test(servlet._prefix, uri)) { - forbid = true; - break; - } - } - } - if (forbid) { - response.finish(403, response.getHttpCode(403)); - return; - } - servlet.execute(request, response); - } catch (Exception e) { - request.getContext().getLogger().log(Level.WARNING, "Servlet occur, force to close channel. request = " + request, e); - response.finish(500, null); - } - } - - /** - * 娣诲姞HttpServlet - * - * @param servlet HttpServlet - * @param prefix url鍓嶇紑 - * @param conf 閰嶇疆淇℃伅 - * @param mappingpaths 鍖归厤瑙勫垯 - */ - @Override - public void addServlet(HttpServlet servlet, Object prefix, AnyValue conf, String... mappingpaths) { - if (prefix == null) prefix = ""; - if (mappingpaths.length < 1) { - WebServlet ws = servlet.getClass().getAnnotation(WebServlet.class); - if (ws != null) { - mappingpaths = ws.value(); - if (!ws.repair()) prefix = "";//琚缃负涓嶈嚜鍔ㄨ拷鍔犲墠缂鍒欐竻绌簆refix - } - } - if (lazyHeaders && !Rest.isSimpleRestDyn(servlet)) { - lazyHeaders = false; - if (context != null) context.lazyHeaders = false; //鍚姩鍚庤繍琛岃繃绋嬩腑鎵цaddServlet - } - synchronized (allMapStrings) { //闇瑕佹暣娈甸攣浣 - for (String mappingpath : mappingpaths) { - if (mappingpath == null) continue; - if (!prefix.toString().isEmpty()) mappingpath = prefix + mappingpath; - - if (Utility.contains(mappingpath, '*', '{', '[', '(', '|', '^', '$', '+', '?', '\\')) { //鏄惁鏄鍒欒〃杈惧紡)) - if (mappingpath.charAt(0) != '^') mappingpath = '^' + mappingpath; - if (mappingpath.endsWith("/*")) { - mappingpath = mappingpath.substring(0, mappingpath.length() - 1) + ".*"; - } else { - mappingpath = mappingpath + "$"; - } - if (regxArray == null) { - regxArray = new MappingEntry[1]; - regxArray[0] = new MappingEntry(mappingpath, Pattern.compile(mappingpath).asPredicate(), servlet); - } else { - regxArray = Arrays.copyOf(regxArray, regxArray.length + 1); - regxArray[regxArray.length - 1] = new MappingEntry(mappingpath, Pattern.compile(mappingpath).asPredicate(), servlet); - Arrays.sort(regxArray); - } - if (servlet instanceof WebSocketServlet) { - if (regxWsArray == null) { - regxWsArray = new MappingEntry[1]; - regxWsArray[0] = new MappingEntry(mappingpath, Pattern.compile(mappingpath).asPredicate(), (WebSocketServlet) servlet); - } else { - regxWsArray = Arrays.copyOf(regxWsArray, regxWsArray.length + 1); - regxWsArray[regxWsArray.length - 1] = new MappingEntry(mappingpath, Pattern.compile(mappingpath).asPredicate(), (WebSocketServlet) servlet); - Arrays.sort(regxWsArray); - } - } - } else if (mappingpath != null && !mappingpath.isEmpty()) { - if (servlet._actionmap != null && servlet._actionmap.containsKey(mappingpath)) { - //context.addRequestURINode(mappingpath); - putMapping(mappingpath, new HttpServlet.HttpActionServlet(servlet._actionmap.get(mappingpath), servlet)); - } else { - putMapping(mappingpath, servlet); - } - if (servlet instanceof WebSocketServlet) { - Map newmappings = new HashMap<>(wsmappings); - newmappings.put(mappingpath, (WebSocketServlet) servlet); - this.wsmappings = newmappings; - } - } - if (this.allMapStrings.containsKey(mappingpath)) { - Class old = this.allMapStrings.get(mappingpath); - throw new RuntimeException("mapping [" + mappingpath + "] repeat on " + old.getName() + " and " + servlet.getClass().getName()); - } - this.allMapStrings.put(mappingpath, servlet.getClass()); - } - setServletConf(servlet, conf); - servlet._prefix = prefix.toString(); - putServlet(servlet); - } - } - - /** - * 璁剧疆闈欐佽祫婧怘ttpServlet - * - * @param servlet HttpServlet - */ - public void setResourceServlet(HttpServlet servlet) { - if (servlet != null) { - this.resourceHttpServlet = servlet; - } - } - - /** - * 鑾峰彇闈欐佽祫婧怘ttpServlet - * - * @return HttpServlet - */ - public HttpServlet getResourceServlet() { - return this.resourceHttpServlet; - } - - public void postStart(HttpContext context, AnyValue config) { - List filters = getFilters(); - synchronized (filters) { - if (!filters.isEmpty()) { - for (Object filter : filters) { - ((HttpFilter) filter).postStart(context, config); - } - } - } - this.resourceHttpServlet.postStart(context, config); - getServlets().forEach(s -> { - s.postStart(context, getServletConf(s)); - }); - } - - public HttpServlet findServletByTopic(String topic) { - return filterServlets(x -> x._reqtopic != null && x._reqtopic.equals(topic)).findFirst().orElse(null); - } - - public Stream filterServletsByMmcTopic(String mmctopic) { - return filterServlets(x -> x._mmctopic != null && x._mmctopic.equals(mmctopic)); - } - - public Stream filterServlets(Predicate predicate) { - return predicate == null ? servletStream() : servletStream().filter(predicate); - } - - @Override - public void destroy(HttpContext context, AnyValue config) { - super.destroy(context, config); //蹇呴』瑕佹墽琛 - this.resourceHttpServlet.destroy(context, config); - getServlets().forEach(s -> { - s.destroy(context, getServletConf(s)); - s.postDestroy(application, context, getServletConf(s)); - }); - this.allMapStrings.clear(); - this.wsmappings.clear(); - this.regxArray = null; - this.regxWsArray = null; - } - - protected static class MappingEntry implements Comparable { - - public final String mapping; - - public final Predicate predicate; - - public final HttpServlet servlet; - - public MappingEntry(String mapping, Predicate predicate, HttpServlet servlet) { - this.mapping = mapping; - this.predicate = predicate; - this.servlet = servlet; - } - - @Override - public int compareTo(MappingEntry o) { - return o.mapping.compareTo(this.mapping); - } - - } -} +/* + * 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.util.AnyValue.DefaultAnyValue; +import java.io.*; +import java.util.*; +import java.util.function.*; +import java.util.logging.*; +import java.util.regex.*; +import java.util.stream.Stream; +import org.redkale.net.*; +import org.redkale.net.http.Rest.RestDynSourceType; +import org.redkale.service.Service; +import org.redkale.util.*; + +/** + * HTTP Servlet鐨勬诲叆鍙o紝璇锋眰鍦℉ttpPrepareServlet涓繘琛屽垎娴併
+ * 涓涓狧ttpServer鍙湁涓涓狧ttpPrepareServlet锛 鐢ㄤ簬绠$悊鎵鏈塇ttpServlet銆
+ * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public class HttpPrepareServlet extends PrepareServlet { + + protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); + + protected HttpServlet resourceHttpServlet = new HttpResourceServlet(); + + protected MappingEntry[] regxArray = null; //regxArray 鍖呭惈 regxWsArray + + protected MappingEntry[] regxWsArray = null; + + protected Map wsmappings = new HashMap<>(); //super.mappings 鍖呭惈 wsmappings + + protected final Map allMapStrings = new HashMap<>(); + + private final Object excludeLock = new Object(); + + protected HttpContext context; + + protected boolean lazyHeaders = true; + + private Map> forbidURIMaps; //绂佺敤鐨刄RL鐨勬鍒欒〃杈惧紡, 蹇呴』涓 forbidURIPredicates 淇濇寔涓鑷 + + private BiPredicate[] forbidURIPredicates; //绂佺敤鐨刄RL鐨凱redicate, 蹇呴』涓 forbidURIMaps 淇濇寔涓鑷 + + private List removeHttpServlet(final Predicate predicateEntry, final Predicate> predicateFilter) { + List servlets = new ArrayList<>(); + synchronized (allMapStrings) { + List keys = new ArrayList<>(); + if (regxArray != null) { + for (MappingEntry me : regxArray) { + if (predicateEntry.test(me)) { + servlets.add(me.servlet); + keys.add(me.mapping); + } + } + } + if (regxWsArray != null) { + for (MappingEntry me : regxWsArray) { + if (predicateEntry.test(me)) { + servlets.add(me.servlet); + keys.add(me.mapping); + } + } + } + Map newwsmappings = new HashMap<>(); + for (Map.Entry en : wsmappings.entrySet()) { + if (predicateFilter.test(en)) { + servlets.add(en.getValue()); + keys.add(en.getKey()); + } else { + newwsmappings.put(en.getKey(), en.getValue()); + } + } + if (newwsmappings.size() != wsmappings.size()) this.wsmappings = newwsmappings; + if (!keys.isEmpty()) { + this.regxArray = Utility.remove(this.regxArray, predicateEntry); + this.regxWsArray = Utility.remove(this.regxWsArray, predicateEntry); + for (HttpServlet rs : servlets) { + super.removeServlet(rs); + } + for (String key : keys) { + super.removeMapping(key); + allMapStrings.remove(key); + } + } + } + return servlets; + } + + public HttpServlet removeHttpServlet(final HttpServlet servlet) { + Predicate predicateEntry = (t) -> t.servlet == servlet; + Predicate> predicateFilter = (t) -> t.getValue() == servlet; + removeHttpServlet(predicateEntry, predicateFilter); + return servlet; + } + + public HttpServlet removeHttpServlet(Service service) { + Predicate predicateEntry = (t) -> { + if (!Rest.isRestDyn(t.servlet)) return false; + Service s = Rest.getService(t.servlet); + if (s == service) return true; + if (s != null) return false; + Map map = Rest.getServiceMap(t.servlet); + if (map == null) return false; + boolean rs = map.values().contains(service); + if (rs && map.size() == 1) return true; + if (rs && map.size() > 1) { + String key = null; + for (Map.Entry en : map.entrySet()) { + if (en.getValue() == service) { + key = en.getKey(); + break; + } + } + if (key != null) map.remove(key); + return false; //杩樻湁鍏朵粬Resouce.name 鐨凷ervice + } + return rs; + }; + Predicate> predicateFilter = null; + List list = removeHttpServlet(predicateEntry, predicateFilter); + return list == null || list.isEmpty() ? null : list.get(0); + } + + @SuppressWarnings("unchecked") + public HttpServlet removeHttpServlet(Class websocketOrServletType) { + Predicate predicateEntry = (t) -> { + Class type = t.servlet.getClass(); + if (type == websocketOrServletType) return true; + RestDynSourceType rdt = (RestDynSourceType) type.getAnnotation(RestDynSourceType.class); + return (rdt != null && rdt.value() == websocketOrServletType); + }; + Predicate> predicateFilter = (t) -> { + Class type = t.getValue().getClass(); + if (type == websocketOrServletType) return true; + RestDynSourceType rdt = (RestDynSourceType) type.getAnnotation(RestDynSourceType.class); + return (rdt != null && rdt.value() == websocketOrServletType); + }; + List list = removeHttpServlet(predicateEntry, predicateFilter); + return list == null || list.isEmpty() ? null : list.get(0); + } + + @SuppressWarnings("unchecked") + public boolean addForbidURIReg(final String urlreg) { + if (urlreg == null || urlreg.isEmpty()) return false; + synchronized (excludeLock) { + if (forbidURIMaps != null && forbidURIMaps.containsKey(urlreg)) return false; + if (forbidURIMaps == null) forbidURIMaps = new HashMap<>(); + String mapping = urlreg; + if (Utility.contains(mapping, '*', '{', '[', '(', '|', '^', '$', '+', '?', '\\')) { //鏄惁鏄鍒欒〃杈惧紡)) + if (mapping.endsWith("/*")) { + mapping = mapping.substring(0, mapping.length() - 1) + ".*"; + } else { + mapping = mapping + "$"; + } + } + final String reg = mapping; + final boolean begin = mapping.charAt(0) == '^'; + final Predicate regPredicate = Pattern.compile(reg).asPredicate(); + BiPredicate predicate = (prefix, uri) -> { + return begin || prefix.isEmpty() ? regPredicate.test(uri) : uri.matches(prefix + reg); + }; + forbidURIMaps.put(urlreg, predicate); + forbidURIPredicates = Utility.append(forbidURIPredicates, predicate); + return true; + } + } + + @SuppressWarnings("unchecked") + public boolean removeForbidURIReg(final String urlreg) { + if (urlreg == null || urlreg.isEmpty()) return false; + synchronized (excludeLock) { + if (forbidURIMaps == null || forbidURIPredicates == null || !forbidURIMaps.containsKey(urlreg)) return false; + BiPredicate predicate = forbidURIMaps.get(urlreg); + forbidURIMaps.remove(urlreg); + int index = -1; + for (int i = 0; i < forbidURIPredicates.length; i++) { + if (forbidURIPredicates[i] == predicate) { + index = i; + break; + } + } + if (index > -1) { + if (forbidURIPredicates.length == 1) { + forbidURIPredicates = null; + } else { + int newlen = forbidURIPredicates.length - 1; + BiPredicate[] news = new BiPredicate[newlen]; + System.arraycopy(forbidURIPredicates, 0, news, 0, index); + System.arraycopy(forbidURIPredicates, index + 1, news, index, newlen - index); + forbidURIPredicates = news; + } + } + return true; + } + } + + @Override + @SuppressWarnings("unchecked") + public void init(HttpContext context, AnyValue config) { + super.init(context, config); //蹇呴』瑕佹墽琛 + this.context = context; + context.lazyHeaders = lazyHeaders; + Collection servlets = getServlets(); + servlets.forEach(s -> { + s.preInit(application, context, getServletConf(s)); + if (application == null || !application.isCompileMode()) s.init(context, getServletConf(s)); + }); + { //璁剧疆ResourceServlet + AnyValue resConfig = config.getAnyValue("resource-servlet"); + if ((resConfig instanceof DefaultAnyValue) && resConfig.getValue("webroot", "").isEmpty()) { + ((DefaultAnyValue) resConfig).addValue("webroot", config.getValue("root")); + } + if (resConfig == null) { //涓昏鐢ㄤ簬宓屽叆寮忕殑HttpServer鍒濆鍖 + DefaultAnyValue dresConfig = new DefaultAnyValue(); + dresConfig.addValue("webroot", config.getValue("root")); + dresConfig.addValue("ranges", config.getValue("ranges")); + dresConfig.addValue("cache", config.getAnyValue("cache")); + AnyValue[] rewrites = config.getAnyValues("rewrite"); + if (rewrites != null) { + for (AnyValue rewrite : rewrites) { + dresConfig.addValue("rewrite", rewrite); + } + } + resConfig = dresConfig; + } + String resServlet = resConfig.getValue("servlet", HttpResourceServlet.class.getName()); + try { + Class resClazz = Thread.currentThread().getContextClassLoader().loadClass(resServlet); + RedkaleClassLoader.putReflectionDeclaredConstructors(resClazz, resClazz.getName()); + this.resourceHttpServlet = (HttpServlet) resClazz.getDeclaredConstructor().newInstance(); + } catch (Throwable e) { + this.resourceHttpServlet = new HttpResourceServlet(); + logger.log(Level.WARNING, "init HttpResourceSerlvet(" + resServlet + ") error", e); + } + { //鑾峰彇render鐨剆uffixs + AnyValue renderConfig = config.getAnyValue("render"); + if (renderConfig != null) { + String[] suffixs = renderConfig.getValue("suffixs", ".htel").toLowerCase().split(";"); + ((HttpResourceServlet) this.resourceHttpServlet).renderSuffixs = suffixs; + } + } + context.getResourceFactory().inject(this.resourceHttpServlet); + if (application == null || !application.isCompileMode()) this.resourceHttpServlet.init(context, resConfig); + } + } + + @Override + public void execute(HttpRequest request, HttpResponse response) throws IOException { + try { + final String uri = request.getRequestURI(); + HttpServlet servlet; + if (response.isAutoOptions() && "OPTIONS".equals(request.getMethod())) { + response.finish(200, null); + return; + } + if (request.isWebSocket()) { + servlet = wsmappings.get(uri); + if (servlet == null && this.regxWsArray != null) { + for (MappingEntry en : regxWsArray) { + if (en.predicate.test(uri)) { + servlet = en.servlet; + break; + } + } + } + if (servlet == null) { + response.finish(500, null); + return; + } + } else { + servlet = mappingServlet(uri); + if (servlet == null && this.regxArray != null) { + for (MappingEntry en : regxArray) { + if (en.predicate.test(uri)) { + servlet = en.servlet; + break; + } + } + } + //鎵句笉鍒板尮閰嶇殑HttpServlet鍒欎娇鐢ㄩ潤鎬佽祫婧怘ttpResourceServlet + if (servlet == null) servlet = this.resourceHttpServlet; + } + boolean forbid = false; + BiPredicate[] forbidUrlPredicates = this.forbidURIPredicates; + if (forbidUrlPredicates != null && forbidUrlPredicates.length > 0) { + for (BiPredicate predicate : forbidUrlPredicates) { + if (predicate != null && predicate.test(servlet._prefix, uri)) { + forbid = true; + break; + } + } + } + if (forbid) { + response.finish(403, response.getHttpCode(403)); + return; + } + servlet.execute(request, response); + } catch (Exception e) { + request.getContext().getLogger().log(Level.WARNING, "Servlet occur, force to close channel. request = " + request, e); + response.finish(500, null); + } + } + + /** + * 娣诲姞HttpServlet + * + * @param servlet HttpServlet + * @param prefix url鍓嶇紑 + * @param conf 閰嶇疆淇℃伅 + * @param mappingpaths 鍖归厤瑙勫垯 + */ + @Override + public void addServlet(HttpServlet servlet, Object prefix, AnyValue conf, String... mappingpaths) { + if (prefix == null) prefix = ""; + if (mappingpaths.length < 1) { + WebServlet ws = servlet.getClass().getAnnotation(WebServlet.class); + if (ws != null) { + mappingpaths = ws.value(); + if (!ws.repair()) prefix = "";//琚缃负涓嶈嚜鍔ㄨ拷鍔犲墠缂鍒欐竻绌簆refix + } + } + if (lazyHeaders && !Rest.isSimpleRestDyn(servlet)) { + lazyHeaders = false; + if (context != null) context.lazyHeaders = false; //鍚姩鍚庤繍琛岃繃绋嬩腑鎵цaddServlet + } + synchronized (allMapStrings) { //闇瑕佹暣娈甸攣浣 + for (String mappingpath : mappingpaths) { + if (mappingpath == null) continue; + if (!prefix.toString().isEmpty()) mappingpath = prefix + mappingpath; + + if (Utility.contains(mappingpath, '*', '{', '[', '(', '|', '^', '$', '+', '?', '\\')) { //鏄惁鏄鍒欒〃杈惧紡)) + if (mappingpath.charAt(0) != '^') mappingpath = '^' + mappingpath; + if (mappingpath.endsWith("/*")) { + mappingpath = mappingpath.substring(0, mappingpath.length() - 1) + ".*"; + } else { + mappingpath = mappingpath + "$"; + } + if (regxArray == null) { + regxArray = new MappingEntry[1]; + regxArray[0] = new MappingEntry(mappingpath, Pattern.compile(mappingpath).asPredicate(), servlet); + } else { + regxArray = Arrays.copyOf(regxArray, regxArray.length + 1); + regxArray[regxArray.length - 1] = new MappingEntry(mappingpath, Pattern.compile(mappingpath).asPredicate(), servlet); + Arrays.sort(regxArray); + } + if (servlet instanceof WebSocketServlet) { + if (regxWsArray == null) { + regxWsArray = new MappingEntry[1]; + regxWsArray[0] = new MappingEntry(mappingpath, Pattern.compile(mappingpath).asPredicate(), (WebSocketServlet) servlet); + } else { + regxWsArray = Arrays.copyOf(regxWsArray, regxWsArray.length + 1); + regxWsArray[regxWsArray.length - 1] = new MappingEntry(mappingpath, Pattern.compile(mappingpath).asPredicate(), (WebSocketServlet) servlet); + Arrays.sort(regxWsArray); + } + } + } else if (mappingpath != null && !mappingpath.isEmpty()) { + if (servlet._actionmap != null && servlet._actionmap.containsKey(mappingpath)) { + //context.addRequestURINode(mappingpath); + putMapping(mappingpath, new HttpServlet.HttpActionServlet(servlet._actionmap.get(mappingpath), servlet)); + } else { + putMapping(mappingpath, servlet); + } + if (servlet instanceof WebSocketServlet) { + Map newmappings = new HashMap<>(wsmappings); + newmappings.put(mappingpath, (WebSocketServlet) servlet); + this.wsmappings = newmappings; + } + } + if (this.allMapStrings.containsKey(mappingpath)) { + Class old = this.allMapStrings.get(mappingpath); + throw new RuntimeException("mapping [" + mappingpath + "] repeat on " + old.getName() + " and " + servlet.getClass().getName()); + } + this.allMapStrings.put(mappingpath, servlet.getClass()); + } + setServletConf(servlet, conf); + servlet._prefix = prefix.toString(); + putServlet(servlet); + } + } + + /** + * 璁剧疆闈欐佽祫婧怘ttpServlet + * + * @param servlet HttpServlet + */ + public void setResourceServlet(HttpServlet servlet) { + if (servlet != null) { + this.resourceHttpServlet = servlet; + } + } + + /** + * 鑾峰彇闈欐佽祫婧怘ttpServlet + * + * @return HttpServlet + */ + public HttpServlet getResourceServlet() { + return this.resourceHttpServlet; + } + + public void postStart(HttpContext context, AnyValue config) { + List filters = getFilters(); + synchronized (filters) { + if (!filters.isEmpty()) { + for (Object filter : filters) { + ((HttpFilter) filter).postStart(context, config); + } + } + } + this.resourceHttpServlet.postStart(context, config); + getServlets().forEach(s -> { + s.postStart(context, getServletConf(s)); + }); + } + + public HttpServlet findServletByTopic(String topic) { + return filterServlets(x -> x._reqtopic != null && x._reqtopic.equals(topic)).findFirst().orElse(null); + } + + public Stream filterServletsByMmcTopic(String mmctopic) { + return filterServlets(x -> x._mmctopic != null && x._mmctopic.equals(mmctopic)); + } + + public Stream filterServlets(Predicate predicate) { + return predicate == null ? servletStream() : servletStream().filter(predicate); + } + + @Override + public void destroy(HttpContext context, AnyValue config) { + super.destroy(context, config); //蹇呴』瑕佹墽琛 + this.resourceHttpServlet.destroy(context, config); + getServlets().forEach(s -> { + s.destroy(context, getServletConf(s)); + s.postDestroy(application, context, getServletConf(s)); + }); + this.allMapStrings.clear(); + this.wsmappings.clear(); + this.regxArray = null; + this.regxWsArray = null; + } + + protected static class MappingEntry implements Comparable { + + public final String mapping; + + public final Predicate predicate; + + public final HttpServlet servlet; + + public MappingEntry(String mapping, Predicate predicate, HttpServlet servlet) { + this.mapping = mapping; + this.predicate = predicate; + this.servlet = servlet; + } + + @Override + public int compareTo(MappingEntry o) { + return o.mapping.compareTo(this.mapping); + } + + } +} diff --git a/src/main/java/org/redkale/net/http/HttpRender.java b/src/main/java/org/redkale/net/http/HttpRender.java index 01fa1de93..4c0886601 100644 --- a/src/main/java/org/redkale/net/http/HttpRender.java +++ b/src/main/java/org/redkale/net/http/HttpRender.java @@ -1,35 +1,35 @@ -/* - * 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.convert.Convert; -import org.redkale.util.AnyValue; - -/** - * HTTP杈撳嚭寮曟搸鐨勫熀绫
- * HttpRender涓昏鏄粰HttpResponse.finish(Object obj)鎻愪緵鎸囧畾鏁版嵁绫诲瀷鐨勮緭鍑虹瓥鐣ャ
- *

- * HttpResponse.finish(Object obj)鍐呯疆瀵瑰涓嬫暟鎹被鍨嬭繘琛屼簡鐗规畩澶勭悊:
- *      CharSequence/String
- *      byte[]
- *      File
- *      RetResult
- *      HttpResult
- * 
- *

- * 濡傛灉瀵瑰叾浠栨暟鎹被鍨嬫湁鐗规畩杈撳嚭鐨勯渶姹傦紝鍒欓渶瑕佽嚜瀹氫箟HttpRender銆 - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public interface HttpRender { - - public void init(HttpContext context, AnyValue config); - - public void renderTo(HttpRequest request, HttpResponse response, Convert convert, HttpScope scope); - -} +/* + * 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.convert.Convert; +import org.redkale.util.AnyValue; + +/** + * HTTP杈撳嚭寮曟搸鐨勫熀绫
+ * HttpRender涓昏鏄粰HttpResponse.finish(Object obj)鎻愪緵鎸囧畾鏁版嵁绫诲瀷鐨勮緭鍑虹瓥鐣ャ
+ *

+ * HttpResponse.finish(Object obj)鍐呯疆瀵瑰涓嬫暟鎹被鍨嬭繘琛屼簡鐗规畩澶勭悊:
+ *      CharSequence/String
+ *      byte[]
+ *      File
+ *      RetResult
+ *      HttpResult
+ * 
+ *

+ * 濡傛灉瀵瑰叾浠栨暟鎹被鍨嬫湁鐗规畩杈撳嚭鐨勯渶姹傦紝鍒欓渶瑕佽嚜瀹氫箟HttpRender銆 + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public interface HttpRender { + + public void init(HttpContext context, AnyValue config); + + public void renderTo(HttpRequest request, HttpResponse response, Convert convert, HttpScope scope); + +} diff --git a/src/main/java/org/redkale/net/http/HttpRequest.java b/src/main/java/org/redkale/net/http/HttpRequest.java index 99c26d62e..d6577785d 100644 --- a/src/main/java/org/redkale/net/http/HttpRequest.java +++ b/src/main/java/org/redkale/net/http/HttpRequest.java @@ -1,2520 +1,2520 @@ -/* - * To change this license headers, 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 java.io.*; -import java.lang.annotation.Annotation; -import java.lang.reflect.Array; -import java.net.*; -import java.nio.ByteBuffer; -import java.nio.charset.*; -import java.util.*; -import java.util.function.Supplier; -import java.util.logging.Level; -import org.redkale.convert.*; -import org.redkale.convert.json.JsonConvert; -import org.redkale.net.*; -import org.redkale.util.*; - -/** - * Http璇锋眰鍖 涓巎avax.servlet.http.HttpServletRequest 鍩烘湰绫讳技銆
- * 鍚屾椂鎻愪緵json鐨勮В鏋愭帴鍙: public Object getJsonParameter(Type type, String name)
- * Redkale鎻愬″甫绠鍗曠殑鍙傛暟鐨凣ET璇锋眰閲囩敤绫讳技REST椋庢牸, 鍥犳鎻愪緵浜 getRequstURIPath 绯诲垪鎺ュ彛銆
- * 渚嬪绠鍗曠殑缈婚〉鏌ヨ
- * /pipes/user/query/offset:0/limit:20
- * 鑾峰彇椤靛彿: int offset = request.getRequstURIPath("offset:", 0);
- * 鑾峰彇琛屾暟: int limit = request.getRequstURIPath("limit:", 10);
- *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public class HttpRequest extends Request { - - private static final boolean pipelineSameHeaders = Boolean.getBoolean("redkale.http.request.pipeline.sameheaders"); - - protected static final Serializable CURRUSERID_NIL = new Serializable() { - }; - - protected static final int READ_STATE_ROUTE = 1; - - protected static final int READ_STATE_HEADER = 2; - - protected static final int READ_STATE_BODY = 3; - - protected static final int READ_STATE_END = 4; - - protected static final byte[] EMPTY_BYTES = new byte[0]; - - protected static final String KEY_GET = "GET"; - - protected static final String KEY_POST = "POST"; - - protected static final String KEY_HTTP_1_1 = "HTTP/1.1"; - - protected static final String KEY_COOKIE = "Cookie"; - - protected static final String KEY_CONNECTION = "Connection"; - - protected static final String KEY_CONTENT_TYPE = "Content-Type"; - - protected static final String KEY_ACCEPT = "Accept"; - - protected static final String KEY_HOST = "Host"; - - public static final String SESSIONID_NAME = "JSESSIONID"; - - //---------- header 鐩稿叧鍙傛暟 寮濮 ---------- - protected int headerLength; - - protected int headerHalfLen; - - protected String contentType; - - protected long contentLength = -1; - - protected String host; - - @Comment("鍘熷鐨刢ookie瀛楃涓诧紝瑙f瀽鍚庡艰祴缁橦ttpCookie[] cookies") - protected String cookie; - - protected HttpCookie[] cookies; - - private boolean maybews = false; //鏄惁鍙兘鏄疻ebSocket - - protected boolean rpc; - - protected int readState = READ_STATE_ROUTE; - - // @since 2.1.0 - protected Serializable currentUserid = CURRUSERID_NIL; - - protected Supplier currentUserSupplier; - - protected boolean frombody; - - protected ConvertType reqConvertType; - - protected Convert reqConvert; - - protected ConvertType respConvertType; - - protected Convert respConvert; - - protected final Map headers = new HashMap<>(); - //---------- header 鐩稿叧鍙傛暟 缁撴潫 ---------- - - @Comment("Method GET/POST/...") - protected String method; - - protected boolean getmethod; - - protected String protocol; - - protected String requestURI; - - protected byte[] queryBytes; - - protected String newsessionid; - - protected final Map params = new HashMap<>(); - - protected boolean boundary = false; - - protected int moduleid; - - protected int actionid; - - protected Annotation[] annotations; - - protected String remoteAddr; - - private String lastRequestURIString; - - private byte[] lastRequestURIBytes; - - private final ByteArray array; - - private byte[] headerBytes; - - private boolean headerParsed = false; - - private boolean bodyParsed = false; - - private final String remoteAddrHeader; - - HttpServlet.ActionEntry actionEntry; //浠呬緵HttpServlet浼犻扙ntry浣跨敤 - - public HttpRequest(HttpContext context) { - this(context, new ByteArray()); - } - - protected HttpRequest(HttpContext context, ByteArray array) { - super(context); - this.array = array; - this.remoteAddrHeader = context.remoteAddrHeader; - } - - @SuppressWarnings("OverridableMethodCallInConstructor") - protected HttpRequest(HttpContext context, HttpSimpleRequest req) { - super(context); - this.array = new ByteArray(); - this.remoteAddrHeader = null; - if (req != null) initSimpleRequest(req, true); - } - - protected HttpRequest initSimpleRequest(HttpSimpleRequest req, boolean needPath) { - if (req != null) { - this.rpc = req.rpc; - if (req.getBody() != null) this.array.put(req.getBody()); - if (req.getHeaders() != null) this.headers.putAll(req.getHeaders()); - this.frombody = req.isFrombody(); - this.reqConvertType = req.getReqConvertType(); - this.reqConvert = req.getReqConvertType() == null ? null : ConvertFactory.findConvert(req.getReqConvertType()); - this.respConvertType = req.getRespConvertType(); - this.respConvert = req.getRespConvertType() == null ? null : ConvertFactory.findConvert(req.getRespConvertType()); - if (req.getParams() != null) this.params.putAll(req.getParams()); - this.hashid = req.getHashid(); - if (req.getCurrentUserid() != null) this.currentUserid = req.getCurrentUserid(); - this.contentType = req.getContentType(); - this.remoteAddr = req.getRemoteAddr(); - if (needPath) { - this.requestURI = (req.getPath() == null || req.getPath().isEmpty()) ? req.getRequestURI() : (req.getPath() + req.getRequestURI()); - } else { - this.requestURI = req.getRequestURI(); - } - this.method = "POST"; - if (req.getSessionid() != null && !req.getSessionid().isEmpty()) { - this.cookies = new HttpCookie[]{new HttpCookie(SESSIONID_NAME, req.getSessionid())}; - } - } - return this; - } - - public HttpSimpleRequest createSimpleRequest(String prefix) { - HttpSimpleRequest req = new HttpSimpleRequest(); - req.setBody(array.length() == 0 ? null : array.getBytes()); - if (!getHeaders().isEmpty()) { - if (headers.containsKey(Rest.REST_HEADER_RPC_NAME) - || headers.containsKey(Rest.REST_HEADER_CURRUSERID_NAME)) { //澶栭儴request涓嶈兘鍖呭惈RPC鐨刪eader淇℃伅 - req.setHeaders(new HashMap<>(headers)); - req.removeHeader(Rest.REST_HEADER_RPC_NAME); - req.removeHeader(Rest.REST_HEADER_CURRUSERID_NAME); - } else { - req.setHeaders(headers); - } - } - parseBody(); - req.setParams(params.isEmpty() ? null : params); - req.setRemoteAddr(getRemoteAddr()); - req.setContentType(getContentType()); - req.setPath(prefix); - String uri = this.requestURI; - if (prefix != null && !prefix.isEmpty() && uri.startsWith(prefix)) { - uri = uri.substring(prefix.length()); - } - req.setHashid(this.hashid); - req.setRequestURI(uri); - req.setSessionid(getSessionid(false)); - req.setRpc(this.rpc); - return req; - } - - protected boolean isWebSocket() { - return maybews && "Upgrade".equalsIgnoreCase(getHeader("Connection")) && "GET".equalsIgnoreCase(method); - } - - protected void setPipelineOver(boolean pipelineOver) { - this.pipelineOver = pipelineOver; - } - - protected void setKeepAlive(boolean keepAlive) { - this.keepAlive = keepAlive; - } - - protected boolean isKeepAlive() { - return this.keepAlive; - } - - protected AsyncConnection getChannel() { - return this.channel; - } - - protected int getPipelineIndex() { - return this.pipelineIndex; - } - - protected int getPipelineCount() { - return this.pipelineCount; - } - - protected ConvertType getRespConvertType() { - return this.respConvertType; - } - - protected Convert getRespConvert() { - return this.respConvert == null ? this.jsonConvert : this.respConvert; - } - - @Override - protected int readHeader(final ByteBuffer buffer, final Request last) { - ByteArray bytes = array; - if (this.readState == READ_STATE_ROUTE) { - int rs = readMethodLine(buffer); - if (rs != 0) return rs; - this.readState = READ_STATE_HEADER; - } - if (this.readState == READ_STATE_HEADER) { - if (last != null && ((HttpRequest) last).headerLength > 0) { - final HttpRequest httplast = (HttpRequest) last; - int bufremain = buffer.remaining(); - int remainhalf = httplast.headerLength - this.headerHalfLen; - if (remainhalf > bufremain) { - bytes.put(buffer); - this.headerHalfLen += bufremain; - buffer.clear(); - return 1; - } - buffer.position(buffer.position() + remainhalf); - this.contentType = httplast.contentType; - this.contentLength = httplast.contentLength; - this.host = httplast.host; - this.cookie = httplast.cookie; - this.cookies = httplast.cookies; - this.keepAlive = httplast.keepAlive; - this.maybews = httplast.maybews; - this.rpc = httplast.rpc; - this.hashid = httplast.hashid; - this.currentUserid = httplast.currentUserid; - this.frombody = httplast.frombody; - this.reqConvertType = httplast.reqConvertType; - this.reqConvert = httplast.reqConvert; - this.respConvertType = httplast.respConvertType; - this.respConvert = httplast.respConvert; - this.headerLength = httplast.headerLength; - this.headerHalfLen = httplast.headerLength; - this.headerBytes = httplast.headerBytes; - this.headerParsed = httplast.headerParsed; - this.headers.putAll(httplast.headers); - } else if (context.lazyHeaders && getmethod) { //闈濭ET蹇呴』瑕佽header锛屼細鏈塁ontent-Length - int rs = loadHeaderBytes(buffer); - if (rs != 0) return rs; - this.headerParsed = false; - } else { - int startpos = buffer.position(); - int rs = readHeaderLines(buffer, bytes); - if (rs != 0) { - this.headerHalfLen = bytes.length(); - return rs; - } - this.headerParsed = true; - this.headerLength = buffer.position() - startpos + this.headerHalfLen; - this.headerHalfLen = this.headerLength; - } - bytes.clear(); - this.readState = READ_STATE_BODY; - } - if (this.contentType != null && this.contentType.contains("boundary=")) this.boundary = true; - if (this.boundary) this.keepAlive = false; //鏂囦欢涓婁紶蹇呴』璁剧疆keepAlive涓篺alse锛屽洜涓烘枃浠惰繃澶ф椂鐢ㄦ埛涓嶄竴瀹氫細skip鎺夊浣欑殑鏁版嵁 - if (this.readState == READ_STATE_BODY) { - if (this.contentLength > 0 && (this.contentType == null || !this.boundary)) { - if (this.contentLength > context.getMaxbody()) return -1; - bytes.put(buffer, Math.min((int) this.contentLength, buffer.remaining())); - int lr = (int) this.contentLength - bytes.length(); - if (lr == 0) { - this.readState = READ_STATE_END; - if (bytes.isEmpty()) this.bodyParsed = true; //no body data - } - return lr > 0 ? lr : 0; - } - if (buffer.hasRemaining() && (this.boundary || !this.keepAlive)) bytes.put(buffer, buffer.remaining()); //鏂囦欢涓婁紶銆丠TTP1.0鎴朇onnection:close - this.readState = READ_STATE_END; - if (bytes.isEmpty()) this.bodyParsed = true; //no body data - } - //鏆備笉鑰冭檻鏄痥eep-alive涓斿瓨鍦╞ody鍗存病鏈夋寚瀹欳ontent-Length鐨勬儏鍐 - return 0; - } - - private int loadHeaderBytes(final ByteBuffer buffer) { - ByteArray bytes = array; - int remain = buffer.remaining(); - byte b1, b2, b3, b4; - for (;;) { - if (remain-- < 4) { //bytes涓嶅瓨鏀綷r\n\r\n杩4涓瓧鑺 - bytes.put(buffer); - buffer.clear(); - if (bytes.length() > 0) { - byte rn1 = 0, rn2 = 0, rn3 = 0; - byte b = bytes.getLastByte(); - if (b == '\r' || b == '\n') { - rn3 = b; - bytes.backCount(); - if (bytes.length() > 0) { - b = bytes.getLastByte(); - if (b == '\r' || b == '\n') { - rn2 = b; - bytes.backCount(); - if (bytes.length() > 0) { - b = bytes.getLastByte(); - if (b == '\r' || b == '\n') { - rn1 = b; - bytes.backCount(); - } - } - } - } - } - if (rn1 != 0) buffer.put(rn1); - if (rn2 != 0) buffer.put(rn2); - if (rn3 != 0) buffer.put(rn3); - } - return 1; - } - b1 = buffer.get(); - bytes.put(b1); - if (b1 == '\r') { - remain--; - b2 = buffer.get(); - bytes.put(b2); - if (b2 == '\n') { - remain--; - b3 = buffer.get(); - bytes.put(b3); - if (b3 == '\r') { - remain--; - b4 = buffer.get(); - bytes.put(b4); - if (b4 == '\n') { - this.headerBytes = Utility.append(this.headerBytes, bytes.content(), 0, bytes.length()); - this.headerLength = this.headerBytes.length; - this.headerHalfLen = this.headerLength; - bytes.clear(); - return 0; - } - } - } - } - } - } - -// @Override -// protected int readBody(ByteBuffer buffer, int length) { -// int len = buffer.remaining(); -// array.put(buffer, len); -// return len; -// } - //瑙f瀽 GET /xxx HTTP/1.1 - private int readMethodLine(final ByteBuffer buffer) { - Charset charset = this.context.getCharset(); - int remain = buffer.remaining(); - int size; - ByteArray bytes = array; - //璇籱ethod - if (this.method == null) { - for (;;) { - if (remain-- < 1) { - buffer.clear(); - return 1; - } - byte b = buffer.get(); - if (b == ' ') break; - bytes.put(b); - } - size = bytes.length(); - if (size == 3 && bytes.get(0) == 'G' && bytes.get(1) == 'E' && bytes.get(2) == 'T') { - this.method = KEY_GET; - this.getmethod = true; - } else if (size == 4 && bytes.get(0) == 'P' && bytes.get(1) == 'O' && bytes.get(2) == 'S' && bytes.get(3) == 'T') { - this.method = KEY_POST; - this.getmethod = false; - } else { - this.method = bytes.toString(charset); - this.getmethod = false; - } - bytes.clear(); - } - //璇籾ri - if (this.requestURI == null) { - int qst = -1;//?鐨勪綅缃 - boolean decodeable = false; - for (;;) { - if (remain-- < 1) { - buffer.clear(); - return 1; - } - byte b = buffer.get(); - if (b == ' ') break; - if (b == '?' && qst < 0) { - qst = bytes.length(); - } else if (!decodeable && (b == '+' || b == '%')) { - decodeable = true; - } - bytes.put(b); - } - size = bytes.length(); - if (qst > 0) { - this.requestURI = decodeable ? toDecodeString(bytes, 0, qst, charset) : bytes.toString(0, qst, charset); - this.queryBytes = bytes.getBytes(qst + 1, size - qst - 1); - this.lastRequestURIString = null; - this.lastRequestURIBytes = null; - try { - addParameter(bytes, qst + 1, size - qst - 1); - } catch (Exception e) { - this.context.getLogger().log(Level.WARNING, "HttpRequest.addParameter error: " + bytes.toString(), e); - } - } else { - if (decodeable) { - this.requestURI = toDecodeString(bytes, 0, bytes.length(), charset); - this.lastRequestURIString = null; - this.lastRequestURIBytes = null; - } else if (context.lazyHeaders) { - byte[] lastURIBytes = lastRequestURIBytes; - if (lastURIBytes != null && lastURIBytes.length == size && bytes.equal(lastURIBytes)) { - this.requestURI = this.lastRequestURIString; - } else { - this.requestURI = bytes.toString(charset); - this.lastRequestURIString = this.requestURI; - this.lastRequestURIBytes = bytes.getBytes(); - } - } else { - this.requestURI = bytes.toString(charset); - } - this.queryBytes = EMPTY_BYTES; - } - bytes.clear(); - } - //璇籶rotocol - for (;;) { - if (remain-- < 1) { - this.params.clear(); - buffer.clear(); - return 1; - } - byte b = buffer.get(); - if (b == '\r') { - if (remain-- < 1) { - this.params.clear(); - buffer.clear(); - buffer.put((byte) '\r'); - return 1; - } - if (buffer.get() != '\n') return -1; - break; - } - bytes.put(b); - } - size = bytes.length(); - if (size == 8 && bytes.get(0) == 'H' && bytes.get(5) == '1' && bytes.get(7) == '1') { - this.protocol = KEY_HTTP_1_1; - } else { - this.protocol = bytes.toString(charset); - } - bytes.clear(); - return 0; - } - - //瑙f瀽Header Connection: keep-alive - private int readHeaderLines(final ByteBuffer buffer, ByteArray bytes) { - Charset charset = this.context.getCharset(); - int remain = buffer.remaining(); - for (;;) { - bytes.clear(); - if (remain-- < 2) { - if (remain == 1) { - byte one = buffer.get(); - buffer.clear(); - buffer.put(one); - return 1; - } - buffer.clear(); - return 1; - } - remain--; - byte b1 = buffer.get(); - byte b2 = buffer.get(); - if (b1 == '\r' && b2 == '\n') return 0; - bytes.put(b1, b2); - for (;;) { // name - if (remain-- < 1) { - buffer.clear(); - buffer.put(bytes.content(), 0, bytes.length()); - return 1; - } - byte b = buffer.get(); - if (b == ':') break; - bytes.put(b); - } - String name = parseHeaderName(bytes, charset); - bytes.clear(); - boolean first = true; - int space = 0; - for (;;) { // value - if (remain-- < 1) { - buffer.clear(); - buffer.put(name.getBytes()); - buffer.put((byte) ':'); - if (space == 1) { - buffer.put((byte) ' '); - } else if (space > 0) { - for (int i = 0; i < space; i++) buffer.put((byte) ' '); - } - buffer.put(bytes.content(), 0, bytes.length()); - return 1; - } - byte b = buffer.get(); - if (b == '\r') { - if (remain-- < 1) { - buffer.clear(); - buffer.put(name.getBytes()); - buffer.put((byte) ':'); - if (space == 1) { - buffer.put((byte) ' '); - } else if (space > 0) { - for (int i = 0; i < space; i++) buffer.put((byte) ' '); - } - buffer.put(bytes.content(), 0, bytes.length()); - buffer.put((byte) '\r'); - return 1; - } - if (buffer.get() != '\n') return -1; - break; - } - if (first) { - if (b <= ' ') { - space++; - continue; - } - first = false; - } - bytes.put(b); - } - String value; - int vallen = bytes.length(); - switch (name) { - case "Content-Type": - case "content-type": - value = bytes.toString(charset); - this.contentType = value; - break; - case "Content-Length": - case "content-length": - value = bytes.toString(charset); - this.contentLength = Long.decode(value); - break; - case "Host": - case "host": - value = bytes.toString(charset); - this.host = value; - break; - case "Cookie": - case "cookie": - value = bytes.toString(charset); - if (this.cookie == null || this.cookie.isEmpty()) { - this.cookie = value; - } else { - this.cookie += ";" + value; - } - break; - case "Connection": - case "connection": - if (vallen > 0) { - if (bytes.get(0) == 'c' && vallen == 5 - && bytes.get(1) == 'l' && bytes.get(2) == 'o' - && bytes.get(3) == 's' && bytes.get(4) == 'e') { - value = "close"; - this.setKeepAlive(false); - } else if (bytes.get(0) == 'k' && vallen == 10 - && bytes.get(1) == 'e' && bytes.get(2) == 'e' - && bytes.get(3) == 'p' && bytes.get(4) == '-' - && bytes.get(5) == 'a' && bytes.get(6) == 'l' - && bytes.get(7) == 'i' && bytes.get(8) == 'v' - && bytes.get(9) == 'e') { - value = "keep-alive"; - //if (context.getAliveTimeoutSeconds() >= 0) { - this.setKeepAlive(true); - //} - } else { - value = bytes.toString(charset); - this.setKeepAlive(true); - } - } else { - value = ""; - } - headers.put("Connection", value); - break; - case "Upgrade": - case "upgrade": - value = bytes.toString(charset); - this.maybews = "websocket".equalsIgnoreCase(value); - headers.put("Upgrade", value); - break; - case "user-agent": - value = bytes.toString(charset); - headers.put("User-Agent", value); - break; - case Rest.REST_HEADER_RPC_NAME: - value = bytes.toString(charset); - this.rpc = "true".equalsIgnoreCase(value); - headers.put(name, value); - break; - case Rest.REST_HEADER_CURRUSERID_NAME: - value = bytes.toString(charset); - this.hashid = value.hashCode(); - this.currentUserid = value; - headers.put(name, value); - break; - case Rest.REST_HEADER_PARAM_FROM_BODY: - value = bytes.toString(charset); - this.frombody = "true".equalsIgnoreCase(value); - headers.put(name, value); - break; - case Rest.REST_HEADER_REQ_CONVERT_TYPE: - value = bytes.toString(charset); - reqConvertType = ConvertType.valueOf(value); - reqConvert = ConvertFactory.findConvert(reqConvertType); - headers.put(name, value); - break; - case Rest.REST_HEADER_RESP_CONVERT_TYPE: - value = bytes.toString(charset); - respConvertType = ConvertType.valueOf(value); - respConvert = ConvertFactory.findConvert(respConvertType); - headers.put(name, value); - break; - default: - value = bytes.toString(charset); - headers.put(name, value); - } - } - } - - private void parseHeader() { - if (headerParsed) return; - headerParsed = true; - if (headerBytes == null) return; - if (array.isEmpty()) { - readHeaderLines(ByteBuffer.wrap(headerBytes), array); - array.clear(); - } else { //array瀛樻湁body鏁版嵁 - readHeaderLines(ByteBuffer.wrap(headerBytes), new ByteArray()); - } - } - - static String parseHeaderName(ByteArray bytes, Charset charset) { - final int size = bytes.length(); - final byte[] bs = bytes.content(); - final byte first = bs[0]; - if (first == 'H' && size == 4) { //Host - if (bs[1] == 'o' && bs[2] == 's' && bs[3] == 't') return KEY_HOST; - } else if (first == 'A' && size == 6) { //Accept - if (bs[1] == 'c' && bs[2] == 'c' && bs[3] == 'e' - && bs[4] == 'p' && bs[5] == 't') return KEY_ACCEPT; - } else if (first == 'C') { - if (size == 10) { //Connection - if (bs[1] == 'o' && bs[2] == 'n' && bs[3] == 'n' - && bs[4] == 'e' && bs[5] == 'c' && bs[6] == 't' - && bs[7] == 'i' && bs[8] == 'o' && bs[9] == 'n') return KEY_CONNECTION; - } else if (size == 12) { //Content-Type - if (bs[1] == 'o' && bs[2] == 'n' && bs[3] == 't' - && bs[4] == 'e' && bs[5] == 'n' && bs[6] == 't' - && bs[7] == '-' && bs[8] == 'T' && bs[9] == 'y' - && bs[10] == 'p' && bs[11] == 'e') return KEY_CONTENT_TYPE; - } else if (size == 6) { //Cookie - if (bs[1] == 'o' && bs[2] == 'o' && bs[3] == 'k' - && bs[4] == 'i' && bs[5] == 'e') return KEY_COOKIE; - } - } - return bytes.toString(charset); - } - - @Override - protected HttpRequest copyHeader() { - if (!pipelineSameHeaders || !context.lazyHeaders) return null; - HttpRequest req = new HttpRequest(context, this.array); - req.headerLength = this.headerLength; - req.headerBytes = this.headerBytes; - req.headerParsed = this.headerParsed; - req.contentType = this.contentType; - req.contentLength = this.contentLength; - req.host = this.host; - req.cookie = this.cookie; - req.cookies = this.cookies; - req.keepAlive = this.keepAlive; - req.maybews = this.maybews; - req.rpc = this.rpc; - req.hashid = this.hashid; - req.currentUserid = this.currentUserid; - req.currentUserSupplier = this.currentUserSupplier; - req.frombody = this.frombody; - req.reqConvertType = this.reqConvertType; - req.reqConvert = this.reqConvert; - req.respConvert = this.respConvert; - req.respConvertType = this.respConvertType; - req.headers.putAll(this.headers); - return req; - } - - @Override - protected void prepare() { - this.keepAlive = true; //榛樿HTTP/1.1 - } - - @Override - protected void recycle() { - //header - this.headerLength = 0; - this.headerHalfLen = 0; - this.headerBytes = null; - this.headerParsed = false; - this.contentType = null; - this.contentLength = -1; - this.host = null; - this.cookie = null; - this.cookies = null; - this.maybews = false; - this.rpc = false; - this.readState = READ_STATE_ROUTE; - this.currentUserid = CURRUSERID_NIL; - this.currentUserSupplier = null; - this.frombody = false; - this.reqConvertType = null; - this.reqConvert = null; - this.respConvert = jsonConvert; - this.respConvertType = null; - this.headers.clear(); - //鍏朵粬 - this.newsessionid = null; - this.method = null; - this.getmethod = false; - this.protocol = null; - this.requestURI = null; - this.queryBytes = null; - this.boundary = false; - this.bodyParsed = false; - this.moduleid = 0; - this.actionid = 0; - this.annotations = null; - this.remoteAddr = null; - this.params.clear(); - this.array.clear(); - //鍐呴儴 - this.actionEntry = null; - super.recycle(); - } - - protected void skipBodyParse() { - this.bodyParsed = true; - } - - private void parseBody() { - if (this.boundary || bodyParsed) return; - bodyParsed = true; - if (this.contentType != null && this.contentType.toLowerCase().contains("x-www-form-urlencoded")) { - addParameter(array, 0, array.length()); - } - } - - private void addParameter(final ByteArray array, final int offset, final int len) { - if (len < 1) return; - Charset charset = this.context.getCharset(); - int limit = offset + len; - int keypos = array.find(offset, limit, '='); - int valpos = array.find(offset, limit, '&'); - if (keypos <= 0 || (valpos >= 0 && valpos < keypos)) { - if (valpos > 0) addParameter(array, valpos + 1, limit - valpos - 1); - return; - } - String name = toDecodeString(array, offset, keypos - offset, charset); - if (name.charAt(0) == '<') return; //鍐呭鍙兘鏄痻ml鏍煎紡; 濡: = 0) { - addParameter(array, valpos + 1, limit - valpos - 1); - } - } - - protected static String toDecodeString(ByteArray array, int offset, int len, final Charset charset) { - byte[] content = array.content(); - int start = offset; - final int end = offset + len; - boolean flag = false; //鏄惁闇瑕佽浆涔 - byte[] bs = content; - for (int i = offset; i < end; i++) { - if (content[i] == '+' || content[i] == '%') { - flag = true; - break; - } - } - if (flag) { - int index = 0; - bs = new byte[len]; - for (int i = offset; i < end; i++) { - switch (content[i]) { - case '+': - bs[index] = ' '; - break; - case '%': - bs[index] = (byte) ((hexBit(content[++i]) * 16 + hexBit(content[++i]))); - break; - default: - bs[index] = content[i]; - break; - } - index++; - } - start = 0; - len = index; - } - if (charset == null) return new String(bs, start, len, StandardCharsets.UTF_8); - return new String(bs, start, len, charset); - } - - private static int hexBit(byte b) { - if ('0' <= b && '9' >= b) return b - '0'; - if ('a' <= b && 'z' >= b) return b - 'a' + 10; - if ('A' <= b && 'Z' >= b) return b - 'A' + 10; - return b; - } - - @Override - protected T setProperty(String name, T value) { - return super.setProperty(name, value); - } - - @Override - @SuppressWarnings("unchecked") - protected T getProperty(String name) { - return super.getProperty(name); - } - - @Override - protected T removeProperty(String name) { - return super.removeProperty(name); - } - - /** - * 璁剧疆褰撳墠鐢ㄦ埛ID, 閫氬父鍦℉ttpServlet.preExecute鏂规硶閲岃缃甤urrentUserid
- * 鏁版嵁绫诲瀷鍙兘鏄痠nt銆乴ong銆丼tring銆丣avaBean - * - * @param 娉涘瀷 - * @param userid 鐢ㄦ埛ID - * - * @return HttpRequest - * - * @since 2.1.0 - */ - public HttpRequest setCurrentUserid(T userid) { - this.currentUserid = userid; - return this; - } - - /** - * 鑾峰彇褰撳墠鐢ㄦ埛ID鐨刬nt鍊
- * - * @return 鐢ㄦ埛ID - * - * @since 2.4.0 - */ - @SuppressWarnings("unchecked") - public int currentIntUserid() { - if (currentUserid == CURRUSERID_NIL || currentUserid == null) return 0; - if (this.currentUserid instanceof Number) return ((Number) this.currentUserid).intValue(); - String uid = this.currentUserid.toString(); - return uid.isEmpty() ? 0 : Integer.parseInt(uid); - } - - /** - * 鑾峰彇褰撳墠鐢ㄦ埛ID
- * - * @param 鏁版嵁绫诲瀷鍙兘鏄痠nt銆乴ong銆丼tring銆丣avaBean - * @param type 绫诲瀷 - * - * @return 鐢ㄦ埛ID - * - * @since 2.1.0 - */ - @SuppressWarnings("unchecked") - public T currentUserid(Class type) { - if (currentUserid == CURRUSERID_NIL || currentUserid == null) { - if (type == int.class) return (T) (Integer) (int) 0; - if (type == long.class) return (T) (Long) (long) 0; - return null; - } - if (type == int.class) { - if (this.currentUserid instanceof Number) return (T) (Integer) ((Number) this.currentUserid).intValue(); - String uid = this.currentUserid.toString(); - return (T) (Integer) (uid.isEmpty() ? 0 : Integer.parseInt(uid)); - } - if (type == long.class) { - if (this.currentUserid instanceof Number) return (T) (Long) ((Number) this.currentUserid).longValue(); - String uid = this.currentUserid.toString(); - return (T) (Long) (uid.isEmpty() ? 0L : Long.parseLong(uid)); - } - if (type == String.class) return (T) this.currentUserid.toString(); - if (this.currentUserid instanceof CharSequence) return JsonConvert.root().convertFrom(type, this.currentUserid.toString()); - return (T) this.currentUserid; - } - - /** - * 寤鸿浣跨敤 setCurrentUserid, 閫氳繃userid浠嶴ervice鎴栫紦瀛樹腑鑾峰彇鐢ㄦ埛淇℃伅
- * 璁剧疆褰撳墠鐢ㄦ埛淇℃伅, 閫氬父鍦℉ttpServlet.preExecute鏂规硶閲岃缃甤urrentUser
- * 鏁版嵁绫诲瀷鐢@HttpUserType鎸囧畾 - * - * @param supplier currentUser瀵硅薄鏂规硶 - * - * @since 2.4.0 - * - * @return HttpRequest - */ - public HttpRequest setCurrentUserSupplier(Supplier supplier) { - this.currentUserSupplier = supplier; - return this; - } - - /** - * 寤鸿浣跨敤 currentUserid, 閫氳繃userid浠嶴ervice鎴栫紦瀛樹腑鑾峰彇鐢ㄦ埛淇℃伅
- * 鑾峰彇褰撳墠鐢ㄦ埛淇℃伅
- * 鏁版嵁绫诲瀷鐢@HttpUserType鎸囧畾 - * - * @param @HttpUserType鎸囧畾鐨勭敤鎴蜂俊鎭被鍨 - * - * @return 鐢ㄦ埛淇℃伅 - */ - @SuppressWarnings("unchecked") - public T currentUser() { - Supplier supplier = this.currentUserSupplier; - return (T) (supplier == null ? null : supplier.get()); - } - - /** - * 鑾峰彇妯″潡ID锛屾潵鑷@HttpServlet.moduleid() - * - * @return 妯″潡ID - */ - @ConvertDisabled - public int getModuleid() { - return this.moduleid; - } - - /** - * 鑾峰彇鎿嶄綔ID锛屾潵鑷@HttpMapping.actionid() - * - * @return 妯″潡ID - */ - @ConvertDisabled - public int getActionid() { - return this.actionid; - } - - /** - * 鑾峰彇褰撳墠鎿嶄綔Method涓婄殑娉ㄨВ闆嗗悎 - * - * @return Annotation[] - */ - @ConvertDisabled - public Annotation[] getAnnotations() { - if (this.annotations == null) return new Annotation[0]; - Annotation[] newanns = new Annotation[this.annotations.length]; - System.arraycopy(this.annotations, 0, newanns, 0, newanns.length); - return newanns; - } - - /** - * 鑾峰彇褰撳墠鎿嶄綔Method涓婄殑娉ㄨВ - * - * @param 娉ㄨВ娉涘瀷 - * @param annotationClass 娉ㄨВ绫诲瀷 - * - * @return Annotation - */ - public T getAnnotation(Class annotationClass) { - if (this.annotations == null) return null; - for (Annotation ann : this.annotations) { - if (ann.getClass() == annotationClass) return (T) ann; - } - return null; - } - - /** - * 鑾峰彇褰撳墠鎿嶄綔Method涓婄殑娉ㄨВ闆嗗悎 - * - * @param 娉ㄨВ娉涘瀷 - * @param annotationClass 娉ㄨВ绫诲瀷 - * - * @return Annotation[] - */ - public T[] getAnnotationsByType(Class annotationClass) { - if (this.annotations == null) return (T[]) Array.newInstance(annotationClass, 0); - T[] news = (T[]) Array.newInstance(annotationClass, this.annotations.length); - int index = 0; - for (Annotation ann : this.annotations) { - if (ann.getClass() == annotationClass) { - news[index++] = (T) ann; - } - } - if (index < 1) return (T[]) Array.newInstance(annotationClass, 0); - return Arrays.copyOf(news, index); - } - - /** - * 鑾峰彇瀹㈡埛绔湴鍧IP - * - * @return 鍦板潃 - */ - @ConvertDisabled - public SocketAddress getRemoteAddress() { - return this.channel == null || !this.channel.isOpen() ? null : this.channel.getRemoteAddress(); - } - - /** - * 鑾峰彇瀹㈡埛绔湴鍧IP, 涓巊etRemoteAddress() 鐨勫尯鍒湪浜庯細鏈柟娉曚紭鍏堝彇header涓寚瀹氫负RemoteAddress鍚嶇殑鍊硷紝娌℃湁鍒欒繑鍥瀏etRemoteAddress()鐨刧etHostAddress()銆
- * 鏈柟娉曢傜敤浜庢湇鍔″墠绔湁濡俷ginx鐨勪唬鐞嗘湇鍔″櫒杩涜涓浆锛岄氳繃 getRemoteAddress()鏄幏鍙栦笉鍒板鎴风鐨勭湡瀹濱P銆 - * - * @return 鍦板潃 - */ - public String getRemoteAddr() { - if (this.remoteAddr != null) return this.remoteAddr; - parseHeader(); - if (remoteAddrHeader != null) { - String val = getHeader(remoteAddrHeader); - if (val != null) { - this.remoteAddr = val; - return val; - } - } - SocketAddress addr = getRemoteAddress(); - if (addr == null) return ""; - if (addr instanceof InetSocketAddress) { - this.remoteAddr = ((InetSocketAddress) addr).getAddress().getHostAddress(); - return this.remoteAddr; - } - this.remoteAddr = String.valueOf(addr); - return this.remoteAddr; - } - - /** - * 鑾峰彇璇锋眰鍐呭鎸囧畾鐨勭紪鐮佸瓧绗︿覆 - * - * @param charset 缂栫爜 - * - * @return 鍐呭 - */ - public String getBody(final Charset charset) { - return charset == null ? array.toString() : array.toString(charset); - } - - /** - * 鑾峰彇璇锋眰鍐呭鐨刄TF-8缂栫爜瀛楃涓 - * - * @return 鍐呭 - */ - @ConvertDisabled - public String getBodyUTF8() { - return array.toString(StandardCharsets.UTF_8); - } - - /** - * 鑾峰彇璇锋眰鍐呭鐨凧avaBean瀵硅薄 - * - * @param 娉涘瀷 - * @param type 绫诲瀷 - * - * @return 鍐呭 - */ - public T getBodyJson(java.lang.reflect.Type type) { - if (array == null || array.isEmpty()) return null; - Convert convert = this.reqConvert; - if (convert == null) convert = context.getJsonConvert(); - if (type == byte[].class) return (T) array.getBytes(); - return (T) convert.convertFrom(type, array.content()); - } - - /** - * 鑾峰彇璇锋眰鍐呭鐨凧avaBean瀵硅薄 - * - * @param 娉涘瀷 - * @param convert Convert - * @param type 绫诲瀷 - * - * @return 鍐呭 - */ - public T getBodyJson(Convert convert, java.lang.reflect.Type type) { - if (array.isEmpty()) return null; - if (type == byte[].class) return (T) array.getBytes(); - return (T) convert.convertFrom(type, array.content()); - } - - /** - * 鑾峰彇璇锋眰鍐呭鐨刡yte[] - * - * @return 鍐呭 - */ - public byte[] getBody() { - return array.length() == 0 ? null : array.getBytes(); - } - - /** - * 鐩存帴鑾峰彇body瀵硅薄 - * - * @return body瀵硅薄 - */ - @ConvertDisabled - protected ByteArray getDirectBody() { - return array; - } - - @Override - public String toString() { - parseBody(); - return this.getClass().getSimpleName() + "{\r\n method: " + this.method + ", \r\n requestURI: " + this.requestURI - + (this.frombody ? (", \r\n frombody: " + this.frombody) : "") - + (this.reqConvertType != null ? (", \r\n reqConvertType: " + this.reqConvertType) : "") - + (this.respConvertType != null ? (", \r\n respConvertType: " + this.respConvertType) : "") - + ", \r\n currentUserid: " + (this.currentUserid == CURRUSERID_NIL ? null : this.currentUserid) + ", \r\n remoteAddr: " + this.getRemoteAddr() - + ", \r\n cookies: " + this.cookie + ", \r\n contentType: " + this.contentType - + ", \r\n protocol: " + this.protocol + ", \r\n host: " + this.host - + ", \r\n contentLength: " + this.contentLength + ", \r\n bodyLength: " + this.array.length() - + (this.boundary || this.array.isEmpty() ? "" : (", \r\n bodyContent: " + (this.respConvertType == null || this.respConvertType == ConvertType.JSON ? this.getBodyUTF8() : Arrays.toString(getBody())))) - + ", \r\n params: " + toMapString(this.params, 4) + ", \r\n header: " + toMapString(this.headers, 4) + "\r\n}"; //this.headers.toString(4) - } - - private static CharSequence toMapString(Map map, int indent) { - char[] chars = new char[indent]; - Arrays.fill(chars, ' '); - final String space = new String(chars); - StringBuilder sb = new StringBuilder(); - sb.append("{\r\n"); - for (Map.Entry en : map.entrySet()) { - sb.append(space).append(" '").append(en.getKey()).append("': '").append(en.getValue()).append("',\r\n"); - } - sb.append(space).append('}'); - return sb; - } - - /** - * 鑾峰彇鏂囦欢涓婁紶瀵硅薄 - * - * @return 鏂囦欢涓婁紶瀵硅薄 - */ - @ConvertDisabled - public final MultiContext getMultiContext() { - final InputStream in = newInputStream(); - return new MultiContext(context.getCharset(), this.getContentType(), this.params, - new BufferedInputStream(in, Math.max(array.length(), 8192)) { - { - array.copyTo(this.buf); - this.count = array.length(); - } - }, null); - } - - /** - * 鏄惁涓婁紶鏂囦欢璇锋眰 - * - * @return boolean - */ - public final boolean isMultipart() { - return boundary; - } - - /** - * 鑾峰彇鏂囦欢涓婁紶淇℃伅鍒楄〃 - * - * @return 鏂囦欢涓婁紶瀵硅薄闆嗗悎 - * - * @throws IOException IO寮傚父 - */ - @ConvertDisabled - public final Iterable multiParts() throws IOException { - return getMultiContext().parts(); - } - - /** - * 鑾峰彇sessionid - * - * @param create 鏃爏essionid鏄惁鑷姩鍒涘缓 - * - * @return sessionid - */ - @ConvertDisabled - public String getSessionid(boolean create) { - String sessionid = getCookie(SESSIONID_NAME, null); - if (create && (sessionid == null || sessionid.isEmpty())) { - sessionid = context.createSessionid(); - this.newsessionid = sessionid; - } - return sessionid; - } - - /** - * 鏇存柊sessionid - * - * @return 鏂扮殑sessionid鍊 - */ - public String changeSessionid() { - this.newsessionid = context.createSessionid(); - return newsessionid; - } - - /** - * 鎸囧畾鍊兼洿鏂皊essionid - * - * @param newsessionid 鏂皊essionid鍊 - * - * @return 鏂扮殑sessionid鍊 - */ - public String changeSessionid(String newsessionid) { - this.newsessionid = newsessionid == null ? context.createSessionid() : newsessionid.trim(); - return newsessionid; - } - - /** - * 浣縮essionid澶辨晥 - */ - public void invalidateSession() { - this.newsessionid = ""; //涓虹┖琛ㄧず鍒犻櫎sessionid - } - - /** - * 鑾峰彇鎵鏈塁ookie瀵硅薄 - * - * @return cookie瀵硅薄鏁扮粍 - */ - public HttpCookie[] getCookies() { - parseHeader(); - if (this.cookies == null) this.cookies = parseCookies(this.cookie); - return this.cookies.length == 0 ? null : this.cookies; - } - - /** - * 鑾峰彇Cookie鍊 - * - * @param name cookie鍚 - * - * @return cookie鍊 - */ - public String getCookie(String name) { - return getCookie(name, null); - } - - /** - * 鑾峰彇Cookie鍊硷紝 娌℃湁杩斿洖榛樿鍊 - * - * @param name cookie鍚 - * @param dfvalue 榛樿cookie鍊 - * - * @return cookie鍊 - */ - public String getCookie(String name, String dfvalue) { - HttpCookie[] cs = getCookies(); - if (cs == null) return dfvalue; - for (HttpCookie c : cs) { - if (name.equals(c.getName())) return c.getValue(); - } - return dfvalue; - } - - private static HttpCookie[] parseCookies(String cookiestr) { - if (cookiestr == null || cookiestr.isEmpty()) return new HttpCookie[0]; - String str = cookiestr.replaceAll("(^;)|(;$)", "").replaceAll(";+", ";"); - if (str.isEmpty()) return new HttpCookie[0]; - String[] strs = str.split(";"); - HttpCookie[] cookies = new HttpCookie[strs.length]; - for (int i = 0; i < strs.length; i++) { - String s = strs[i]; - int pos = s.indexOf('='); - String v = (pos < 0 ? "" : s.substring(pos + 1)); - if (v.indexOf('"') == 0 && v.lastIndexOf('"') == v.length() - 1) v = v.substring(1, v.length() - 1); - cookies[i] = new HttpCookie((pos < 0 ? s : s.substring(0, pos)), v); - } - return cookies; - } - - /** - * 鑾峰彇鍗忚鍚 http銆乭ttps銆亀s銆亀ss绛 - * - * @return protocol - */ - public String getProtocol() { - return protocol; - } - - /** - * 鑾峰彇璇锋眰鏂规硶 GET銆丳OST绛 - * - * @return method - */ - public String getMethod() { - return method; - } - - /** - * 鑾峰彇Content-Type鐨刪eader鍊 - * - * @return contentType - */ - public String getContentType() { - return contentType; - } - - /** - * 鑾峰彇璇锋眰鍐呭鐨勯暱搴, 涓-1琛ㄧず鍐呭闀垮害涓嶇‘瀹 - * - * @return 鍐呭闀垮害 - */ - public long getContentLength() { - return contentLength; - } - - /** - * 鑾峰彇Host鐨凥eader鍊 - * - * @return Host - */ - public String getHost() { - return host; - } - - /** - * 鑾峰彇璇锋眰鐨刄RL - * - * @return 璇锋眰鐨刄RL - */ - public String getRequestURI() { - return requestURI; - } - - /** - * 鑾峰彇璇锋眰鍙傛暟鐨刡yte[] - * - * @return byte[] - */ - public byte[] getQueryBytes() { - return queryBytes; - } - - /** - * 鎴彇getRequestURI鏈鍚庣殑涓涓/鍚庨潰鐨勯儴鍒 - * - * @return String - */ - @ConvertDisabled - public String getRequstURILastPath() { - if (requestURI == null) return ""; - return requestURI.substring(requestURI.lastIndexOf('/') + 1); - } - - /** - * 鑾峰彇璇锋眰URL鏈鍚庣殑涓涓/鍚庨潰鐨勯儴鍒嗙殑short鍊
- * 渚嬪璇锋眰URL /pipes/user/query/2
- * 鑾峰彇type鍙傛暟: short type = request.getRequstURILastPath((short)0); //type = 2 - * - * @param defvalue 榛樿short鍊 - * - * @return short鍊 - */ - public short getRequstURILastPath(short defvalue) { - String val = getRequstURILastPath(); - if (val.isEmpty()) return defvalue; - try { - return Short.parseShort(val); - } catch (NumberFormatException e) { - return defvalue; - } - } - - /** - * 鑾峰彇璇锋眰URL鏈鍚庣殑涓涓/鍚庨潰鐨勯儴鍒嗙殑short鍊
- * 渚嬪璇锋眰URL /pipes/user/query/2
- * 鑾峰彇type鍙傛暟: short type = request.getRequstURILastPath(16, (short)0); //type = 2 - * - * @param radix 杩涘埗鏁 - * @param defvalue 榛樿short鍊 - * - * @return short鍊 - */ - public short getRequstURILastPath(int radix, short defvalue) { - String val = getRequstURILastPath(); - if (val.isEmpty()) return defvalue; - try { - return Short.parseShort(val, radix); - } catch (NumberFormatException e) { - return defvalue; - } - } - - /** - * 鑾峰彇璇锋眰URL鏈鍚庣殑涓涓/鍚庨潰鐨勯儴鍒嗙殑int鍊
- * 渚嬪璇锋眰URL /pipes/user/query/2
- * 鑾峰彇type鍙傛暟: int type = request.getRequstURILastPath(0); //type = 2 - * - * @param defvalue 榛樿int鍊 - * - * @return int鍊 - */ - public int getRequstURILastPath(int defvalue) { - String val = getRequstURILastPath(); - try { - return val.isEmpty() ? defvalue : Integer.parseInt(val); - } catch (NumberFormatException e) { - return defvalue; - } - } - - /** - * 鑾峰彇璇锋眰URL鏈鍚庣殑涓涓/鍚庨潰鐨勯儴鍒嗙殑int鍊
- * 渚嬪璇锋眰URL /pipes/user/query/2
- * 鑾峰彇type鍙傛暟: int type = request.getRequstURILastPath(16, 0); //type = 2 - * - * @param radix 杩涘埗鏁 - * @param defvalue 榛樿int鍊 - * - * @return int鍊 - */ - public int getRequstURILastPath(int radix, int defvalue) { - String val = getRequstURILastPath(); - try { - return val.isEmpty() ? defvalue : Integer.parseInt(val, radix); - } catch (NumberFormatException e) { - return defvalue; - } - } - - /** - * 鑾峰彇璇锋眰URL鏈鍚庣殑涓涓/鍚庨潰鐨勯儴鍒嗙殑float鍊
- * 渚嬪璇锋眰URL /pipes/user/query/2
- * 鑾峰彇type鍙傛暟: float type = request.getRequstURILastPath(0.0f); //type = 2.0f - * - * @param defvalue 榛樿float鍊 - * - * @return float鍊 - */ - public float getRequstURILastPath(float defvalue) { - String val = getRequstURILastPath(); - try { - return val.isEmpty() ? defvalue : Float.parseFloat(val); - } catch (NumberFormatException e) { - return defvalue; - } - } - - /** - * 鑾峰彇璇锋眰URL鏈鍚庣殑涓涓/鍚庨潰鐨勯儴鍒嗙殑int鍊
- * 渚嬪璇锋眰URL /pipes/user/query/2
- * 鑾峰彇type鍙傛暟: long type = request.getRequstURILastPath(0L); //type = 2 - * - * @param defvalue 榛樿long鍊 - * - * @return long鍊 - */ - public long getRequstURILastPath(long defvalue) { - String val = getRequstURILastPath(); - try { - return val.isEmpty() ? defvalue : Long.parseLong(val); - } catch (NumberFormatException e) { - return defvalue; - } - } - - /** - * 鑾峰彇璇锋眰URL鏈鍚庣殑涓涓/鍚庨潰鐨勯儴鍒嗙殑int鍊
- * 渚嬪璇锋眰URL /pipes/user/query/2
- * 鑾峰彇type鍙傛暟: long type = request.getRequstURILastPath(16, 0L); //type = 2 - * - * @param radix 杩涘埗鏁 - * @param defvalue 榛樿long鍊 - * - * @return long鍊 - */ - public long getRequstURILastPath(int radix, long defvalue) { - String val = getRequstURILastPath(); - try { - return val.isEmpty() ? defvalue : Long.parseLong(val, radix); - } catch (NumberFormatException e) { - return defvalue; - } - } - - /** - * 鑾峰彇璇锋眰URL鏈鍚庣殑涓涓/鍚庨潰鐨勯儴鍒嗙殑double鍊
- * 渚嬪璇锋眰URL /pipes/user/query/2
- * 鑾峰彇type鍙傛暟: double type = request.getRequstURILastPath(0.0); //type = 2.0 - * - * @param defvalue 榛樿double鍊 - * - * @return double鍊 - */ - public double getRequstURILastPath(double defvalue) { - String val = getRequstURILastPath(); - try { - return val.isEmpty() ? defvalue : Double.parseDouble(val); - } catch (NumberFormatException e) { - return defvalue; - } - } - - /** - * - * 浠巔refix涔嬪悗鎴彇getRequestURI鍐嶅"/"杩涜鍒嗛殧 - *

- * @param prefix 鍓嶇紑 - * - * @return String[] - */ - public String[] getRequstURIPaths(String prefix) { - if (requestURI == null || prefix == null) return new String[0]; - return requestURI.substring(requestURI.indexOf(prefix) + prefix.length() + (prefix.endsWith("/") ? 0 : 1)).split("/"); - } - - /** - * 鑾峰彇璇锋眰URL鍒嗘涓惈prefix娈电殑鍊
- * 渚嬪璇锋眰URL /pipes/user/query/name:hello
- * 鑾峰彇name鍙傛暟: String name = request.getRequstURIPath("name:", "none"); - * - * @param prefix prefix娈靛墠缂 - * @param defvalue 榛樿鍊 - * - * @return prefix鎴柇鍚庣殑鍊 - */ - public String getRequstURIPath(String prefix, String defvalue) { - if (requestURI == null || prefix == null || prefix.isEmpty()) return defvalue; - int pos = requestURI.indexOf(prefix); - if (pos < 0) return defvalue; - String sub = requestURI.substring(pos + prefix.length()); - pos = sub.indexOf('/'); - return pos < 0 ? sub : sub.substring(0, pos); - } - - /** - * 鑾峰彇璇锋眰URL鍒嗘涓惈prefix娈电殑short鍊
- * 渚嬪璇锋眰URL /pipes/user/query/type:10
- * 鑾峰彇type鍙傛暟: short type = request.getRequstURIPath("type:", (short)0); - * - * @param prefix prefix娈靛墠缂 - * @param defvalue 榛樿short鍊 - * - * @return short鍊 - */ - public short getRequstURIPath(String prefix, short defvalue) { - String val = getRequstURIPath(prefix, null); - try { - return val == null ? defvalue : Short.parseShort(val); - } catch (NumberFormatException e) { - return defvalue; - } - } - - /** - * 鑾峰彇璇锋眰URL鍒嗘涓惈prefix娈电殑short鍊
- * 渚嬪璇锋眰URL /pipes/user/query/type:a
- * 鑾峰彇type鍙傛暟: short type = request.getRequstURIPath(16, "type:", (short)0); //type = 10 - * - * @param radix 杩涘埗鏁 - * @param prefix prefix娈靛墠缂 - * @param defvalue 榛樿short鍊 - * - * @return short鍊 - */ - public short getRequstURIPath(int radix, String prefix, short defvalue) { - String val = getRequstURIPath(prefix, null); - try { - return val == null ? defvalue : Short.parseShort(val, radix); - } catch (NumberFormatException e) { - return defvalue; - } - } - - /** - * 鑾峰彇璇锋眰URL鍒嗘涓惈prefix娈电殑int鍊
- * 渚嬪璇锋眰URL /pipes/user/query/offset:0/limit:50
- * 鑾峰彇offset鍙傛暟: int offset = request.getRequstURIPath("offset:", 0);
- * 鑾峰彇limit鍙傛暟: int limit = request.getRequstURIPath("limit:", 20);
- * - * @param prefix prefix娈靛墠缂 - * @param defvalue 榛樿int鍊 - * - * @return int鍊 - */ - public int getRequstURIPath(String prefix, int defvalue) { - String val = getRequstURIPath(prefix, null); - try { - return val == null ? defvalue : Integer.parseInt(val); - } catch (NumberFormatException e) { - return defvalue; - } - } - - /** - * 鑾峰彇璇锋眰URL鍒嗘涓惈prefix娈电殑int鍊
- * 渚嬪璇锋眰URL /pipes/user/query/offset:0/limit:50
- * 鑾峰彇offset鍙傛暟: int offset = request.getRequstURIPath("offset:", 0);
- * 鑾峰彇limit鍙傛暟: int limit = request.getRequstURIPath(16, "limit:", 20); // limit = 16
- * - * @param radix 杩涘埗鏁 - * @param prefix prefix娈靛墠缂 - * @param defvalue 榛樿int鍊 - * - * @return int鍊 - */ - public int getRequstURIPath(int radix, String prefix, int defvalue) { - String val = getRequstURIPath(prefix, null); - try { - return val == null ? defvalue : Integer.parseInt(val, radix); - } catch (NumberFormatException e) { - return defvalue; - } - } - - /** - * 鑾峰彇璇锋眰URL鍒嗘涓惈prefix娈电殑float鍊
- * 渚嬪璇锋眰URL /pipes/user/query/point:40.0
- * 鑾峰彇time鍙傛暟: float point = request.getRequstURIPath("point:", 0.0f); - * - * @param prefix prefix娈靛墠缂 - * @param defvalue 榛樿float鍊 - * - * @return float鍊 - */ - public float getRequstURIPath(String prefix, float defvalue) { - String val = getRequstURIPath(prefix, null); - try { - return val == null ? defvalue : Float.parseFloat(val); - } catch (NumberFormatException e) { - return defvalue; - } - } - - /** - * 鑾峰彇璇锋眰URL鍒嗘涓惈prefix娈电殑long鍊
- * 渚嬪璇锋眰URL /pipes/user/query/time:1453104341363/id:40
- * 鑾峰彇time鍙傛暟: long time = request.getRequstURIPath("time:", 0L); - * - * @param prefix prefix娈靛墠缂 - * @param defvalue 榛樿long鍊 - * - * @return long鍊 - */ - public long getRequstURIPath(String prefix, long defvalue) { - String val = getRequstURIPath(prefix, null); - try { - return val == null ? defvalue : Long.parseLong(val); - } catch (NumberFormatException e) { - return defvalue; - } - } - - /** - * 鑾峰彇璇锋眰URL鍒嗘涓惈prefix娈电殑long鍊
- * 渚嬪璇锋眰URL /pipes/user/query/time:1453104341363/id:40
- * 鑾峰彇time鍙傛暟: long time = request.getRequstURIPath(16, "time:", 0L); - * - * @param radix 杩涘埗鏁 - * @param prefix prefix娈靛墠缂 - * @param defvalue 榛樿long鍊 - * - * @return long鍊 - */ - public long getRequstURIPath(int radix, String prefix, long defvalue) { - String val = getRequstURIPath(prefix, null); - try { - return val == null ? defvalue : Long.parseLong(val, radix); - } catch (NumberFormatException e) { - return defvalue; - } - } - - /** - * 鑾峰彇璇锋眰URL鍒嗘涓惈prefix娈电殑double鍊
- * 渚嬪璇锋眰URL /pipes/user/query/point:40.0
- * 鑾峰彇time鍙傛暟: double point = request.getRequstURIPath("point:", 0.0); - * - * @param prefix prefix娈靛墠缂 - * @param defvalue 榛樿double鍊 - * - * @return double鍊 - */ - public double getRequstURIPath(String prefix, double defvalue) { - String val = getRequstURIPath(prefix, null); - try { - return val == null ? defvalue : Double.parseDouble(val); - } catch (NumberFormatException e) { - return defvalue; - } - } - - //------------------------------------------------------------------------------ - /** - * 鑾峰彇璇锋眰Header鎬诲璞 - * - * @return AnyValue - */ - public Map getHeaders() { - parseHeader(); - return headers; - } - - /** - * 灏嗚姹侶eader杞崲鎴怣ap - * - * @param map Map - * - * @return Map - */ - @ConvertDisabled - public Map getHeadersToMap(Map map) { - parseHeader(); - if (map == null) map = new LinkedHashMap<>(); - final Map map0 = map; - headers.forEach((k, v) -> map0.put(k, v)); - return map0; - } - - /** - * 鑾峰彇鎵鏈夌殑header鍚 - * - * @return header鍚嶆暟缁 - */ - @ConvertDisabled - public String[] getHeaderNames() { - parseHeader(); - Set names = headers.keySet(); - return names.toArray(new String[names.size()]); - } - - /** - * 鑾峰彇鎸囧畾鐨刪eader鍊 - * - * @param name header鍚 - * - * @return header鍊 - */ - public String getHeader(String name) { - parseHeader(); - return headers.get(name); - } - - /** - * 鑾峰彇鎸囧畾鐨刪eader鍊, 娌℃湁杩斿洖榛樿鍊 - * - * @param name header鍚 - * @param defaultValue 榛樿鍊 - * - * @return header鍊 - */ - public String getHeader(String name, String defaultValue) { - parseHeader(); - return headers.getOrDefault(name, defaultValue); - } - - /** - * 鑾峰彇鎸囧畾鐨刪eader鐨刯son鍊 - * - * @param 娉涘瀷 - * @param type 鍙嶅簭鍒楀寲鐨勭被鍚 - * @param name header鍚 - * - * @return header鍊 - */ - public T getJsonHeader(java.lang.reflect.Type type, String name) { - String v = getHeader(name); - return v == null || v.isEmpty() ? null : jsonConvert.convertFrom(type, v); - } - - /** - * 鑾峰彇鎸囧畾鐨刪eader鐨刯son鍊 - * - * @param 娉涘瀷 - * @param convert JsonConvert瀵硅薄 - * @param type 鍙嶅簭鍒楀寲鐨勭被鍚 - * @param name header鍚 - * - * @return header鍊 - */ - public T getJsonHeader(JsonConvert convert, java.lang.reflect.Type type, String name) { - String v = getHeader(name); - return v == null || v.isEmpty() ? null : convert.convertFrom(type, v); - } - - /** - * 鑾峰彇鎸囧畾鐨刪eader鐨刡oolean鍊, 娌℃湁杩斿洖榛樿boolean鍊 - * - * @param name header鍚 - * @param defaultValue 榛樿boolean鍊 - * - * @return header鍊 - */ - public boolean getBooleanHeader(String name, boolean defaultValue) { - //return headers.getBoolValue(name, defaultValue); - parseHeader(); - String value = headers.get(name); - return value == null || value.length() == 0 ? defaultValue : Boolean.parseBoolean(value); - } - - /** - * 鑾峰彇鎸囧畾鐨刪eader鐨剆hort鍊, 娌℃湁杩斿洖榛樿short鍊 - * - * @param name header鍚 - * @param defaultValue 榛樿short鍊 - * - * @return header鍊 - */ - public short getShortHeader(String name, short defaultValue) { - //return headers.getShortValue(name, defaultValue); - parseHeader(); - String value = headers.get(name); - if (value == null || value.length() == 0) return defaultValue; - try { - return Short.decode(value); - } catch (NumberFormatException e) { - return defaultValue; - } - } - - /** - * 鑾峰彇鎸囧畾鐨刪eader鐨剆hort鍊, 娌℃湁杩斿洖榛樿short鍊 - * - * @param radix 杩涘埗鏁 - * @param name header鍚 - * @param defaultValue 榛樿short鍊 - * - * @return header鍊 - */ - public short getShortHeader(int radix, String name, short defaultValue) { - //return headers.getShortValue(name, defaultValue); - parseHeader(); - String value = headers.get(name); - if (value == null || value.length() == 0) return defaultValue; - try { - return (radix == 10 ? Short.decode(value) : Short.parseShort(value, radix)); - } catch (NumberFormatException e) { - return defaultValue; - } - } - - /** - * 鑾峰彇鎸囧畾鐨刪eader鐨剆hort鍊, 娌℃湁杩斿洖榛樿short鍊 - * - * @param name header鍚 - * @param defaultValue 榛樿short鍊 - * - * @return header鍊 - */ - public short getShortHeader(String name, int defaultValue) { - //return headers.getShortValue(name, (short) defaultValue); - parseHeader(); - String value = headers.get(name); - if (value == null || value.length() == 0) return (short) defaultValue; - try { - return Short.decode(value); - } catch (NumberFormatException e) { - return (short) defaultValue; - } - } - - /** - * 鑾峰彇鎸囧畾鐨刪eader鐨剆hort鍊, 娌℃湁杩斿洖榛樿short鍊 - * - * @param radix 杩涘埗鏁 - * @param name header鍚 - * @param defaultValue 榛樿short鍊 - * - * @return header鍊 - */ - public short getShortHeader(int radix, String name, int defaultValue) { - //return headers.getShortValue(radix, name, (short) defaultValue); - parseHeader(); - String value = headers.get(name); - if (value == null || value.length() == 0) return (short) defaultValue; - try { - return (radix == 10 ? Short.decode(value) : Short.parseShort(value, radix)); - } catch (NumberFormatException e) { - return (short) defaultValue; - } - } - - /** - * 鑾峰彇鎸囧畾鐨刪eader鐨刬nt鍊, 娌℃湁杩斿洖榛樿int鍊 - * - * @param name header鍚 - * @param defaultValue 榛樿int鍊 - * - * @return header鍊 - */ - public int getIntHeader(String name, int defaultValue) { - //return headers.getIntValue(name, defaultValue); - parseHeader(); - String value = headers.get(name); - if (value == null || value.length() == 0) return defaultValue; - try { - return Integer.parseInt(value); - } catch (NumberFormatException e) { - return defaultValue; - } - } - - /** - * 鑾峰彇鎸囧畾鐨刪eader鐨刬nt鍊, 娌℃湁杩斿洖榛樿int鍊 - * - * @param radix 杩涘埗鏁 - * @param name header鍚 - * @param defaultValue 榛樿int鍊 - * - * @return header鍊 - */ - public int getIntHeader(int radix, String name, int defaultValue) { - //return headers.getIntValue(radix, name, defaultValue); - parseHeader(); - String value = headers.get(name); - if (value == null || value.length() == 0) return defaultValue; - try { - return (radix == 10 ? Integer.decode(value) : Integer.parseInt(value, radix)); - } catch (NumberFormatException e) { - return defaultValue; - } - } - - /** - * 鑾峰彇鎸囧畾鐨刪eader鐨刲ong鍊, 娌℃湁杩斿洖榛樿long鍊 - * - * @param name header鍚 - * @param defaultValue 榛樿long鍊 - * - * @return header鍊 - */ - public long getLongHeader(String name, long defaultValue) { - //return headers.getLongValue(name, defaultValue); - parseHeader(); - String value = headers.get(name); - if (value == null || value.length() == 0) return defaultValue; - try { - return Long.decode(value); - } catch (NumberFormatException e) { - return defaultValue; - } - } - - /** - * 鑾峰彇鎸囧畾鐨刪eader鐨刲ong鍊, 娌℃湁杩斿洖榛樿long鍊 - * - * @param radix 杩涘埗鏁 - * @param name header鍚 - * @param defaultValue 榛樿long鍊 - * - * @return header鍊 - */ - public long getLongHeader(int radix, String name, long defaultValue) { - //return headers.getLongValue(radix, name, defaultValue); - parseHeader(); - String value = headers.get(name); - if (value == null || value.length() == 0) return defaultValue; - try { - return (radix == 10 ? Long.decode(value) : Long.parseLong(value, radix)); - } catch (NumberFormatException e) { - return defaultValue; - } - } - - /** - * 鑾峰彇鎸囧畾鐨刪eader鐨刦loat鍊, 娌℃湁杩斿洖榛樿float鍊 - * - * @param name header鍚 - * @param defaultValue 榛樿float鍊 - * - * @return header鍊 - */ - public float getFloatHeader(String name, float defaultValue) { - //return headers.getFloatValue(name, defaultValue); - parseHeader(); - String value = headers.get(name); - if (value == null || value.length() == 0) return defaultValue; - try { - return Float.parseFloat(value); - } catch (NumberFormatException e) { - return defaultValue; - } - } - - /** - * 鑾峰彇鎸囧畾鐨刪eader鐨刣ouble鍊, 娌℃湁杩斿洖榛樿double鍊 - * - * @param name header鍚 - * @param defaultValue 榛樿double鍊 - * - * @return header鍊 - */ - public double getDoubleHeader(String name, double defaultValue) { - //return headers.getDoubleValue(name, defaultValue); - parseHeader(); - String value = headers.get(name); - if (value == null || value.length() == 0) return defaultValue; - try { - return Double.parseDouble(value); - } catch (NumberFormatException e) { - return defaultValue; - } - } - - //------------------------------------------------------------------------------ - /** - * 鑾峰彇璇锋眰鍙傛暟鎬诲璞 - * - * @return AnyValue - */ - public Map getParameters() { - parseBody(); - return params; - } - - /** - * 灏嗚姹傚弬鏁拌浆鎹㈡垚Map - * - * @param map Map - * - * @return Map - */ - @ConvertDisabled - public Map getParametersToMap(Map map) { - if (map == null) map = new LinkedHashMap<>(); - final Map map0 = map; - getParameters().forEach((k, v) -> map0.put(k, v)); - return map0; - } - - /** - * 灏嗚姹傚弬鏁拌浆鎹㈡垚String, 瀛楃涓叉牸寮忎负: bean1={}&id=13&name=xxx
- * 涓嶄細杩斿洖null锛屾病鏈夊弬鏁拌繑鍥炵┖瀛楃涓 - * - * - * @return String - */ - @ConvertDisabled - public String getParametersToString() { - return getParametersToString(null); - } - - /** - * 灏嗚姹傚弬鏁拌浆鎹㈡垚String, 瀛楃涓叉牸寮忎负: bean1={}&id=13&name=xxx
- * 涓嶄細杩斿洖null锛屾病鏈夊弬鏁拌繑鍥炵┖瀛楃涓 - * - * @param prefix 鎷兼帴鍓嶇紑锛 濡傛灉鏃犲弬鏁帮紝杩斿洖鐨勫瓧绗︿覆涓嶄細鍚湁鎷兼帴鍓嶇紑 - * - * @return String - */ - public String getParametersToString(String prefix) { - byte[] rbs = queryBytes; - if (rbs == null || rbs.length < 1) return ""; - Charset charset = this.context.getCharset(); - String str = charset == null ? new String(rbs, StandardCharsets.UTF_8) : new String(rbs, charset); - return (prefix == null) ? str : (prefix + str); - } - - /** - * 鑾峰彇鎵鏈夊弬鏁板悕 - * - * @return 鍙傛暟鍚嶆暟缁 - */ - @ConvertDisabled - public String[] getParameterNames() { - parseBody(); - Set names = params.keySet(); - return names.toArray(new String[names.size()]); - } - - /** - * 鑾峰彇鎸囧畾鐨勫弬鏁板 - * - * @param name 鍙傛暟鍚 - * - * @return 鍙傛暟鍊 - */ - public String getParameter(String name) { - if (this.frombody) { - if (array.isEmpty()) return null; - Convert convert = this.reqConvert; - if (convert == null) convert = jsonConvert; - return (String) convert.convertFrom(String.class, array.content()); - } - parseBody(); - return params.get(name); - } - - /** - * 鑾峰彇鎸囧畾鐨勫弬鏁板, 娌℃湁杩斿洖榛樿鍊 - * - * @param name 鍙傛暟鍚 - * @param defaultValue 榛樿鍊 - * - * @return 鍙傛暟鍊 - */ - public String getParameter(String name, String defaultValue) { - if (this.frombody) { - if (array.isEmpty()) return defaultValue; - Convert convert = this.reqConvert; - if (convert == null) convert = jsonConvert; - return (String) convert.convertFrom(String.class, array.content()); - } - parseBody(); - return params.getOrDefault(name, defaultValue); - } - - /** - * 鑾峰彇鎸囧畾鐨勫弬鏁癹son鍊 - * - * @param 娉涘瀷 - * @param type 鍙嶅簭鍒楀寲鐨勭被鍚 - * @param name 鍙傛暟鍚 - * - * @return 鍙傛暟鍊 - */ - public T getJsonParameter(java.lang.reflect.Type type, String name) { - if (this.frombody) { - if (array.isEmpty()) return null; - Convert convert = this.reqConvert; - if (convert == null) convert = jsonConvert; - if (type == byte[].class) return (T) array.getBytes(); - return (T) convert.convertFrom(type, array.content()); - } - String v = getParameter(name); - return v == null || v.isEmpty() ? null : jsonConvert.convertFrom(type, v); - } - - /** - * 鑾峰彇鎸囧畾鐨勫弬鏁癹son鍊 - * - * @param 娉涘瀷 - * @param convert JsonConvert瀵硅薄 - * @param type 鍙嶅簭鍒楀寲鐨勭被鍚 - * @param name 鍙傛暟鍚 - * - * @return 鍙傛暟鍊 - */ - public T getJsonParameter(JsonConvert convert, java.lang.reflect.Type type, String name) { - String v = getParameter(name); - return v == null || v.isEmpty() ? null : convert.convertFrom(type, v); - } - - /** - * 鑾峰彇鎸囧畾鐨勫弬鏁癰oolean鍊, 娌℃湁杩斿洖榛樿boolean鍊 - * - * @param name 鍙傛暟鍚 - * @param defaultValue 榛樿boolean鍊 - * - * @return 鍙傛暟鍊 - */ - public boolean getBooleanParameter(String name, boolean defaultValue) { - if (this.frombody) { - if (array.isEmpty()) return defaultValue; - Convert convert = this.reqConvert; - if (convert == null) convert = jsonConvert; - return (boolean) convert.convertFrom(boolean.class, array.content()); - } - parseBody(); - String value = params.get(name); - return value == null || value.length() == 0 ? defaultValue : Boolean.parseBoolean(value); - } - - /** - * 鑾峰彇鎸囧畾鐨勫弬鏁皊hort鍊, 娌℃湁杩斿洖榛樿short鍊 - * - * @param name 鍙傛暟鍚 - * @param defaultValue 榛樿short鍊 - * - * @return 鍙傛暟鍊 - */ - public short getShortParameter(String name, short defaultValue) { - if (this.frombody) { - if (array.isEmpty()) return defaultValue; - Convert convert = this.reqConvert; - if (convert == null) convert = jsonConvert; - return (short) convert.convertFrom(short.class, array.content()); - } - parseBody(); - String value = params.get(name); - if (value == null || value.length() == 0) return defaultValue; - try { - return Short.decode(value); - } catch (NumberFormatException e) { - return defaultValue; - } - } - - /** - * 鑾峰彇鎸囧畾鐨勫弬鏁皊hort鍊, 娌℃湁杩斿洖榛樿short鍊 - * - * @param radix 杩涘埗鏁 - * @param name 鍙傛暟鍚 - * @param defaultValue 榛樿short鍊 - * - * @return 鍙傛暟鍊 - */ - public short getShortParameter(int radix, String name, short defaultValue) { - if (this.frombody) { - if (array.isEmpty()) return (short) defaultValue; - Convert convert = this.reqConvert; - if (convert == null) convert = jsonConvert; - return (short) convert.convertFrom(short.class, array.content()); - } - parseBody(); - String value = params.get(name); - if (value == null || value.length() == 0) return defaultValue; - try { - return (radix == 10 ? Short.decode(value) : Short.parseShort(value, radix)); - } catch (NumberFormatException e) { - return defaultValue; - } - } - - /** - * 鑾峰彇鎸囧畾鐨勫弬鏁皊hort鍊, 娌℃湁杩斿洖榛樿short鍊 - * - * @param name 鍙傛暟鍚 - * @param defaultValue 榛樿short鍊 - * - * @return 鍙傛暟鍊 - */ - public short getShortParameter(String name, int defaultValue) { - if (this.frombody) { - if (array.isEmpty()) return (short) defaultValue; - Convert convert = this.reqConvert; - if (convert == null) convert = jsonConvert; - return (short) convert.convertFrom(short.class, array.content()); - } - parseBody(); - String value = params.get(name); - if (value == null || value.length() == 0) return (short) defaultValue; - try { - return Short.decode(value); - } catch (NumberFormatException e) { - return (short) defaultValue; - } - } - - /** - * 鑾峰彇鎸囧畾鐨勫弬鏁癷nt鍊, 娌℃湁杩斿洖榛樿int鍊 - * - * @param name 鍙傛暟鍚 - * @param defaultValue 榛樿int鍊 - * - * @return 鍙傛暟鍊 - */ - public int getIntParameter(String name, int defaultValue) { - if (this.frombody) { - if (array.isEmpty()) return defaultValue; - Convert convert = this.reqConvert; - if (convert == null) convert = jsonConvert; - return (int) convert.convertFrom(int.class, array.content()); - } - parseBody(); - String value = params.get(name); - if (value == null || value.length() == 0) return defaultValue; - try { - return Integer.decode(value); - } catch (NumberFormatException e) { - return defaultValue; - } - } - - /** - * 鑾峰彇鎸囧畾鐨勫弬鏁癷nt鍊, 娌℃湁杩斿洖榛樿int鍊 - * - * @param radix 杩涘埗鏁 - * @param name 鍙傛暟鍚 - * @param defaultValue 榛樿int鍊 - * - * @return 鍙傛暟鍊 - */ - public int getIntParameter(int radix, String name, int defaultValue) { - if (this.frombody) { - if (array.isEmpty()) return defaultValue; - Convert convert = this.reqConvert; - if (convert == null) convert = jsonConvert; - return (int) convert.convertFrom(int.class, array.content()); - } - parseBody(); - String value = params.get(name); - if (value == null || value.length() == 0) return defaultValue; - try { - return (radix == 10 ? Integer.decode(value) : Integer.parseInt(value, radix)); - } catch (NumberFormatException e) { - return defaultValue; - } - } - - /** - * 鑾峰彇鎸囧畾鐨勫弬鏁發ong鍊, 娌℃湁杩斿洖榛樿long鍊 - * - * @param name 鍙傛暟鍚 - * @param defaultValue 榛樿long鍊 - * - * @return 鍙傛暟鍊 - */ - public long getLongParameter(String name, long defaultValue) { - if (this.frombody) { - if (array.isEmpty()) return defaultValue; - Convert convert = this.reqConvert; - if (convert == null) convert = jsonConvert; - return (long) convert.convertFrom(long.class, array.content()); - } - parseBody(); - String value = params.get(name); - if (value == null || value.length() == 0) return defaultValue; - try { - return Long.decode(value); - } catch (NumberFormatException e) { - return defaultValue; - } - } - - /** - * 鑾峰彇鎸囧畾鐨勫弬鏁發ong鍊, 娌℃湁杩斿洖榛樿long鍊 - * - * @param radix 杩涘埗鏁 - * @param name 鍙傛暟鍚 - * @param defaultValue 榛樿long鍊 - * - * @return 鍙傛暟鍊 - */ - public long getLongParameter(int radix, String name, long defaultValue) { - if (this.frombody) { - if (array.isEmpty()) return defaultValue; - Convert convert = this.reqConvert; - if (convert == null) convert = jsonConvert; - return (long) convert.convertFrom(long.class, array.content()); - } - parseBody(); - String value = params.get(name); - if (value == null || value.length() == 0) return defaultValue; - try { - return (radix == 10 ? Long.decode(value) : Long.parseLong(value, radix)); - } catch (NumberFormatException e) { - return defaultValue; - } - } - - /** - * 鑾峰彇鎸囧畾鐨勫弬鏁癴loat鍊, 娌℃湁杩斿洖榛樿float鍊 - * - * @param name 鍙傛暟鍚 - * @param defaultValue 榛樿float鍊 - * - * @return 鍙傛暟鍊 - */ - public float getFloatParameter(String name, float defaultValue) { - if (this.frombody) { - if (array.isEmpty()) return defaultValue; - Convert convert = this.reqConvert; - if (convert == null) convert = jsonConvert; - return (float) convert.convertFrom(float.class, array.content()); - } - parseBody(); - String value = params.get(name); - if (value == null || value.length() == 0) return defaultValue; - try { - return Float.parseFloat(value); - } catch (NumberFormatException e) { - return defaultValue; - } - } - - /** - * 鑾峰彇鎸囧畾鐨勫弬鏁癲ouble鍊, 娌℃湁杩斿洖榛樿double鍊 - * - * @param name 鍙傛暟鍚 - * @param defaultValue 榛樿double鍊 - * - * @return 鍙傛暟鍊 - */ - public double getDoubleParameter(String name, double defaultValue) { - if (this.frombody) { - if (array.isEmpty()) return defaultValue; - Convert convert = this.reqConvert; - if (convert == null) convert = jsonConvert; - return (double) convert.convertFrom(double.class, array.content()); - } - parseBody(); - String value = params.get(name); - if (value == null || value.length() == 0) return defaultValue; - try { - return Double.parseDouble(value); - } catch (NumberFormatException e) { - return defaultValue; - } - } - - /** - * 鑾峰彇缈婚〉瀵硅薄 鍚 getFlipper("flipper", false, 0); - * - * @return Flipper缈婚〉瀵硅薄 - */ - public org.redkale.source.Flipper getFlipper() { - return getFlipper(false, 0); - } - - /** - * 鑾峰彇缈婚〉瀵硅薄 鍚 getFlipper("flipper", needcreate, 0); - * - * @param needcreate 鏃犲弬鏁版椂鏄惁鍒涘缓鏂癋lipper瀵硅薄 - * - * @return Flipper缈婚〉瀵硅薄 - */ - public org.redkale.source.Flipper getFlipper(boolean needcreate) { - return getFlipper(needcreate, 0); - } - - /** - * 鑾峰彇缈婚〉瀵硅薄 鍚 getFlipper("flipper", false, maxLimit); - * - * @param maxLimit 鏈澶ц鏁帮紝 灏忎簬1鍒欏间负Flipper.DEFAULT_LIMIT - * - * @return Flipper缈婚〉瀵硅薄 - */ - public org.redkale.source.Flipper getFlipper(int maxLimit) { - return getFlipper(false, maxLimit); - } - - /** - * 鑾峰彇缈婚〉瀵硅薄 鍚 getFlipper("flipper", needcreate, maxLimit) - * - * @param needcreate 鏃犲弬鏁版椂鏄惁鍒涘缓鏂癋lipper瀵硅薄 - * @param maxLimit 鏈澶ц鏁帮紝 灏忎簬1鍒欏间负Flipper.DEFAULT_LIMIT - * - * @return Flipper缈婚〉瀵硅薄 - */ - public org.redkale.source.Flipper getFlipper(boolean needcreate, int maxLimit) { - return getFlipper("flipper", needcreate, maxLimit); - } - - /** - * 鑾峰彇缈婚〉瀵硅薄 https://redkale.org/pipes/users/list/offset:0/limit:20/sort:createtime%20ASC
- * https://redkale.org/pipes/users/list?flipper={'offset':0,'limit':20, 'sort':'createtime ASC'}
- * 浠ヤ笂涓ょ鎺ュ彛閮藉彲浠ヨ幏鍙栧埌缈婚〉瀵硅薄 - * - * - * @param name Flipper瀵硅薄鐨勫弬鏁板悕锛岄粯璁や负 "flipper" - * @param needcreate 鏃犲弬鏁版椂鏄惁鍒涘缓鏂癋lipper瀵硅薄 - * @param maxLimit 鏈澶ц鏁帮紝 灏忎簬1鍒欏间负Flipper.DEFAULT_LIMIT - * - * @return Flipper缈婚〉瀵硅薄 - */ - public org.redkale.source.Flipper getFlipper(String name, boolean needcreate, int maxLimit) { - org.redkale.source.Flipper flipper = getJsonParameter(org.redkale.source.Flipper.class, name); - if (flipper == null) { - if (maxLimit < 1) maxLimit = org.redkale.source.Flipper.DEFAULT_LIMIT; - int limit = getRequstURIPath("limit:", 0); - int offset = getRequstURIPath("offset:", 0); - String sort = getRequstURIPath("sort:", ""); - if (limit > 0) { - if (limit > maxLimit) limit = maxLimit; - flipper = new org.redkale.source.Flipper(limit, offset, sort); - } - } else if (flipper.getLimit() < 1 || (maxLimit > 0 && flipper.getLimit() > maxLimit)) { - flipper.setLimit(maxLimit); - } - if (flipper != null || !needcreate) return flipper; - if (maxLimit < 1) maxLimit = org.redkale.source.Flipper.DEFAULT_LIMIT; - return new org.redkale.source.Flipper(maxLimit); - } -} +/* + * To change this license headers, 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 java.io.*; +import java.lang.annotation.Annotation; +import java.lang.reflect.Array; +import java.net.*; +import java.nio.ByteBuffer; +import java.nio.charset.*; +import java.util.*; +import java.util.function.Supplier; +import java.util.logging.Level; +import org.redkale.convert.*; +import org.redkale.convert.json.JsonConvert; +import org.redkale.net.*; +import org.redkale.util.*; + +/** + * Http璇锋眰鍖 涓巎avax.servlet.http.HttpServletRequest 鍩烘湰绫讳技銆
+ * 鍚屾椂鎻愪緵json鐨勮В鏋愭帴鍙: public Object getJsonParameter(Type type, String name)
+ * Redkale鎻愬″甫绠鍗曠殑鍙傛暟鐨凣ET璇锋眰閲囩敤绫讳技REST椋庢牸, 鍥犳鎻愪緵浜 getRequstURIPath 绯诲垪鎺ュ彛銆
+ * 渚嬪绠鍗曠殑缈婚〉鏌ヨ
+ * /pipes/user/query/offset:0/limit:20
+ * 鑾峰彇椤靛彿: int offset = request.getRequstURIPath("offset:", 0);
+ * 鑾峰彇琛屾暟: int limit = request.getRequstURIPath("limit:", 10);
+ *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public class HttpRequest extends Request { + + private static final boolean pipelineSameHeaders = Boolean.getBoolean("redkale.http.request.pipeline.sameheaders"); + + protected static final Serializable CURRUSERID_NIL = new Serializable() { + }; + + protected static final int READ_STATE_ROUTE = 1; + + protected static final int READ_STATE_HEADER = 2; + + protected static final int READ_STATE_BODY = 3; + + protected static final int READ_STATE_END = 4; + + protected static final byte[] EMPTY_BYTES = new byte[0]; + + protected static final String KEY_GET = "GET"; + + protected static final String KEY_POST = "POST"; + + protected static final String KEY_HTTP_1_1 = "HTTP/1.1"; + + protected static final String KEY_COOKIE = "Cookie"; + + protected static final String KEY_CONNECTION = "Connection"; + + protected static final String KEY_CONTENT_TYPE = "Content-Type"; + + protected static final String KEY_ACCEPT = "Accept"; + + protected static final String KEY_HOST = "Host"; + + public static final String SESSIONID_NAME = "JSESSIONID"; + + //---------- header 鐩稿叧鍙傛暟 寮濮 ---------- + protected int headerLength; + + protected int headerHalfLen; + + protected String contentType; + + protected long contentLength = -1; + + protected String host; + + @Comment("鍘熷鐨刢ookie瀛楃涓诧紝瑙f瀽鍚庡艰祴缁橦ttpCookie[] cookies") + protected String cookie; + + protected HttpCookie[] cookies; + + private boolean maybews = false; //鏄惁鍙兘鏄疻ebSocket + + protected boolean rpc; + + protected int readState = READ_STATE_ROUTE; + + // @since 2.1.0 + protected Serializable currentUserid = CURRUSERID_NIL; + + protected Supplier currentUserSupplier; + + protected boolean frombody; + + protected ConvertType reqConvertType; + + protected Convert reqConvert; + + protected ConvertType respConvertType; + + protected Convert respConvert; + + protected final Map headers = new HashMap<>(); + //---------- header 鐩稿叧鍙傛暟 缁撴潫 ---------- + + @Comment("Method GET/POST/...") + protected String method; + + protected boolean getmethod; + + protected String protocol; + + protected String requestURI; + + protected byte[] queryBytes; + + protected String newsessionid; + + protected final Map params = new HashMap<>(); + + protected boolean boundary = false; + + protected int moduleid; + + protected int actionid; + + protected Annotation[] annotations; + + protected String remoteAddr; + + private String lastRequestURIString; + + private byte[] lastRequestURIBytes; + + private final ByteArray array; + + private byte[] headerBytes; + + private boolean headerParsed = false; + + private boolean bodyParsed = false; + + private final String remoteAddrHeader; + + HttpServlet.ActionEntry actionEntry; //浠呬緵HttpServlet浼犻扙ntry浣跨敤 + + public HttpRequest(HttpContext context) { + this(context, new ByteArray()); + } + + protected HttpRequest(HttpContext context, ByteArray array) { + super(context); + this.array = array; + this.remoteAddrHeader = context.remoteAddrHeader; + } + + @SuppressWarnings("OverridableMethodCallInConstructor") + protected HttpRequest(HttpContext context, HttpSimpleRequest req) { + super(context); + this.array = new ByteArray(); + this.remoteAddrHeader = null; + if (req != null) initSimpleRequest(req, true); + } + + protected HttpRequest initSimpleRequest(HttpSimpleRequest req, boolean needPath) { + if (req != null) { + this.rpc = req.rpc; + if (req.getBody() != null) this.array.put(req.getBody()); + if (req.getHeaders() != null) this.headers.putAll(req.getHeaders()); + this.frombody = req.isFrombody(); + this.reqConvertType = req.getReqConvertType(); + this.reqConvert = req.getReqConvertType() == null ? null : ConvertFactory.findConvert(req.getReqConvertType()); + this.respConvertType = req.getRespConvertType(); + this.respConvert = req.getRespConvertType() == null ? null : ConvertFactory.findConvert(req.getRespConvertType()); + if (req.getParams() != null) this.params.putAll(req.getParams()); + this.hashid = req.getHashid(); + if (req.getCurrentUserid() != null) this.currentUserid = req.getCurrentUserid(); + this.contentType = req.getContentType(); + this.remoteAddr = req.getRemoteAddr(); + if (needPath) { + this.requestURI = (req.getPath() == null || req.getPath().isEmpty()) ? req.getRequestURI() : (req.getPath() + req.getRequestURI()); + } else { + this.requestURI = req.getRequestURI(); + } + this.method = "POST"; + if (req.getSessionid() != null && !req.getSessionid().isEmpty()) { + this.cookies = new HttpCookie[]{new HttpCookie(SESSIONID_NAME, req.getSessionid())}; + } + } + return this; + } + + public HttpSimpleRequest createSimpleRequest(String prefix) { + HttpSimpleRequest req = new HttpSimpleRequest(); + req.setBody(array.length() == 0 ? null : array.getBytes()); + if (!getHeaders().isEmpty()) { + if (headers.containsKey(Rest.REST_HEADER_RPC_NAME) + || headers.containsKey(Rest.REST_HEADER_CURRUSERID_NAME)) { //澶栭儴request涓嶈兘鍖呭惈RPC鐨刪eader淇℃伅 + req.setHeaders(new HashMap<>(headers)); + req.removeHeader(Rest.REST_HEADER_RPC_NAME); + req.removeHeader(Rest.REST_HEADER_CURRUSERID_NAME); + } else { + req.setHeaders(headers); + } + } + parseBody(); + req.setParams(params.isEmpty() ? null : params); + req.setRemoteAddr(getRemoteAddr()); + req.setContentType(getContentType()); + req.setPath(prefix); + String uri = this.requestURI; + if (prefix != null && !prefix.isEmpty() && uri.startsWith(prefix)) { + uri = uri.substring(prefix.length()); + } + req.setHashid(this.hashid); + req.setRequestURI(uri); + req.setSessionid(getSessionid(false)); + req.setRpc(this.rpc); + return req; + } + + protected boolean isWebSocket() { + return maybews && "Upgrade".equalsIgnoreCase(getHeader("Connection")) && "GET".equalsIgnoreCase(method); + } + + protected void setPipelineOver(boolean pipelineOver) { + this.pipelineOver = pipelineOver; + } + + protected void setKeepAlive(boolean keepAlive) { + this.keepAlive = keepAlive; + } + + protected boolean isKeepAlive() { + return this.keepAlive; + } + + protected AsyncConnection getChannel() { + return this.channel; + } + + protected int getPipelineIndex() { + return this.pipelineIndex; + } + + protected int getPipelineCount() { + return this.pipelineCount; + } + + protected ConvertType getRespConvertType() { + return this.respConvertType; + } + + protected Convert getRespConvert() { + return this.respConvert == null ? this.jsonConvert : this.respConvert; + } + + @Override + protected int readHeader(final ByteBuffer buffer, final Request last) { + ByteArray bytes = array; + if (this.readState == READ_STATE_ROUTE) { + int rs = readMethodLine(buffer); + if (rs != 0) return rs; + this.readState = READ_STATE_HEADER; + } + if (this.readState == READ_STATE_HEADER) { + if (last != null && ((HttpRequest) last).headerLength > 0) { + final HttpRequest httplast = (HttpRequest) last; + int bufremain = buffer.remaining(); + int remainhalf = httplast.headerLength - this.headerHalfLen; + if (remainhalf > bufremain) { + bytes.put(buffer); + this.headerHalfLen += bufremain; + buffer.clear(); + return 1; + } + buffer.position(buffer.position() + remainhalf); + this.contentType = httplast.contentType; + this.contentLength = httplast.contentLength; + this.host = httplast.host; + this.cookie = httplast.cookie; + this.cookies = httplast.cookies; + this.keepAlive = httplast.keepAlive; + this.maybews = httplast.maybews; + this.rpc = httplast.rpc; + this.hashid = httplast.hashid; + this.currentUserid = httplast.currentUserid; + this.frombody = httplast.frombody; + this.reqConvertType = httplast.reqConvertType; + this.reqConvert = httplast.reqConvert; + this.respConvertType = httplast.respConvertType; + this.respConvert = httplast.respConvert; + this.headerLength = httplast.headerLength; + this.headerHalfLen = httplast.headerLength; + this.headerBytes = httplast.headerBytes; + this.headerParsed = httplast.headerParsed; + this.headers.putAll(httplast.headers); + } else if (context.lazyHeaders && getmethod) { //闈濭ET蹇呴』瑕佽header锛屼細鏈塁ontent-Length + int rs = loadHeaderBytes(buffer); + if (rs != 0) return rs; + this.headerParsed = false; + } else { + int startpos = buffer.position(); + int rs = readHeaderLines(buffer, bytes); + if (rs != 0) { + this.headerHalfLen = bytes.length(); + return rs; + } + this.headerParsed = true; + this.headerLength = buffer.position() - startpos + this.headerHalfLen; + this.headerHalfLen = this.headerLength; + } + bytes.clear(); + this.readState = READ_STATE_BODY; + } + if (this.contentType != null && this.contentType.contains("boundary=")) this.boundary = true; + if (this.boundary) this.keepAlive = false; //鏂囦欢涓婁紶蹇呴』璁剧疆keepAlive涓篺alse锛屽洜涓烘枃浠惰繃澶ф椂鐢ㄦ埛涓嶄竴瀹氫細skip鎺夊浣欑殑鏁版嵁 + if (this.readState == READ_STATE_BODY) { + if (this.contentLength > 0 && (this.contentType == null || !this.boundary)) { + if (this.contentLength > context.getMaxbody()) return -1; + bytes.put(buffer, Math.min((int) this.contentLength, buffer.remaining())); + int lr = (int) this.contentLength - bytes.length(); + if (lr == 0) { + this.readState = READ_STATE_END; + if (bytes.isEmpty()) this.bodyParsed = true; //no body data + } + return lr > 0 ? lr : 0; + } + if (buffer.hasRemaining() && (this.boundary || !this.keepAlive)) bytes.put(buffer, buffer.remaining()); //鏂囦欢涓婁紶銆丠TTP1.0鎴朇onnection:close + this.readState = READ_STATE_END; + if (bytes.isEmpty()) this.bodyParsed = true; //no body data + } + //鏆備笉鑰冭檻鏄痥eep-alive涓斿瓨鍦╞ody鍗存病鏈夋寚瀹欳ontent-Length鐨勬儏鍐 + return 0; + } + + private int loadHeaderBytes(final ByteBuffer buffer) { + ByteArray bytes = array; + int remain = buffer.remaining(); + byte b1, b2, b3, b4; + for (;;) { + if (remain-- < 4) { //bytes涓嶅瓨鏀綷r\n\r\n杩4涓瓧鑺 + bytes.put(buffer); + buffer.clear(); + if (bytes.length() > 0) { + byte rn1 = 0, rn2 = 0, rn3 = 0; + byte b = bytes.getLastByte(); + if (b == '\r' || b == '\n') { + rn3 = b; + bytes.backCount(); + if (bytes.length() > 0) { + b = bytes.getLastByte(); + if (b == '\r' || b == '\n') { + rn2 = b; + bytes.backCount(); + if (bytes.length() > 0) { + b = bytes.getLastByte(); + if (b == '\r' || b == '\n') { + rn1 = b; + bytes.backCount(); + } + } + } + } + } + if (rn1 != 0) buffer.put(rn1); + if (rn2 != 0) buffer.put(rn2); + if (rn3 != 0) buffer.put(rn3); + } + return 1; + } + b1 = buffer.get(); + bytes.put(b1); + if (b1 == '\r') { + remain--; + b2 = buffer.get(); + bytes.put(b2); + if (b2 == '\n') { + remain--; + b3 = buffer.get(); + bytes.put(b3); + if (b3 == '\r') { + remain--; + b4 = buffer.get(); + bytes.put(b4); + if (b4 == '\n') { + this.headerBytes = Utility.append(this.headerBytes, bytes.content(), 0, bytes.length()); + this.headerLength = this.headerBytes.length; + this.headerHalfLen = this.headerLength; + bytes.clear(); + return 0; + } + } + } + } + } + } + +// @Override +// protected int readBody(ByteBuffer buffer, int length) { +// int len = buffer.remaining(); +// array.put(buffer, len); +// return len; +// } + //瑙f瀽 GET /xxx HTTP/1.1 + private int readMethodLine(final ByteBuffer buffer) { + Charset charset = this.context.getCharset(); + int remain = buffer.remaining(); + int size; + ByteArray bytes = array; + //璇籱ethod + if (this.method == null) { + for (;;) { + if (remain-- < 1) { + buffer.clear(); + return 1; + } + byte b = buffer.get(); + if (b == ' ') break; + bytes.put(b); + } + size = bytes.length(); + if (size == 3 && bytes.get(0) == 'G' && bytes.get(1) == 'E' && bytes.get(2) == 'T') { + this.method = KEY_GET; + this.getmethod = true; + } else if (size == 4 && bytes.get(0) == 'P' && bytes.get(1) == 'O' && bytes.get(2) == 'S' && bytes.get(3) == 'T') { + this.method = KEY_POST; + this.getmethod = false; + } else { + this.method = bytes.toString(charset); + this.getmethod = false; + } + bytes.clear(); + } + //璇籾ri + if (this.requestURI == null) { + int qst = -1;//?鐨勪綅缃 + boolean decodeable = false; + for (;;) { + if (remain-- < 1) { + buffer.clear(); + return 1; + } + byte b = buffer.get(); + if (b == ' ') break; + if (b == '?' && qst < 0) { + qst = bytes.length(); + } else if (!decodeable && (b == '+' || b == '%')) { + decodeable = true; + } + bytes.put(b); + } + size = bytes.length(); + if (qst > 0) { + this.requestURI = decodeable ? toDecodeString(bytes, 0, qst, charset) : bytes.toString(0, qst, charset); + this.queryBytes = bytes.getBytes(qst + 1, size - qst - 1); + this.lastRequestURIString = null; + this.lastRequestURIBytes = null; + try { + addParameter(bytes, qst + 1, size - qst - 1); + } catch (Exception e) { + this.context.getLogger().log(Level.WARNING, "HttpRequest.addParameter error: " + bytes.toString(), e); + } + } else { + if (decodeable) { + this.requestURI = toDecodeString(bytes, 0, bytes.length(), charset); + this.lastRequestURIString = null; + this.lastRequestURIBytes = null; + } else if (context.lazyHeaders) { + byte[] lastURIBytes = lastRequestURIBytes; + if (lastURIBytes != null && lastURIBytes.length == size && bytes.equal(lastURIBytes)) { + this.requestURI = this.lastRequestURIString; + } else { + this.requestURI = bytes.toString(charset); + this.lastRequestURIString = this.requestURI; + this.lastRequestURIBytes = bytes.getBytes(); + } + } else { + this.requestURI = bytes.toString(charset); + } + this.queryBytes = EMPTY_BYTES; + } + bytes.clear(); + } + //璇籶rotocol + for (;;) { + if (remain-- < 1) { + this.params.clear(); + buffer.clear(); + return 1; + } + byte b = buffer.get(); + if (b == '\r') { + if (remain-- < 1) { + this.params.clear(); + buffer.clear(); + buffer.put((byte) '\r'); + return 1; + } + if (buffer.get() != '\n') return -1; + break; + } + bytes.put(b); + } + size = bytes.length(); + if (size == 8 && bytes.get(0) == 'H' && bytes.get(5) == '1' && bytes.get(7) == '1') { + this.protocol = KEY_HTTP_1_1; + } else { + this.protocol = bytes.toString(charset); + } + bytes.clear(); + return 0; + } + + //瑙f瀽Header Connection: keep-alive + private int readHeaderLines(final ByteBuffer buffer, ByteArray bytes) { + Charset charset = this.context.getCharset(); + int remain = buffer.remaining(); + for (;;) { + bytes.clear(); + if (remain-- < 2) { + if (remain == 1) { + byte one = buffer.get(); + buffer.clear(); + buffer.put(one); + return 1; + } + buffer.clear(); + return 1; + } + remain--; + byte b1 = buffer.get(); + byte b2 = buffer.get(); + if (b1 == '\r' && b2 == '\n') return 0; + bytes.put(b1, b2); + for (;;) { // name + if (remain-- < 1) { + buffer.clear(); + buffer.put(bytes.content(), 0, bytes.length()); + return 1; + } + byte b = buffer.get(); + if (b == ':') break; + bytes.put(b); + } + String name = parseHeaderName(bytes, charset); + bytes.clear(); + boolean first = true; + int space = 0; + for (;;) { // value + if (remain-- < 1) { + buffer.clear(); + buffer.put(name.getBytes()); + buffer.put((byte) ':'); + if (space == 1) { + buffer.put((byte) ' '); + } else if (space > 0) { + for (int i = 0; i < space; i++) buffer.put((byte) ' '); + } + buffer.put(bytes.content(), 0, bytes.length()); + return 1; + } + byte b = buffer.get(); + if (b == '\r') { + if (remain-- < 1) { + buffer.clear(); + buffer.put(name.getBytes()); + buffer.put((byte) ':'); + if (space == 1) { + buffer.put((byte) ' '); + } else if (space > 0) { + for (int i = 0; i < space; i++) buffer.put((byte) ' '); + } + buffer.put(bytes.content(), 0, bytes.length()); + buffer.put((byte) '\r'); + return 1; + } + if (buffer.get() != '\n') return -1; + break; + } + if (first) { + if (b <= ' ') { + space++; + continue; + } + first = false; + } + bytes.put(b); + } + String value; + int vallen = bytes.length(); + switch (name) { + case "Content-Type": + case "content-type": + value = bytes.toString(charset); + this.contentType = value; + break; + case "Content-Length": + case "content-length": + value = bytes.toString(charset); + this.contentLength = Long.decode(value); + break; + case "Host": + case "host": + value = bytes.toString(charset); + this.host = value; + break; + case "Cookie": + case "cookie": + value = bytes.toString(charset); + if (this.cookie == null || this.cookie.isEmpty()) { + this.cookie = value; + } else { + this.cookie += ";" + value; + } + break; + case "Connection": + case "connection": + if (vallen > 0) { + if (bytes.get(0) == 'c' && vallen == 5 + && bytes.get(1) == 'l' && bytes.get(2) == 'o' + && bytes.get(3) == 's' && bytes.get(4) == 'e') { + value = "close"; + this.setKeepAlive(false); + } else if (bytes.get(0) == 'k' && vallen == 10 + && bytes.get(1) == 'e' && bytes.get(2) == 'e' + && bytes.get(3) == 'p' && bytes.get(4) == '-' + && bytes.get(5) == 'a' && bytes.get(6) == 'l' + && bytes.get(7) == 'i' && bytes.get(8) == 'v' + && bytes.get(9) == 'e') { + value = "keep-alive"; + //if (context.getAliveTimeoutSeconds() >= 0) { + this.setKeepAlive(true); + //} + } else { + value = bytes.toString(charset); + this.setKeepAlive(true); + } + } else { + value = ""; + } + headers.put("Connection", value); + break; + case "Upgrade": + case "upgrade": + value = bytes.toString(charset); + this.maybews = "websocket".equalsIgnoreCase(value); + headers.put("Upgrade", value); + break; + case "user-agent": + value = bytes.toString(charset); + headers.put("User-Agent", value); + break; + case Rest.REST_HEADER_RPC_NAME: + value = bytes.toString(charset); + this.rpc = "true".equalsIgnoreCase(value); + headers.put(name, value); + break; + case Rest.REST_HEADER_CURRUSERID_NAME: + value = bytes.toString(charset); + this.hashid = value.hashCode(); + this.currentUserid = value; + headers.put(name, value); + break; + case Rest.REST_HEADER_PARAM_FROM_BODY: + value = bytes.toString(charset); + this.frombody = "true".equalsIgnoreCase(value); + headers.put(name, value); + break; + case Rest.REST_HEADER_REQ_CONVERT_TYPE: + value = bytes.toString(charset); + reqConvertType = ConvertType.valueOf(value); + reqConvert = ConvertFactory.findConvert(reqConvertType); + headers.put(name, value); + break; + case Rest.REST_HEADER_RESP_CONVERT_TYPE: + value = bytes.toString(charset); + respConvertType = ConvertType.valueOf(value); + respConvert = ConvertFactory.findConvert(respConvertType); + headers.put(name, value); + break; + default: + value = bytes.toString(charset); + headers.put(name, value); + } + } + } + + private void parseHeader() { + if (headerParsed) return; + headerParsed = true; + if (headerBytes == null) return; + if (array.isEmpty()) { + readHeaderLines(ByteBuffer.wrap(headerBytes), array); + array.clear(); + } else { //array瀛樻湁body鏁版嵁 + readHeaderLines(ByteBuffer.wrap(headerBytes), new ByteArray()); + } + } + + static String parseHeaderName(ByteArray bytes, Charset charset) { + final int size = bytes.length(); + final byte[] bs = bytes.content(); + final byte first = bs[0]; + if (first == 'H' && size == 4) { //Host + if (bs[1] == 'o' && bs[2] == 's' && bs[3] == 't') return KEY_HOST; + } else if (first == 'A' && size == 6) { //Accept + if (bs[1] == 'c' && bs[2] == 'c' && bs[3] == 'e' + && bs[4] == 'p' && bs[5] == 't') return KEY_ACCEPT; + } else if (first == 'C') { + if (size == 10) { //Connection + if (bs[1] == 'o' && bs[2] == 'n' && bs[3] == 'n' + && bs[4] == 'e' && bs[5] == 'c' && bs[6] == 't' + && bs[7] == 'i' && bs[8] == 'o' && bs[9] == 'n') return KEY_CONNECTION; + } else if (size == 12) { //Content-Type + if (bs[1] == 'o' && bs[2] == 'n' && bs[3] == 't' + && bs[4] == 'e' && bs[5] == 'n' && bs[6] == 't' + && bs[7] == '-' && bs[8] == 'T' && bs[9] == 'y' + && bs[10] == 'p' && bs[11] == 'e') return KEY_CONTENT_TYPE; + } else if (size == 6) { //Cookie + if (bs[1] == 'o' && bs[2] == 'o' && bs[3] == 'k' + && bs[4] == 'i' && bs[5] == 'e') return KEY_COOKIE; + } + } + return bytes.toString(charset); + } + + @Override + protected HttpRequest copyHeader() { + if (!pipelineSameHeaders || !context.lazyHeaders) return null; + HttpRequest req = new HttpRequest(context, this.array); + req.headerLength = this.headerLength; + req.headerBytes = this.headerBytes; + req.headerParsed = this.headerParsed; + req.contentType = this.contentType; + req.contentLength = this.contentLength; + req.host = this.host; + req.cookie = this.cookie; + req.cookies = this.cookies; + req.keepAlive = this.keepAlive; + req.maybews = this.maybews; + req.rpc = this.rpc; + req.hashid = this.hashid; + req.currentUserid = this.currentUserid; + req.currentUserSupplier = this.currentUserSupplier; + req.frombody = this.frombody; + req.reqConvertType = this.reqConvertType; + req.reqConvert = this.reqConvert; + req.respConvert = this.respConvert; + req.respConvertType = this.respConvertType; + req.headers.putAll(this.headers); + return req; + } + + @Override + protected void prepare() { + this.keepAlive = true; //榛樿HTTP/1.1 + } + + @Override + protected void recycle() { + //header + this.headerLength = 0; + this.headerHalfLen = 0; + this.headerBytes = null; + this.headerParsed = false; + this.contentType = null; + this.contentLength = -1; + this.host = null; + this.cookie = null; + this.cookies = null; + this.maybews = false; + this.rpc = false; + this.readState = READ_STATE_ROUTE; + this.currentUserid = CURRUSERID_NIL; + this.currentUserSupplier = null; + this.frombody = false; + this.reqConvertType = null; + this.reqConvert = null; + this.respConvert = jsonConvert; + this.respConvertType = null; + this.headers.clear(); + //鍏朵粬 + this.newsessionid = null; + this.method = null; + this.getmethod = false; + this.protocol = null; + this.requestURI = null; + this.queryBytes = null; + this.boundary = false; + this.bodyParsed = false; + this.moduleid = 0; + this.actionid = 0; + this.annotations = null; + this.remoteAddr = null; + this.params.clear(); + this.array.clear(); + //鍐呴儴 + this.actionEntry = null; + super.recycle(); + } + + protected void skipBodyParse() { + this.bodyParsed = true; + } + + private void parseBody() { + if (this.boundary || bodyParsed) return; + bodyParsed = true; + if (this.contentType != null && this.contentType.toLowerCase().contains("x-www-form-urlencoded")) { + addParameter(array, 0, array.length()); + } + } + + private void addParameter(final ByteArray array, final int offset, final int len) { + if (len < 1) return; + Charset charset = this.context.getCharset(); + int limit = offset + len; + int keypos = array.find(offset, limit, '='); + int valpos = array.find(offset, limit, '&'); + if (keypos <= 0 || (valpos >= 0 && valpos < keypos)) { + if (valpos > 0) addParameter(array, valpos + 1, limit - valpos - 1); + return; + } + String name = toDecodeString(array, offset, keypos - offset, charset); + if (name.charAt(0) == '<') return; //鍐呭鍙兘鏄痻ml鏍煎紡; 濡: = 0) { + addParameter(array, valpos + 1, limit - valpos - 1); + } + } + + protected static String toDecodeString(ByteArray array, int offset, int len, final Charset charset) { + byte[] content = array.content(); + int start = offset; + final int end = offset + len; + boolean flag = false; //鏄惁闇瑕佽浆涔 + byte[] bs = content; + for (int i = offset; i < end; i++) { + if (content[i] == '+' || content[i] == '%') { + flag = true; + break; + } + } + if (flag) { + int index = 0; + bs = new byte[len]; + for (int i = offset; i < end; i++) { + switch (content[i]) { + case '+': + bs[index] = ' '; + break; + case '%': + bs[index] = (byte) ((hexBit(content[++i]) * 16 + hexBit(content[++i]))); + break; + default: + bs[index] = content[i]; + break; + } + index++; + } + start = 0; + len = index; + } + if (charset == null) return new String(bs, start, len, StandardCharsets.UTF_8); + return new String(bs, start, len, charset); + } + + private static int hexBit(byte b) { + if ('0' <= b && '9' >= b) return b - '0'; + if ('a' <= b && 'z' >= b) return b - 'a' + 10; + if ('A' <= b && 'Z' >= b) return b - 'A' + 10; + return b; + } + + @Override + protected T setProperty(String name, T value) { + return super.setProperty(name, value); + } + + @Override + @SuppressWarnings("unchecked") + protected T getProperty(String name) { + return super.getProperty(name); + } + + @Override + protected T removeProperty(String name) { + return super.removeProperty(name); + } + + /** + * 璁剧疆褰撳墠鐢ㄦ埛ID, 閫氬父鍦℉ttpServlet.preExecute鏂规硶閲岃缃甤urrentUserid
+ * 鏁版嵁绫诲瀷鍙兘鏄痠nt銆乴ong銆丼tring銆丣avaBean + * + * @param 娉涘瀷 + * @param userid 鐢ㄦ埛ID + * + * @return HttpRequest + * + * @since 2.1.0 + */ + public HttpRequest setCurrentUserid(T userid) { + this.currentUserid = userid; + return this; + } + + /** + * 鑾峰彇褰撳墠鐢ㄦ埛ID鐨刬nt鍊
+ * + * @return 鐢ㄦ埛ID + * + * @since 2.4.0 + */ + @SuppressWarnings("unchecked") + public int currentIntUserid() { + if (currentUserid == CURRUSERID_NIL || currentUserid == null) return 0; + if (this.currentUserid instanceof Number) return ((Number) this.currentUserid).intValue(); + String uid = this.currentUserid.toString(); + return uid.isEmpty() ? 0 : Integer.parseInt(uid); + } + + /** + * 鑾峰彇褰撳墠鐢ㄦ埛ID
+ * + * @param 鏁版嵁绫诲瀷鍙兘鏄痠nt銆乴ong銆丼tring銆丣avaBean + * @param type 绫诲瀷 + * + * @return 鐢ㄦ埛ID + * + * @since 2.1.0 + */ + @SuppressWarnings("unchecked") + public T currentUserid(Class type) { + if (currentUserid == CURRUSERID_NIL || currentUserid == null) { + if (type == int.class) return (T) (Integer) (int) 0; + if (type == long.class) return (T) (Long) (long) 0; + return null; + } + if (type == int.class) { + if (this.currentUserid instanceof Number) return (T) (Integer) ((Number) this.currentUserid).intValue(); + String uid = this.currentUserid.toString(); + return (T) (Integer) (uid.isEmpty() ? 0 : Integer.parseInt(uid)); + } + if (type == long.class) { + if (this.currentUserid instanceof Number) return (T) (Long) ((Number) this.currentUserid).longValue(); + String uid = this.currentUserid.toString(); + return (T) (Long) (uid.isEmpty() ? 0L : Long.parseLong(uid)); + } + if (type == String.class) return (T) this.currentUserid.toString(); + if (this.currentUserid instanceof CharSequence) return JsonConvert.root().convertFrom(type, this.currentUserid.toString()); + return (T) this.currentUserid; + } + + /** + * 寤鸿浣跨敤 setCurrentUserid, 閫氳繃userid浠嶴ervice鎴栫紦瀛樹腑鑾峰彇鐢ㄦ埛淇℃伅
+ * 璁剧疆褰撳墠鐢ㄦ埛淇℃伅, 閫氬父鍦℉ttpServlet.preExecute鏂规硶閲岃缃甤urrentUser
+ * 鏁版嵁绫诲瀷鐢@HttpUserType鎸囧畾 + * + * @param supplier currentUser瀵硅薄鏂规硶 + * + * @since 2.4.0 + * + * @return HttpRequest + */ + public HttpRequest setCurrentUserSupplier(Supplier supplier) { + this.currentUserSupplier = supplier; + return this; + } + + /** + * 寤鸿浣跨敤 currentUserid, 閫氳繃userid浠嶴ervice鎴栫紦瀛樹腑鑾峰彇鐢ㄦ埛淇℃伅
+ * 鑾峰彇褰撳墠鐢ㄦ埛淇℃伅
+ * 鏁版嵁绫诲瀷鐢@HttpUserType鎸囧畾 + * + * @param @HttpUserType鎸囧畾鐨勭敤鎴蜂俊鎭被鍨 + * + * @return 鐢ㄦ埛淇℃伅 + */ + @SuppressWarnings("unchecked") + public T currentUser() { + Supplier supplier = this.currentUserSupplier; + return (T) (supplier == null ? null : supplier.get()); + } + + /** + * 鑾峰彇妯″潡ID锛屾潵鑷@HttpServlet.moduleid() + * + * @return 妯″潡ID + */ + @ConvertDisabled + public int getModuleid() { + return this.moduleid; + } + + /** + * 鑾峰彇鎿嶄綔ID锛屾潵鑷@HttpMapping.actionid() + * + * @return 妯″潡ID + */ + @ConvertDisabled + public int getActionid() { + return this.actionid; + } + + /** + * 鑾峰彇褰撳墠鎿嶄綔Method涓婄殑娉ㄨВ闆嗗悎 + * + * @return Annotation[] + */ + @ConvertDisabled + public Annotation[] getAnnotations() { + if (this.annotations == null) return new Annotation[0]; + Annotation[] newanns = new Annotation[this.annotations.length]; + System.arraycopy(this.annotations, 0, newanns, 0, newanns.length); + return newanns; + } + + /** + * 鑾峰彇褰撳墠鎿嶄綔Method涓婄殑娉ㄨВ + * + * @param 娉ㄨВ娉涘瀷 + * @param annotationClass 娉ㄨВ绫诲瀷 + * + * @return Annotation + */ + public T getAnnotation(Class annotationClass) { + if (this.annotations == null) return null; + for (Annotation ann : this.annotations) { + if (ann.getClass() == annotationClass) return (T) ann; + } + return null; + } + + /** + * 鑾峰彇褰撳墠鎿嶄綔Method涓婄殑娉ㄨВ闆嗗悎 + * + * @param 娉ㄨВ娉涘瀷 + * @param annotationClass 娉ㄨВ绫诲瀷 + * + * @return Annotation[] + */ + public T[] getAnnotationsByType(Class annotationClass) { + if (this.annotations == null) return (T[]) Array.newInstance(annotationClass, 0); + T[] news = (T[]) Array.newInstance(annotationClass, this.annotations.length); + int index = 0; + for (Annotation ann : this.annotations) { + if (ann.getClass() == annotationClass) { + news[index++] = (T) ann; + } + } + if (index < 1) return (T[]) Array.newInstance(annotationClass, 0); + return Arrays.copyOf(news, index); + } + + /** + * 鑾峰彇瀹㈡埛绔湴鍧IP + * + * @return 鍦板潃 + */ + @ConvertDisabled + public SocketAddress getRemoteAddress() { + return this.channel == null || !this.channel.isOpen() ? null : this.channel.getRemoteAddress(); + } + + /** + * 鑾峰彇瀹㈡埛绔湴鍧IP, 涓巊etRemoteAddress() 鐨勫尯鍒湪浜庯細鏈柟娉曚紭鍏堝彇header涓寚瀹氫负RemoteAddress鍚嶇殑鍊硷紝娌℃湁鍒欒繑鍥瀏etRemoteAddress()鐨刧etHostAddress()銆
+ * 鏈柟娉曢傜敤浜庢湇鍔″墠绔湁濡俷ginx鐨勪唬鐞嗘湇鍔″櫒杩涜涓浆锛岄氳繃 getRemoteAddress()鏄幏鍙栦笉鍒板鎴风鐨勭湡瀹濱P銆 + * + * @return 鍦板潃 + */ + public String getRemoteAddr() { + if (this.remoteAddr != null) return this.remoteAddr; + parseHeader(); + if (remoteAddrHeader != null) { + String val = getHeader(remoteAddrHeader); + if (val != null) { + this.remoteAddr = val; + return val; + } + } + SocketAddress addr = getRemoteAddress(); + if (addr == null) return ""; + if (addr instanceof InetSocketAddress) { + this.remoteAddr = ((InetSocketAddress) addr).getAddress().getHostAddress(); + return this.remoteAddr; + } + this.remoteAddr = String.valueOf(addr); + return this.remoteAddr; + } + + /** + * 鑾峰彇璇锋眰鍐呭鎸囧畾鐨勭紪鐮佸瓧绗︿覆 + * + * @param charset 缂栫爜 + * + * @return 鍐呭 + */ + public String getBody(final Charset charset) { + return charset == null ? array.toString() : array.toString(charset); + } + + /** + * 鑾峰彇璇锋眰鍐呭鐨刄TF-8缂栫爜瀛楃涓 + * + * @return 鍐呭 + */ + @ConvertDisabled + public String getBodyUTF8() { + return array.toString(StandardCharsets.UTF_8); + } + + /** + * 鑾峰彇璇锋眰鍐呭鐨凧avaBean瀵硅薄 + * + * @param 娉涘瀷 + * @param type 绫诲瀷 + * + * @return 鍐呭 + */ + public T getBodyJson(java.lang.reflect.Type type) { + if (array == null || array.isEmpty()) return null; + Convert convert = this.reqConvert; + if (convert == null) convert = context.getJsonConvert(); + if (type == byte[].class) return (T) array.getBytes(); + return (T) convert.convertFrom(type, array.content()); + } + + /** + * 鑾峰彇璇锋眰鍐呭鐨凧avaBean瀵硅薄 + * + * @param 娉涘瀷 + * @param convert Convert + * @param type 绫诲瀷 + * + * @return 鍐呭 + */ + public T getBodyJson(Convert convert, java.lang.reflect.Type type) { + if (array.isEmpty()) return null; + if (type == byte[].class) return (T) array.getBytes(); + return (T) convert.convertFrom(type, array.content()); + } + + /** + * 鑾峰彇璇锋眰鍐呭鐨刡yte[] + * + * @return 鍐呭 + */ + public byte[] getBody() { + return array.length() == 0 ? null : array.getBytes(); + } + + /** + * 鐩存帴鑾峰彇body瀵硅薄 + * + * @return body瀵硅薄 + */ + @ConvertDisabled + protected ByteArray getDirectBody() { + return array; + } + + @Override + public String toString() { + parseBody(); + return this.getClass().getSimpleName() + "{\r\n method: " + this.method + ", \r\n requestURI: " + this.requestURI + + (this.frombody ? (", \r\n frombody: " + this.frombody) : "") + + (this.reqConvertType != null ? (", \r\n reqConvertType: " + this.reqConvertType) : "") + + (this.respConvertType != null ? (", \r\n respConvertType: " + this.respConvertType) : "") + + ", \r\n currentUserid: " + (this.currentUserid == CURRUSERID_NIL ? null : this.currentUserid) + ", \r\n remoteAddr: " + this.getRemoteAddr() + + ", \r\n cookies: " + this.cookie + ", \r\n contentType: " + this.contentType + + ", \r\n protocol: " + this.protocol + ", \r\n host: " + this.host + + ", \r\n contentLength: " + this.contentLength + ", \r\n bodyLength: " + this.array.length() + + (this.boundary || this.array.isEmpty() ? "" : (", \r\n bodyContent: " + (this.respConvertType == null || this.respConvertType == ConvertType.JSON ? this.getBodyUTF8() : Arrays.toString(getBody())))) + + ", \r\n params: " + toMapString(this.params, 4) + ", \r\n header: " + toMapString(this.headers, 4) + "\r\n}"; //this.headers.toString(4) + } + + private static CharSequence toMapString(Map map, int indent) { + char[] chars = new char[indent]; + Arrays.fill(chars, ' '); + final String space = new String(chars); + StringBuilder sb = new StringBuilder(); + sb.append("{\r\n"); + for (Map.Entry en : map.entrySet()) { + sb.append(space).append(" '").append(en.getKey()).append("': '").append(en.getValue()).append("',\r\n"); + } + sb.append(space).append('}'); + return sb; + } + + /** + * 鑾峰彇鏂囦欢涓婁紶瀵硅薄 + * + * @return 鏂囦欢涓婁紶瀵硅薄 + */ + @ConvertDisabled + public final MultiContext getMultiContext() { + final InputStream in = newInputStream(); + return new MultiContext(context.getCharset(), this.getContentType(), this.params, + new BufferedInputStream(in, Math.max(array.length(), 8192)) { + { + array.copyTo(this.buf); + this.count = array.length(); + } + }, null); + } + + /** + * 鏄惁涓婁紶鏂囦欢璇锋眰 + * + * @return boolean + */ + public final boolean isMultipart() { + return boundary; + } + + /** + * 鑾峰彇鏂囦欢涓婁紶淇℃伅鍒楄〃 + * + * @return 鏂囦欢涓婁紶瀵硅薄闆嗗悎 + * + * @throws IOException IO寮傚父 + */ + @ConvertDisabled + public final Iterable multiParts() throws IOException { + return getMultiContext().parts(); + } + + /** + * 鑾峰彇sessionid + * + * @param create 鏃爏essionid鏄惁鑷姩鍒涘缓 + * + * @return sessionid + */ + @ConvertDisabled + public String getSessionid(boolean create) { + String sessionid = getCookie(SESSIONID_NAME, null); + if (create && (sessionid == null || sessionid.isEmpty())) { + sessionid = context.createSessionid(); + this.newsessionid = sessionid; + } + return sessionid; + } + + /** + * 鏇存柊sessionid + * + * @return 鏂扮殑sessionid鍊 + */ + public String changeSessionid() { + this.newsessionid = context.createSessionid(); + return newsessionid; + } + + /** + * 鎸囧畾鍊兼洿鏂皊essionid + * + * @param newsessionid 鏂皊essionid鍊 + * + * @return 鏂扮殑sessionid鍊 + */ + public String changeSessionid(String newsessionid) { + this.newsessionid = newsessionid == null ? context.createSessionid() : newsessionid.trim(); + return newsessionid; + } + + /** + * 浣縮essionid澶辨晥 + */ + public void invalidateSession() { + this.newsessionid = ""; //涓虹┖琛ㄧず鍒犻櫎sessionid + } + + /** + * 鑾峰彇鎵鏈塁ookie瀵硅薄 + * + * @return cookie瀵硅薄鏁扮粍 + */ + public HttpCookie[] getCookies() { + parseHeader(); + if (this.cookies == null) this.cookies = parseCookies(this.cookie); + return this.cookies.length == 0 ? null : this.cookies; + } + + /** + * 鑾峰彇Cookie鍊 + * + * @param name cookie鍚 + * + * @return cookie鍊 + */ + public String getCookie(String name) { + return getCookie(name, null); + } + + /** + * 鑾峰彇Cookie鍊硷紝 娌℃湁杩斿洖榛樿鍊 + * + * @param name cookie鍚 + * @param dfvalue 榛樿cookie鍊 + * + * @return cookie鍊 + */ + public String getCookie(String name, String dfvalue) { + HttpCookie[] cs = getCookies(); + if (cs == null) return dfvalue; + for (HttpCookie c : cs) { + if (name.equals(c.getName())) return c.getValue(); + } + return dfvalue; + } + + private static HttpCookie[] parseCookies(String cookiestr) { + if (cookiestr == null || cookiestr.isEmpty()) return new HttpCookie[0]; + String str = cookiestr.replaceAll("(^;)|(;$)", "").replaceAll(";+", ";"); + if (str.isEmpty()) return new HttpCookie[0]; + String[] strs = str.split(";"); + HttpCookie[] cookies = new HttpCookie[strs.length]; + for (int i = 0; i < strs.length; i++) { + String s = strs[i]; + int pos = s.indexOf('='); + String v = (pos < 0 ? "" : s.substring(pos + 1)); + if (v.indexOf('"') == 0 && v.lastIndexOf('"') == v.length() - 1) v = v.substring(1, v.length() - 1); + cookies[i] = new HttpCookie((pos < 0 ? s : s.substring(0, pos)), v); + } + return cookies; + } + + /** + * 鑾峰彇鍗忚鍚 http銆乭ttps銆亀s銆亀ss绛 + * + * @return protocol + */ + public String getProtocol() { + return protocol; + } + + /** + * 鑾峰彇璇锋眰鏂规硶 GET銆丳OST绛 + * + * @return method + */ + public String getMethod() { + return method; + } + + /** + * 鑾峰彇Content-Type鐨刪eader鍊 + * + * @return contentType + */ + public String getContentType() { + return contentType; + } + + /** + * 鑾峰彇璇锋眰鍐呭鐨勯暱搴, 涓-1琛ㄧず鍐呭闀垮害涓嶇‘瀹 + * + * @return 鍐呭闀垮害 + */ + public long getContentLength() { + return contentLength; + } + + /** + * 鑾峰彇Host鐨凥eader鍊 + * + * @return Host + */ + public String getHost() { + return host; + } + + /** + * 鑾峰彇璇锋眰鐨刄RL + * + * @return 璇锋眰鐨刄RL + */ + public String getRequestURI() { + return requestURI; + } + + /** + * 鑾峰彇璇锋眰鍙傛暟鐨刡yte[] + * + * @return byte[] + */ + public byte[] getQueryBytes() { + return queryBytes; + } + + /** + * 鎴彇getRequestURI鏈鍚庣殑涓涓/鍚庨潰鐨勯儴鍒 + * + * @return String + */ + @ConvertDisabled + public String getRequstURILastPath() { + if (requestURI == null) return ""; + return requestURI.substring(requestURI.lastIndexOf('/') + 1); + } + + /** + * 鑾峰彇璇锋眰URL鏈鍚庣殑涓涓/鍚庨潰鐨勯儴鍒嗙殑short鍊
+ * 渚嬪璇锋眰URL /pipes/user/query/2
+ * 鑾峰彇type鍙傛暟: short type = request.getRequstURILastPath((short)0); //type = 2 + * + * @param defvalue 榛樿short鍊 + * + * @return short鍊 + */ + public short getRequstURILastPath(short defvalue) { + String val = getRequstURILastPath(); + if (val.isEmpty()) return defvalue; + try { + return Short.parseShort(val); + } catch (NumberFormatException e) { + return defvalue; + } + } + + /** + * 鑾峰彇璇锋眰URL鏈鍚庣殑涓涓/鍚庨潰鐨勯儴鍒嗙殑short鍊
+ * 渚嬪璇锋眰URL /pipes/user/query/2
+ * 鑾峰彇type鍙傛暟: short type = request.getRequstURILastPath(16, (short)0); //type = 2 + * + * @param radix 杩涘埗鏁 + * @param defvalue 榛樿short鍊 + * + * @return short鍊 + */ + public short getRequstURILastPath(int radix, short defvalue) { + String val = getRequstURILastPath(); + if (val.isEmpty()) return defvalue; + try { + return Short.parseShort(val, radix); + } catch (NumberFormatException e) { + return defvalue; + } + } + + /** + * 鑾峰彇璇锋眰URL鏈鍚庣殑涓涓/鍚庨潰鐨勯儴鍒嗙殑int鍊
+ * 渚嬪璇锋眰URL /pipes/user/query/2
+ * 鑾峰彇type鍙傛暟: int type = request.getRequstURILastPath(0); //type = 2 + * + * @param defvalue 榛樿int鍊 + * + * @return int鍊 + */ + public int getRequstURILastPath(int defvalue) { + String val = getRequstURILastPath(); + try { + return val.isEmpty() ? defvalue : Integer.parseInt(val); + } catch (NumberFormatException e) { + return defvalue; + } + } + + /** + * 鑾峰彇璇锋眰URL鏈鍚庣殑涓涓/鍚庨潰鐨勯儴鍒嗙殑int鍊
+ * 渚嬪璇锋眰URL /pipes/user/query/2
+ * 鑾峰彇type鍙傛暟: int type = request.getRequstURILastPath(16, 0); //type = 2 + * + * @param radix 杩涘埗鏁 + * @param defvalue 榛樿int鍊 + * + * @return int鍊 + */ + public int getRequstURILastPath(int radix, int defvalue) { + String val = getRequstURILastPath(); + try { + return val.isEmpty() ? defvalue : Integer.parseInt(val, radix); + } catch (NumberFormatException e) { + return defvalue; + } + } + + /** + * 鑾峰彇璇锋眰URL鏈鍚庣殑涓涓/鍚庨潰鐨勯儴鍒嗙殑float鍊
+ * 渚嬪璇锋眰URL /pipes/user/query/2
+ * 鑾峰彇type鍙傛暟: float type = request.getRequstURILastPath(0.0f); //type = 2.0f + * + * @param defvalue 榛樿float鍊 + * + * @return float鍊 + */ + public float getRequstURILastPath(float defvalue) { + String val = getRequstURILastPath(); + try { + return val.isEmpty() ? defvalue : Float.parseFloat(val); + } catch (NumberFormatException e) { + return defvalue; + } + } + + /** + * 鑾峰彇璇锋眰URL鏈鍚庣殑涓涓/鍚庨潰鐨勯儴鍒嗙殑int鍊
+ * 渚嬪璇锋眰URL /pipes/user/query/2
+ * 鑾峰彇type鍙傛暟: long type = request.getRequstURILastPath(0L); //type = 2 + * + * @param defvalue 榛樿long鍊 + * + * @return long鍊 + */ + public long getRequstURILastPath(long defvalue) { + String val = getRequstURILastPath(); + try { + return val.isEmpty() ? defvalue : Long.parseLong(val); + } catch (NumberFormatException e) { + return defvalue; + } + } + + /** + * 鑾峰彇璇锋眰URL鏈鍚庣殑涓涓/鍚庨潰鐨勯儴鍒嗙殑int鍊
+ * 渚嬪璇锋眰URL /pipes/user/query/2
+ * 鑾峰彇type鍙傛暟: long type = request.getRequstURILastPath(16, 0L); //type = 2 + * + * @param radix 杩涘埗鏁 + * @param defvalue 榛樿long鍊 + * + * @return long鍊 + */ + public long getRequstURILastPath(int radix, long defvalue) { + String val = getRequstURILastPath(); + try { + return val.isEmpty() ? defvalue : Long.parseLong(val, radix); + } catch (NumberFormatException e) { + return defvalue; + } + } + + /** + * 鑾峰彇璇锋眰URL鏈鍚庣殑涓涓/鍚庨潰鐨勯儴鍒嗙殑double鍊
+ * 渚嬪璇锋眰URL /pipes/user/query/2
+ * 鑾峰彇type鍙傛暟: double type = request.getRequstURILastPath(0.0); //type = 2.0 + * + * @param defvalue 榛樿double鍊 + * + * @return double鍊 + */ + public double getRequstURILastPath(double defvalue) { + String val = getRequstURILastPath(); + try { + return val.isEmpty() ? defvalue : Double.parseDouble(val); + } catch (NumberFormatException e) { + return defvalue; + } + } + + /** + * + * 浠巔refix涔嬪悗鎴彇getRequestURI鍐嶅"/"杩涜鍒嗛殧 + *

+ * @param prefix 鍓嶇紑 + * + * @return String[] + */ + public String[] getRequstURIPaths(String prefix) { + if (requestURI == null || prefix == null) return new String[0]; + return requestURI.substring(requestURI.indexOf(prefix) + prefix.length() + (prefix.endsWith("/") ? 0 : 1)).split("/"); + } + + /** + * 鑾峰彇璇锋眰URL鍒嗘涓惈prefix娈电殑鍊
+ * 渚嬪璇锋眰URL /pipes/user/query/name:hello
+ * 鑾峰彇name鍙傛暟: String name = request.getRequstURIPath("name:", "none"); + * + * @param prefix prefix娈靛墠缂 + * @param defvalue 榛樿鍊 + * + * @return prefix鎴柇鍚庣殑鍊 + */ + public String getRequstURIPath(String prefix, String defvalue) { + if (requestURI == null || prefix == null || prefix.isEmpty()) return defvalue; + int pos = requestURI.indexOf(prefix); + if (pos < 0) return defvalue; + String sub = requestURI.substring(pos + prefix.length()); + pos = sub.indexOf('/'); + return pos < 0 ? sub : sub.substring(0, pos); + } + + /** + * 鑾峰彇璇锋眰URL鍒嗘涓惈prefix娈电殑short鍊
+ * 渚嬪璇锋眰URL /pipes/user/query/type:10
+ * 鑾峰彇type鍙傛暟: short type = request.getRequstURIPath("type:", (short)0); + * + * @param prefix prefix娈靛墠缂 + * @param defvalue 榛樿short鍊 + * + * @return short鍊 + */ + public short getRequstURIPath(String prefix, short defvalue) { + String val = getRequstURIPath(prefix, null); + try { + return val == null ? defvalue : Short.parseShort(val); + } catch (NumberFormatException e) { + return defvalue; + } + } + + /** + * 鑾峰彇璇锋眰URL鍒嗘涓惈prefix娈电殑short鍊
+ * 渚嬪璇锋眰URL /pipes/user/query/type:a
+ * 鑾峰彇type鍙傛暟: short type = request.getRequstURIPath(16, "type:", (short)0); //type = 10 + * + * @param radix 杩涘埗鏁 + * @param prefix prefix娈靛墠缂 + * @param defvalue 榛樿short鍊 + * + * @return short鍊 + */ + public short getRequstURIPath(int radix, String prefix, short defvalue) { + String val = getRequstURIPath(prefix, null); + try { + return val == null ? defvalue : Short.parseShort(val, radix); + } catch (NumberFormatException e) { + return defvalue; + } + } + + /** + * 鑾峰彇璇锋眰URL鍒嗘涓惈prefix娈电殑int鍊
+ * 渚嬪璇锋眰URL /pipes/user/query/offset:0/limit:50
+ * 鑾峰彇offset鍙傛暟: int offset = request.getRequstURIPath("offset:", 0);
+ * 鑾峰彇limit鍙傛暟: int limit = request.getRequstURIPath("limit:", 20);
+ * + * @param prefix prefix娈靛墠缂 + * @param defvalue 榛樿int鍊 + * + * @return int鍊 + */ + public int getRequstURIPath(String prefix, int defvalue) { + String val = getRequstURIPath(prefix, null); + try { + return val == null ? defvalue : Integer.parseInt(val); + } catch (NumberFormatException e) { + return defvalue; + } + } + + /** + * 鑾峰彇璇锋眰URL鍒嗘涓惈prefix娈电殑int鍊
+ * 渚嬪璇锋眰URL /pipes/user/query/offset:0/limit:50
+ * 鑾峰彇offset鍙傛暟: int offset = request.getRequstURIPath("offset:", 0);
+ * 鑾峰彇limit鍙傛暟: int limit = request.getRequstURIPath(16, "limit:", 20); // limit = 16
+ * + * @param radix 杩涘埗鏁 + * @param prefix prefix娈靛墠缂 + * @param defvalue 榛樿int鍊 + * + * @return int鍊 + */ + public int getRequstURIPath(int radix, String prefix, int defvalue) { + String val = getRequstURIPath(prefix, null); + try { + return val == null ? defvalue : Integer.parseInt(val, radix); + } catch (NumberFormatException e) { + return defvalue; + } + } + + /** + * 鑾峰彇璇锋眰URL鍒嗘涓惈prefix娈电殑float鍊
+ * 渚嬪璇锋眰URL /pipes/user/query/point:40.0
+ * 鑾峰彇time鍙傛暟: float point = request.getRequstURIPath("point:", 0.0f); + * + * @param prefix prefix娈靛墠缂 + * @param defvalue 榛樿float鍊 + * + * @return float鍊 + */ + public float getRequstURIPath(String prefix, float defvalue) { + String val = getRequstURIPath(prefix, null); + try { + return val == null ? defvalue : Float.parseFloat(val); + } catch (NumberFormatException e) { + return defvalue; + } + } + + /** + * 鑾峰彇璇锋眰URL鍒嗘涓惈prefix娈电殑long鍊
+ * 渚嬪璇锋眰URL /pipes/user/query/time:1453104341363/id:40
+ * 鑾峰彇time鍙傛暟: long time = request.getRequstURIPath("time:", 0L); + * + * @param prefix prefix娈靛墠缂 + * @param defvalue 榛樿long鍊 + * + * @return long鍊 + */ + public long getRequstURIPath(String prefix, long defvalue) { + String val = getRequstURIPath(prefix, null); + try { + return val == null ? defvalue : Long.parseLong(val); + } catch (NumberFormatException e) { + return defvalue; + } + } + + /** + * 鑾峰彇璇锋眰URL鍒嗘涓惈prefix娈电殑long鍊
+ * 渚嬪璇锋眰URL /pipes/user/query/time:1453104341363/id:40
+ * 鑾峰彇time鍙傛暟: long time = request.getRequstURIPath(16, "time:", 0L); + * + * @param radix 杩涘埗鏁 + * @param prefix prefix娈靛墠缂 + * @param defvalue 榛樿long鍊 + * + * @return long鍊 + */ + public long getRequstURIPath(int radix, String prefix, long defvalue) { + String val = getRequstURIPath(prefix, null); + try { + return val == null ? defvalue : Long.parseLong(val, radix); + } catch (NumberFormatException e) { + return defvalue; + } + } + + /** + * 鑾峰彇璇锋眰URL鍒嗘涓惈prefix娈电殑double鍊
+ * 渚嬪璇锋眰URL /pipes/user/query/point:40.0
+ * 鑾峰彇time鍙傛暟: double point = request.getRequstURIPath("point:", 0.0); + * + * @param prefix prefix娈靛墠缂 + * @param defvalue 榛樿double鍊 + * + * @return double鍊 + */ + public double getRequstURIPath(String prefix, double defvalue) { + String val = getRequstURIPath(prefix, null); + try { + return val == null ? defvalue : Double.parseDouble(val); + } catch (NumberFormatException e) { + return defvalue; + } + } + + //------------------------------------------------------------------------------ + /** + * 鑾峰彇璇锋眰Header鎬诲璞 + * + * @return AnyValue + */ + public Map getHeaders() { + parseHeader(); + return headers; + } + + /** + * 灏嗚姹侶eader杞崲鎴怣ap + * + * @param map Map + * + * @return Map + */ + @ConvertDisabled + public Map getHeadersToMap(Map map) { + parseHeader(); + if (map == null) map = new LinkedHashMap<>(); + final Map map0 = map; + headers.forEach((k, v) -> map0.put(k, v)); + return map0; + } + + /** + * 鑾峰彇鎵鏈夌殑header鍚 + * + * @return header鍚嶆暟缁 + */ + @ConvertDisabled + public String[] getHeaderNames() { + parseHeader(); + Set names = headers.keySet(); + return names.toArray(new String[names.size()]); + } + + /** + * 鑾峰彇鎸囧畾鐨刪eader鍊 + * + * @param name header鍚 + * + * @return header鍊 + */ + public String getHeader(String name) { + parseHeader(); + return headers.get(name); + } + + /** + * 鑾峰彇鎸囧畾鐨刪eader鍊, 娌℃湁杩斿洖榛樿鍊 + * + * @param name header鍚 + * @param defaultValue 榛樿鍊 + * + * @return header鍊 + */ + public String getHeader(String name, String defaultValue) { + parseHeader(); + return headers.getOrDefault(name, defaultValue); + } + + /** + * 鑾峰彇鎸囧畾鐨刪eader鐨刯son鍊 + * + * @param 娉涘瀷 + * @param type 鍙嶅簭鍒楀寲鐨勭被鍚 + * @param name header鍚 + * + * @return header鍊 + */ + public T getJsonHeader(java.lang.reflect.Type type, String name) { + String v = getHeader(name); + return v == null || v.isEmpty() ? null : jsonConvert.convertFrom(type, v); + } + + /** + * 鑾峰彇鎸囧畾鐨刪eader鐨刯son鍊 + * + * @param 娉涘瀷 + * @param convert JsonConvert瀵硅薄 + * @param type 鍙嶅簭鍒楀寲鐨勭被鍚 + * @param name header鍚 + * + * @return header鍊 + */ + public T getJsonHeader(JsonConvert convert, java.lang.reflect.Type type, String name) { + String v = getHeader(name); + return v == null || v.isEmpty() ? null : convert.convertFrom(type, v); + } + + /** + * 鑾峰彇鎸囧畾鐨刪eader鐨刡oolean鍊, 娌℃湁杩斿洖榛樿boolean鍊 + * + * @param name header鍚 + * @param defaultValue 榛樿boolean鍊 + * + * @return header鍊 + */ + public boolean getBooleanHeader(String name, boolean defaultValue) { + //return headers.getBoolValue(name, defaultValue); + parseHeader(); + String value = headers.get(name); + return value == null || value.length() == 0 ? defaultValue : Boolean.parseBoolean(value); + } + + /** + * 鑾峰彇鎸囧畾鐨刪eader鐨剆hort鍊, 娌℃湁杩斿洖榛樿short鍊 + * + * @param name header鍚 + * @param defaultValue 榛樿short鍊 + * + * @return header鍊 + */ + public short getShortHeader(String name, short defaultValue) { + //return headers.getShortValue(name, defaultValue); + parseHeader(); + String value = headers.get(name); + if (value == null || value.length() == 0) return defaultValue; + try { + return Short.decode(value); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + /** + * 鑾峰彇鎸囧畾鐨刪eader鐨剆hort鍊, 娌℃湁杩斿洖榛樿short鍊 + * + * @param radix 杩涘埗鏁 + * @param name header鍚 + * @param defaultValue 榛樿short鍊 + * + * @return header鍊 + */ + public short getShortHeader(int radix, String name, short defaultValue) { + //return headers.getShortValue(name, defaultValue); + parseHeader(); + String value = headers.get(name); + if (value == null || value.length() == 0) return defaultValue; + try { + return (radix == 10 ? Short.decode(value) : Short.parseShort(value, radix)); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + /** + * 鑾峰彇鎸囧畾鐨刪eader鐨剆hort鍊, 娌℃湁杩斿洖榛樿short鍊 + * + * @param name header鍚 + * @param defaultValue 榛樿short鍊 + * + * @return header鍊 + */ + public short getShortHeader(String name, int defaultValue) { + //return headers.getShortValue(name, (short) defaultValue); + parseHeader(); + String value = headers.get(name); + if (value == null || value.length() == 0) return (short) defaultValue; + try { + return Short.decode(value); + } catch (NumberFormatException e) { + return (short) defaultValue; + } + } + + /** + * 鑾峰彇鎸囧畾鐨刪eader鐨剆hort鍊, 娌℃湁杩斿洖榛樿short鍊 + * + * @param radix 杩涘埗鏁 + * @param name header鍚 + * @param defaultValue 榛樿short鍊 + * + * @return header鍊 + */ + public short getShortHeader(int radix, String name, int defaultValue) { + //return headers.getShortValue(radix, name, (short) defaultValue); + parseHeader(); + String value = headers.get(name); + if (value == null || value.length() == 0) return (short) defaultValue; + try { + return (radix == 10 ? Short.decode(value) : Short.parseShort(value, radix)); + } catch (NumberFormatException e) { + return (short) defaultValue; + } + } + + /** + * 鑾峰彇鎸囧畾鐨刪eader鐨刬nt鍊, 娌℃湁杩斿洖榛樿int鍊 + * + * @param name header鍚 + * @param defaultValue 榛樿int鍊 + * + * @return header鍊 + */ + public int getIntHeader(String name, int defaultValue) { + //return headers.getIntValue(name, defaultValue); + parseHeader(); + String value = headers.get(name); + if (value == null || value.length() == 0) return defaultValue; + try { + return Integer.parseInt(value); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + /** + * 鑾峰彇鎸囧畾鐨刪eader鐨刬nt鍊, 娌℃湁杩斿洖榛樿int鍊 + * + * @param radix 杩涘埗鏁 + * @param name header鍚 + * @param defaultValue 榛樿int鍊 + * + * @return header鍊 + */ + public int getIntHeader(int radix, String name, int defaultValue) { + //return headers.getIntValue(radix, name, defaultValue); + parseHeader(); + String value = headers.get(name); + if (value == null || value.length() == 0) return defaultValue; + try { + return (radix == 10 ? Integer.decode(value) : Integer.parseInt(value, radix)); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + /** + * 鑾峰彇鎸囧畾鐨刪eader鐨刲ong鍊, 娌℃湁杩斿洖榛樿long鍊 + * + * @param name header鍚 + * @param defaultValue 榛樿long鍊 + * + * @return header鍊 + */ + public long getLongHeader(String name, long defaultValue) { + //return headers.getLongValue(name, defaultValue); + parseHeader(); + String value = headers.get(name); + if (value == null || value.length() == 0) return defaultValue; + try { + return Long.decode(value); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + /** + * 鑾峰彇鎸囧畾鐨刪eader鐨刲ong鍊, 娌℃湁杩斿洖榛樿long鍊 + * + * @param radix 杩涘埗鏁 + * @param name header鍚 + * @param defaultValue 榛樿long鍊 + * + * @return header鍊 + */ + public long getLongHeader(int radix, String name, long defaultValue) { + //return headers.getLongValue(radix, name, defaultValue); + parseHeader(); + String value = headers.get(name); + if (value == null || value.length() == 0) return defaultValue; + try { + return (radix == 10 ? Long.decode(value) : Long.parseLong(value, radix)); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + /** + * 鑾峰彇鎸囧畾鐨刪eader鐨刦loat鍊, 娌℃湁杩斿洖榛樿float鍊 + * + * @param name header鍚 + * @param defaultValue 榛樿float鍊 + * + * @return header鍊 + */ + public float getFloatHeader(String name, float defaultValue) { + //return headers.getFloatValue(name, defaultValue); + parseHeader(); + String value = headers.get(name); + if (value == null || value.length() == 0) return defaultValue; + try { + return Float.parseFloat(value); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + /** + * 鑾峰彇鎸囧畾鐨刪eader鐨刣ouble鍊, 娌℃湁杩斿洖榛樿double鍊 + * + * @param name header鍚 + * @param defaultValue 榛樿double鍊 + * + * @return header鍊 + */ + public double getDoubleHeader(String name, double defaultValue) { + //return headers.getDoubleValue(name, defaultValue); + parseHeader(); + String value = headers.get(name); + if (value == null || value.length() == 0) return defaultValue; + try { + return Double.parseDouble(value); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + //------------------------------------------------------------------------------ + /** + * 鑾峰彇璇锋眰鍙傛暟鎬诲璞 + * + * @return AnyValue + */ + public Map getParameters() { + parseBody(); + return params; + } + + /** + * 灏嗚姹傚弬鏁拌浆鎹㈡垚Map + * + * @param map Map + * + * @return Map + */ + @ConvertDisabled + public Map getParametersToMap(Map map) { + if (map == null) map = new LinkedHashMap<>(); + final Map map0 = map; + getParameters().forEach((k, v) -> map0.put(k, v)); + return map0; + } + + /** + * 灏嗚姹傚弬鏁拌浆鎹㈡垚String, 瀛楃涓叉牸寮忎负: bean1={}&id=13&name=xxx
+ * 涓嶄細杩斿洖null锛屾病鏈夊弬鏁拌繑鍥炵┖瀛楃涓 + * + * + * @return String + */ + @ConvertDisabled + public String getParametersToString() { + return getParametersToString(null); + } + + /** + * 灏嗚姹傚弬鏁拌浆鎹㈡垚String, 瀛楃涓叉牸寮忎负: bean1={}&id=13&name=xxx
+ * 涓嶄細杩斿洖null锛屾病鏈夊弬鏁拌繑鍥炵┖瀛楃涓 + * + * @param prefix 鎷兼帴鍓嶇紑锛 濡傛灉鏃犲弬鏁帮紝杩斿洖鐨勫瓧绗︿覆涓嶄細鍚湁鎷兼帴鍓嶇紑 + * + * @return String + */ + public String getParametersToString(String prefix) { + byte[] rbs = queryBytes; + if (rbs == null || rbs.length < 1) return ""; + Charset charset = this.context.getCharset(); + String str = charset == null ? new String(rbs, StandardCharsets.UTF_8) : new String(rbs, charset); + return (prefix == null) ? str : (prefix + str); + } + + /** + * 鑾峰彇鎵鏈夊弬鏁板悕 + * + * @return 鍙傛暟鍚嶆暟缁 + */ + @ConvertDisabled + public String[] getParameterNames() { + parseBody(); + Set names = params.keySet(); + return names.toArray(new String[names.size()]); + } + + /** + * 鑾峰彇鎸囧畾鐨勫弬鏁板 + * + * @param name 鍙傛暟鍚 + * + * @return 鍙傛暟鍊 + */ + public String getParameter(String name) { + if (this.frombody) { + if (array.isEmpty()) return null; + Convert convert = this.reqConvert; + if (convert == null) convert = jsonConvert; + return (String) convert.convertFrom(String.class, array.content()); + } + parseBody(); + return params.get(name); + } + + /** + * 鑾峰彇鎸囧畾鐨勫弬鏁板, 娌℃湁杩斿洖榛樿鍊 + * + * @param name 鍙傛暟鍚 + * @param defaultValue 榛樿鍊 + * + * @return 鍙傛暟鍊 + */ + public String getParameter(String name, String defaultValue) { + if (this.frombody) { + if (array.isEmpty()) return defaultValue; + Convert convert = this.reqConvert; + if (convert == null) convert = jsonConvert; + return (String) convert.convertFrom(String.class, array.content()); + } + parseBody(); + return params.getOrDefault(name, defaultValue); + } + + /** + * 鑾峰彇鎸囧畾鐨勫弬鏁癹son鍊 + * + * @param 娉涘瀷 + * @param type 鍙嶅簭鍒楀寲鐨勭被鍚 + * @param name 鍙傛暟鍚 + * + * @return 鍙傛暟鍊 + */ + public T getJsonParameter(java.lang.reflect.Type type, String name) { + if (this.frombody) { + if (array.isEmpty()) return null; + Convert convert = this.reqConvert; + if (convert == null) convert = jsonConvert; + if (type == byte[].class) return (T) array.getBytes(); + return (T) convert.convertFrom(type, array.content()); + } + String v = getParameter(name); + return v == null || v.isEmpty() ? null : jsonConvert.convertFrom(type, v); + } + + /** + * 鑾峰彇鎸囧畾鐨勫弬鏁癹son鍊 + * + * @param 娉涘瀷 + * @param convert JsonConvert瀵硅薄 + * @param type 鍙嶅簭鍒楀寲鐨勭被鍚 + * @param name 鍙傛暟鍚 + * + * @return 鍙傛暟鍊 + */ + public T getJsonParameter(JsonConvert convert, java.lang.reflect.Type type, String name) { + String v = getParameter(name); + return v == null || v.isEmpty() ? null : convert.convertFrom(type, v); + } + + /** + * 鑾峰彇鎸囧畾鐨勫弬鏁癰oolean鍊, 娌℃湁杩斿洖榛樿boolean鍊 + * + * @param name 鍙傛暟鍚 + * @param defaultValue 榛樿boolean鍊 + * + * @return 鍙傛暟鍊 + */ + public boolean getBooleanParameter(String name, boolean defaultValue) { + if (this.frombody) { + if (array.isEmpty()) return defaultValue; + Convert convert = this.reqConvert; + if (convert == null) convert = jsonConvert; + return (boolean) convert.convertFrom(boolean.class, array.content()); + } + parseBody(); + String value = params.get(name); + return value == null || value.length() == 0 ? defaultValue : Boolean.parseBoolean(value); + } + + /** + * 鑾峰彇鎸囧畾鐨勫弬鏁皊hort鍊, 娌℃湁杩斿洖榛樿short鍊 + * + * @param name 鍙傛暟鍚 + * @param defaultValue 榛樿short鍊 + * + * @return 鍙傛暟鍊 + */ + public short getShortParameter(String name, short defaultValue) { + if (this.frombody) { + if (array.isEmpty()) return defaultValue; + Convert convert = this.reqConvert; + if (convert == null) convert = jsonConvert; + return (short) convert.convertFrom(short.class, array.content()); + } + parseBody(); + String value = params.get(name); + if (value == null || value.length() == 0) return defaultValue; + try { + return Short.decode(value); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + /** + * 鑾峰彇鎸囧畾鐨勫弬鏁皊hort鍊, 娌℃湁杩斿洖榛樿short鍊 + * + * @param radix 杩涘埗鏁 + * @param name 鍙傛暟鍚 + * @param defaultValue 榛樿short鍊 + * + * @return 鍙傛暟鍊 + */ + public short getShortParameter(int radix, String name, short defaultValue) { + if (this.frombody) { + if (array.isEmpty()) return (short) defaultValue; + Convert convert = this.reqConvert; + if (convert == null) convert = jsonConvert; + return (short) convert.convertFrom(short.class, array.content()); + } + parseBody(); + String value = params.get(name); + if (value == null || value.length() == 0) return defaultValue; + try { + return (radix == 10 ? Short.decode(value) : Short.parseShort(value, radix)); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + /** + * 鑾峰彇鎸囧畾鐨勫弬鏁皊hort鍊, 娌℃湁杩斿洖榛樿short鍊 + * + * @param name 鍙傛暟鍚 + * @param defaultValue 榛樿short鍊 + * + * @return 鍙傛暟鍊 + */ + public short getShortParameter(String name, int defaultValue) { + if (this.frombody) { + if (array.isEmpty()) return (short) defaultValue; + Convert convert = this.reqConvert; + if (convert == null) convert = jsonConvert; + return (short) convert.convertFrom(short.class, array.content()); + } + parseBody(); + String value = params.get(name); + if (value == null || value.length() == 0) return (short) defaultValue; + try { + return Short.decode(value); + } catch (NumberFormatException e) { + return (short) defaultValue; + } + } + + /** + * 鑾峰彇鎸囧畾鐨勫弬鏁癷nt鍊, 娌℃湁杩斿洖榛樿int鍊 + * + * @param name 鍙傛暟鍚 + * @param defaultValue 榛樿int鍊 + * + * @return 鍙傛暟鍊 + */ + public int getIntParameter(String name, int defaultValue) { + if (this.frombody) { + if (array.isEmpty()) return defaultValue; + Convert convert = this.reqConvert; + if (convert == null) convert = jsonConvert; + return (int) convert.convertFrom(int.class, array.content()); + } + parseBody(); + String value = params.get(name); + if (value == null || value.length() == 0) return defaultValue; + try { + return Integer.decode(value); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + /** + * 鑾峰彇鎸囧畾鐨勫弬鏁癷nt鍊, 娌℃湁杩斿洖榛樿int鍊 + * + * @param radix 杩涘埗鏁 + * @param name 鍙傛暟鍚 + * @param defaultValue 榛樿int鍊 + * + * @return 鍙傛暟鍊 + */ + public int getIntParameter(int radix, String name, int defaultValue) { + if (this.frombody) { + if (array.isEmpty()) return defaultValue; + Convert convert = this.reqConvert; + if (convert == null) convert = jsonConvert; + return (int) convert.convertFrom(int.class, array.content()); + } + parseBody(); + String value = params.get(name); + if (value == null || value.length() == 0) return defaultValue; + try { + return (radix == 10 ? Integer.decode(value) : Integer.parseInt(value, radix)); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + /** + * 鑾峰彇鎸囧畾鐨勫弬鏁發ong鍊, 娌℃湁杩斿洖榛樿long鍊 + * + * @param name 鍙傛暟鍚 + * @param defaultValue 榛樿long鍊 + * + * @return 鍙傛暟鍊 + */ + public long getLongParameter(String name, long defaultValue) { + if (this.frombody) { + if (array.isEmpty()) return defaultValue; + Convert convert = this.reqConvert; + if (convert == null) convert = jsonConvert; + return (long) convert.convertFrom(long.class, array.content()); + } + parseBody(); + String value = params.get(name); + if (value == null || value.length() == 0) return defaultValue; + try { + return Long.decode(value); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + /** + * 鑾峰彇鎸囧畾鐨勫弬鏁發ong鍊, 娌℃湁杩斿洖榛樿long鍊 + * + * @param radix 杩涘埗鏁 + * @param name 鍙傛暟鍚 + * @param defaultValue 榛樿long鍊 + * + * @return 鍙傛暟鍊 + */ + public long getLongParameter(int radix, String name, long defaultValue) { + if (this.frombody) { + if (array.isEmpty()) return defaultValue; + Convert convert = this.reqConvert; + if (convert == null) convert = jsonConvert; + return (long) convert.convertFrom(long.class, array.content()); + } + parseBody(); + String value = params.get(name); + if (value == null || value.length() == 0) return defaultValue; + try { + return (radix == 10 ? Long.decode(value) : Long.parseLong(value, radix)); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + /** + * 鑾峰彇鎸囧畾鐨勫弬鏁癴loat鍊, 娌℃湁杩斿洖榛樿float鍊 + * + * @param name 鍙傛暟鍚 + * @param defaultValue 榛樿float鍊 + * + * @return 鍙傛暟鍊 + */ + public float getFloatParameter(String name, float defaultValue) { + if (this.frombody) { + if (array.isEmpty()) return defaultValue; + Convert convert = this.reqConvert; + if (convert == null) convert = jsonConvert; + return (float) convert.convertFrom(float.class, array.content()); + } + parseBody(); + String value = params.get(name); + if (value == null || value.length() == 0) return defaultValue; + try { + return Float.parseFloat(value); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + /** + * 鑾峰彇鎸囧畾鐨勫弬鏁癲ouble鍊, 娌℃湁杩斿洖榛樿double鍊 + * + * @param name 鍙傛暟鍚 + * @param defaultValue 榛樿double鍊 + * + * @return 鍙傛暟鍊 + */ + public double getDoubleParameter(String name, double defaultValue) { + if (this.frombody) { + if (array.isEmpty()) return defaultValue; + Convert convert = this.reqConvert; + if (convert == null) convert = jsonConvert; + return (double) convert.convertFrom(double.class, array.content()); + } + parseBody(); + String value = params.get(name); + if (value == null || value.length() == 0) return defaultValue; + try { + return Double.parseDouble(value); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + /** + * 鑾峰彇缈婚〉瀵硅薄 鍚 getFlipper("flipper", false, 0); + * + * @return Flipper缈婚〉瀵硅薄 + */ + public org.redkale.source.Flipper getFlipper() { + return getFlipper(false, 0); + } + + /** + * 鑾峰彇缈婚〉瀵硅薄 鍚 getFlipper("flipper", needcreate, 0); + * + * @param needcreate 鏃犲弬鏁版椂鏄惁鍒涘缓鏂癋lipper瀵硅薄 + * + * @return Flipper缈婚〉瀵硅薄 + */ + public org.redkale.source.Flipper getFlipper(boolean needcreate) { + return getFlipper(needcreate, 0); + } + + /** + * 鑾峰彇缈婚〉瀵硅薄 鍚 getFlipper("flipper", false, maxLimit); + * + * @param maxLimit 鏈澶ц鏁帮紝 灏忎簬1鍒欏间负Flipper.DEFAULT_LIMIT + * + * @return Flipper缈婚〉瀵硅薄 + */ + public org.redkale.source.Flipper getFlipper(int maxLimit) { + return getFlipper(false, maxLimit); + } + + /** + * 鑾峰彇缈婚〉瀵硅薄 鍚 getFlipper("flipper", needcreate, maxLimit) + * + * @param needcreate 鏃犲弬鏁版椂鏄惁鍒涘缓鏂癋lipper瀵硅薄 + * @param maxLimit 鏈澶ц鏁帮紝 灏忎簬1鍒欏间负Flipper.DEFAULT_LIMIT + * + * @return Flipper缈婚〉瀵硅薄 + */ + public org.redkale.source.Flipper getFlipper(boolean needcreate, int maxLimit) { + return getFlipper("flipper", needcreate, maxLimit); + } + + /** + * 鑾峰彇缈婚〉瀵硅薄 https://redkale.org/pipes/users/list/offset:0/limit:20/sort:createtime%20ASC
+ * https://redkale.org/pipes/users/list?flipper={'offset':0,'limit':20, 'sort':'createtime ASC'}
+ * 浠ヤ笂涓ょ鎺ュ彛閮藉彲浠ヨ幏鍙栧埌缈婚〉瀵硅薄 + * + * + * @param name Flipper瀵硅薄鐨勫弬鏁板悕锛岄粯璁や负 "flipper" + * @param needcreate 鏃犲弬鏁版椂鏄惁鍒涘缓鏂癋lipper瀵硅薄 + * @param maxLimit 鏈澶ц鏁帮紝 灏忎簬1鍒欏间负Flipper.DEFAULT_LIMIT + * + * @return Flipper缈婚〉瀵硅薄 + */ + public org.redkale.source.Flipper getFlipper(String name, boolean needcreate, int maxLimit) { + org.redkale.source.Flipper flipper = getJsonParameter(org.redkale.source.Flipper.class, name); + if (flipper == null) { + if (maxLimit < 1) maxLimit = org.redkale.source.Flipper.DEFAULT_LIMIT; + int limit = getRequstURIPath("limit:", 0); + int offset = getRequstURIPath("offset:", 0); + String sort = getRequstURIPath("sort:", ""); + if (limit > 0) { + if (limit > maxLimit) limit = maxLimit; + flipper = new org.redkale.source.Flipper(limit, offset, sort); + } + } else if (flipper.getLimit() < 1 || (maxLimit > 0 && flipper.getLimit() > maxLimit)) { + flipper.setLimit(maxLimit); + } + if (flipper != null || !needcreate) return flipper; + if (maxLimit < 1) maxLimit = org.redkale.source.Flipper.DEFAULT_LIMIT; + return new org.redkale.source.Flipper(maxLimit); + } +} diff --git a/src/main/java/org/redkale/net/http/HttpResourceServlet.java b/src/main/java/org/redkale/net/http/HttpResourceServlet.java index e2ffd8917..abb904472 100644 --- a/src/main/java/org/redkale/net/http/HttpResourceServlet.java +++ b/src/main/java/org/redkale/net/http/HttpResourceServlet.java @@ -1,333 +1,333 @@ -/* - * 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 java.io.*; -import static java.nio.file.StandardWatchEventKinds.*; -import java.nio.file.*; -import java.util.AbstractMap.SimpleEntry; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.LongAdder; -import java.util.logging.*; -import java.util.regex.*; -import org.redkale.util.*; - -/** - * 闈欐佽祫婧怘ttpServlet - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public class HttpResourceServlet extends HttpServlet { - - protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); - - protected class WatchThread extends Thread { - - protected final File root; - - protected final WatchService watcher; - - public WatchThread(File root) throws IOException { - this.root = root; - this.setName("Redkale-HttpResourceServlet-Watch-Thread"); - this.setDaemon(true); - this.watcher = this.root.toPath().getFileSystem().newWatchService(); - } - - @Override - public void run() { - try { - final String rootstr = root.getCanonicalPath(); - while (!this.isInterrupted()) { - final WatchKey key = watcher.take(); - final Path parent = keymaps.get(key); - if (parent == null) { - key.cancel(); - continue; - } - key.pollEvents().stream().forEach((event) -> { - try { - Path path = parent.resolve((Path) event.context()); - final String uri = path.toString().substring(rootstr.length()).replace('\\', '/'); - //logger.log(Level.FINEST, "file(" + uri + ") happen " + event.kind() + " event"); - if (event.kind() == ENTRY_DELETE) { - FileEntry en = files.remove(uri); - if (en != null) en.remove(); - } else if (event.kind() == ENTRY_MODIFY) { - FileEntry en = files.get(uri); - if (en != null && en.file != null) { - long d; //绛夊緟update file瀹屾瘯 - for (;;) { - d = en.file.lastModified(); - Thread.sleep(2000L); - if (d == en.file.lastModified()) break; - } - en.update(); - } - } - } catch (Exception ex) { - logger.log(Level.FINE, event.context() + " occur erroneous", ex); - } - }); - key.reset(); - } - } catch (Exception e) { - } - } - } - - protected final LongAdder cachedLength = new LongAdder(); - - //缂撳瓨鎬诲ぇ灏, 榛樿0 - protected long cachelimit = 0 * 1024 * 1024L; - - //鏈澶у彲缂撳瓨鐨勬枃浠跺ぇ灏忥紝 澶т簬璇ュ肩殑鏂囦欢灏嗕笉琚紦瀛 - protected long cachelengthmax = 1 * 1024 * 1024; - - //鏄惁鐩戞帶缂撳瓨鏂囦欢鐨勫彉鍖栵紝 榛樿涓嶇洃鎺 - protected boolean watch = false; - - protected File root = new File("./root/"); - - protected String indexHtml = "index.html"; - - protected final ConcurrentHashMap files = new ConcurrentHashMap<>(); - - protected final ConcurrentHashMap keymaps = new ConcurrentHashMap<>(); - - protected SimpleEntry[] locationRewrites; - - protected WatchThread watchThread; - - protected String[] renderSuffixs; - - @Override - public void init(HttpContext context, AnyValue config) { - if (config != null) { - String rootstr = config.getValue("webroot", "root"); - this.indexHtml = config.getValue("index", "index.html"); - if (rootstr.indexOf(':') < 0 && rootstr.indexOf('/') != 0 && System.getProperty("APP_HOME") != null) { - rootstr = new File(System.getProperty("APP_HOME"), rootstr).getPath(); - } - try { - this.root = new File(rootstr).getCanonicalFile(); - } catch (IOException ioe) { - this.root = new File(rootstr); - } - AnyValue cacheconf = config.getAnyValue("cache"); - if (cacheconf != null) { - this.cachelimit = parseLenth(cacheconf.getValue("limit"), 0 * 1024 * 1024L); - this.cachelengthmax = parseLenth(cacheconf.getValue("lengthmax"), 1 * 1024 * 1024L); - this.watch = cacheconf.getBoolValue("watch", false); - } - List> locations = new ArrayList<>(); - for (AnyValue av : config.getAnyValues("rewrite")) { - if ("location".equals(av.getValue("type"))) { - String m = av.getValue("match"); - String f = av.getValue("forward"); - if (m != null && f != null) { - locations.add(new SimpleEntry<>(Pattern.compile(m), f)); - } - } - } - this.locationRewrites = locations.isEmpty() ? null : locations.toArray(new SimpleEntry[locations.size()]); - } - if (this.cachelimit < 1) return; //涓嶇紦瀛樹笉闇瑕佸紑鍚疻atchThread鐩戝惉 - if (this.root != null && this.watch) { - try { - this.watchThread = new WatchThread(this.root); - this.watchThread.start(); - } catch (IOException ex) { - logger.log(Level.WARNING, HttpResourceServlet.class.getSimpleName() + " start watch-thread error", ex); - } - } - } - - @Override - public void destroy(HttpContext context, AnyValue config) { - if (this.watchThread != null) { - try { - this.watchThread.watcher.close(); - } catch (IOException ex) { - logger.log(Level.WARNING, HttpResourceServlet.class.getSimpleName() + " close watch-thread error", ex); - } - if (this.watchThread.isAlive()) this.watchThread.interrupt(); - } - } - - public void setRoot(String rootstr) { - if (rootstr == null) return; - try { - this.root = new File(rootstr).getCanonicalFile(); - } catch (IOException ioe) { - this.root = new File(rootstr); - } - } - - public void setRoot(File file) { - if (file == null) return; - try { - this.root = file.getCanonicalFile(); - } catch (IOException ioe) { - this.root = file; - } - } - - protected static long parseLenth(String value, long defValue) { - if (value == null) return defValue; - value = value.toUpperCase().replace("B", ""); - if (value.endsWith("G")) return Long.decode(value.replace("G", "")) * 1024 * 1024 * 1024; - if (value.endsWith("M")) return Long.decode(value.replace("M", "")) * 1024 * 1024; - if (value.endsWith("K")) return Long.decode(value.replace("K", "")) * 1024; - return Long.decode(value); - } - - @Override - public void execute(HttpRequest request, HttpResponse response) throws IOException { - String uri = request.getRequestURI(); - if (uri.contains("../")) { - if (logger.isLoggable(Level.FINEST)) logger.log(Level.FINEST, "Not found resource (404) be " + uri + ", request = " + request); - response.finish404(); - return; - } - if (locationRewrites != null) { - for (SimpleEntry entry : locationRewrites) { - Matcher matcher = entry.getKey().matcher(uri); - if (matcher.find()) { - StringBuffer sb = new StringBuffer(uri.length()); - matcher.appendReplacement(sb, entry.getValue()); - matcher.appendTail(sb); - uri = sb.toString(); - break; - } - } - } - if (uri.length() == 0 || uri.equals("/")) { - uri = this.indexHtml.indexOf('/') == 0 ? this.indexHtml : ("/" + this.indexHtml); - } - //璺宠繃妯℃澘寮曟搸鐨勫悗缂鏂囦欢 - if (renderSuffixs != null) { - String suri = uri.toLowerCase(); - for (String suffix : renderSuffixs) { - if (suri.endsWith(suffix)) { - response.finish404(); - return; - } - } - } - //System.out.println(request); - FileEntry entry; - if (watchThread == null && files.isEmpty()) { - entry = createFileEntry(uri); - } else { //鏈夌紦瀛 - entry = files.computeIfAbsent(uri, x -> createFileEntry(x)); - } - if (entry == null) { - if (logger.isLoggable(Level.FINER)) logger.log(Level.FINER, "Not found resource (404), url = " + request.getRequestURI()); - response.finish404(); - } else { - //file = null 琛ㄧず璧勬簮鍐呭鍦ㄥ唴瀛樿屼笉鏄湪File涓 - //file = null 鏃跺繀椤讳紶 filename - response.finishFile(entry.file == null ? entry.filename : null, entry.file, entry.content); - } - } - - protected FileEntry createFileEntry(String uri) { - File rfile = new File(root, uri); - File file = rfile; - if (file.isDirectory()) file = new File(rfile, this.indexHtml); - if (file.isDirectory()) file = new File(rfile, "index.html"); - if (!file.isFile() || !file.canRead()) return null; - FileEntry en = new FileEntry(this, file); - if (watchThread == null) return en; - try { - Path p = file.getParentFile().toPath(); - keymaps.put(p.register(watchThread.watcher, ENTRY_MODIFY, ENTRY_DELETE), p); - } catch (IOException e) { - logger.log(Level.INFO, HttpResourceServlet.class.getSimpleName() + " watch FileEntry(" + uri + ") erroneous", e); - } - return en; - } - - protected static class FileEntry { - - protected final String filename; - - protected final File file; //濡傛灉鎵鏈夎祫婧愭枃浠舵墦鍖呮垚zip鏂囦欢鍒檉ile=null - - protected final HttpResourceServlet servlet; - - protected ByteArray content; - - @SuppressWarnings("OverridableMethodCallInConstructor") - public FileEntry(final HttpResourceServlet servlet, File file) { - this.servlet = servlet; - this.file = file; - this.filename = file.getName(); - update(); - } - - public FileEntry(final HttpResourceServlet servlet, String filename, ByteArray content) { - this.servlet = servlet; - this.file = null; - this.filename = filename; - this.content = content; - this.servlet.cachedLength.add(this.content.length()); - } - - public FileEntry(final HttpResourceServlet servlet, String filename, InputStream in) throws IOException { - ByteArray out = new ByteArray(); - byte[] bytes = new byte[10240]; - int pos; - while ((pos = in.read(bytes)) != -1) { - out.put(bytes, 0, pos); - } - this.servlet = servlet; - this.file = null; - this.filename = filename; - this.content = out; - this.servlet.cachedLength.add(this.content.length()); - } - - public void update() { - if (this.file == null) return; - if (this.content != null) { - this.servlet.cachedLength.add(0L - this.content.length()); - this.content = null; - } - long length = this.file.length(); - if (length > this.servlet.cachelengthmax) return; - if (this.servlet.cachedLength.longValue() + length > this.servlet.cachelimit) return; //瓒呰繃缂撳瓨鎬诲閲 - try { - FileInputStream in = new FileInputStream(file); - ByteArray out = new ByteArray((int) file.length()); - byte[] bytes = new byte[10240]; - int pos; - while ((pos = in.read(bytes)) != -1) { - out.put(bytes, 0, pos); - } - in.close(); - this.content = out; - this.servlet.cachedLength.add(this.content.length()); - } catch (Exception e) { - this.servlet.logger.log(Level.INFO, HttpResourceServlet.class.getSimpleName() + " update FileEntry(" + file + ") erroneous", e); - } - } - - public void remove() { - if (this.content != null) this.servlet.cachedLength.add(0L - this.content.length()); - } - - public long getCachedLength() { - return this.content == null ? 0L : this.content.length(); - } - - } -} +/* + * 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 java.io.*; +import static java.nio.file.StandardWatchEventKinds.*; +import java.nio.file.*; +import java.util.AbstractMap.SimpleEntry; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.LongAdder; +import java.util.logging.*; +import java.util.regex.*; +import org.redkale.util.*; + +/** + * 闈欐佽祫婧怘ttpServlet + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public class HttpResourceServlet extends HttpServlet { + + protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); + + protected class WatchThread extends Thread { + + protected final File root; + + protected final WatchService watcher; + + public WatchThread(File root) throws IOException { + this.root = root; + this.setName("Redkale-HttpResourceServlet-Watch-Thread"); + this.setDaemon(true); + this.watcher = this.root.toPath().getFileSystem().newWatchService(); + } + + @Override + public void run() { + try { + final String rootstr = root.getCanonicalPath(); + while (!this.isInterrupted()) { + final WatchKey key = watcher.take(); + final Path parent = keymaps.get(key); + if (parent == null) { + key.cancel(); + continue; + } + key.pollEvents().stream().forEach((event) -> { + try { + Path path = parent.resolve((Path) event.context()); + final String uri = path.toString().substring(rootstr.length()).replace('\\', '/'); + //logger.log(Level.FINEST, "file(" + uri + ") happen " + event.kind() + " event"); + if (event.kind() == ENTRY_DELETE) { + FileEntry en = files.remove(uri); + if (en != null) en.remove(); + } else if (event.kind() == ENTRY_MODIFY) { + FileEntry en = files.get(uri); + if (en != null && en.file != null) { + long d; //绛夊緟update file瀹屾瘯 + for (;;) { + d = en.file.lastModified(); + Thread.sleep(2000L); + if (d == en.file.lastModified()) break; + } + en.update(); + } + } + } catch (Exception ex) { + logger.log(Level.FINE, event.context() + " occur erroneous", ex); + } + }); + key.reset(); + } + } catch (Exception e) { + } + } + } + + protected final LongAdder cachedLength = new LongAdder(); + + //缂撳瓨鎬诲ぇ灏, 榛樿0 + protected long cachelimit = 0 * 1024 * 1024L; + + //鏈澶у彲缂撳瓨鐨勬枃浠跺ぇ灏忥紝 澶т簬璇ュ肩殑鏂囦欢灏嗕笉琚紦瀛 + protected long cachelengthmax = 1 * 1024 * 1024; + + //鏄惁鐩戞帶缂撳瓨鏂囦欢鐨勫彉鍖栵紝 榛樿涓嶇洃鎺 + protected boolean watch = false; + + protected File root = new File("./root/"); + + protected String indexHtml = "index.html"; + + protected final ConcurrentHashMap files = new ConcurrentHashMap<>(); + + protected final ConcurrentHashMap keymaps = new ConcurrentHashMap<>(); + + protected SimpleEntry[] locationRewrites; + + protected WatchThread watchThread; + + protected String[] renderSuffixs; + + @Override + public void init(HttpContext context, AnyValue config) { + if (config != null) { + String rootstr = config.getValue("webroot", "root"); + this.indexHtml = config.getValue("index", "index.html"); + if (rootstr.indexOf(':') < 0 && rootstr.indexOf('/') != 0 && System.getProperty("APP_HOME") != null) { + rootstr = new File(System.getProperty("APP_HOME"), rootstr).getPath(); + } + try { + this.root = new File(rootstr).getCanonicalFile(); + } catch (IOException ioe) { + this.root = new File(rootstr); + } + AnyValue cacheconf = config.getAnyValue("cache"); + if (cacheconf != null) { + this.cachelimit = parseLenth(cacheconf.getValue("limit"), 0 * 1024 * 1024L); + this.cachelengthmax = parseLenth(cacheconf.getValue("lengthmax"), 1 * 1024 * 1024L); + this.watch = cacheconf.getBoolValue("watch", false); + } + List> locations = new ArrayList<>(); + for (AnyValue av : config.getAnyValues("rewrite")) { + if ("location".equals(av.getValue("type"))) { + String m = av.getValue("match"); + String f = av.getValue("forward"); + if (m != null && f != null) { + locations.add(new SimpleEntry<>(Pattern.compile(m), f)); + } + } + } + this.locationRewrites = locations.isEmpty() ? null : locations.toArray(new SimpleEntry[locations.size()]); + } + if (this.cachelimit < 1) return; //涓嶇紦瀛樹笉闇瑕佸紑鍚疻atchThread鐩戝惉 + if (this.root != null && this.watch) { + try { + this.watchThread = new WatchThread(this.root); + this.watchThread.start(); + } catch (IOException ex) { + logger.log(Level.WARNING, HttpResourceServlet.class.getSimpleName() + " start watch-thread error", ex); + } + } + } + + @Override + public void destroy(HttpContext context, AnyValue config) { + if (this.watchThread != null) { + try { + this.watchThread.watcher.close(); + } catch (IOException ex) { + logger.log(Level.WARNING, HttpResourceServlet.class.getSimpleName() + " close watch-thread error", ex); + } + if (this.watchThread.isAlive()) this.watchThread.interrupt(); + } + } + + public void setRoot(String rootstr) { + if (rootstr == null) return; + try { + this.root = new File(rootstr).getCanonicalFile(); + } catch (IOException ioe) { + this.root = new File(rootstr); + } + } + + public void setRoot(File file) { + if (file == null) return; + try { + this.root = file.getCanonicalFile(); + } catch (IOException ioe) { + this.root = file; + } + } + + protected static long parseLenth(String value, long defValue) { + if (value == null) return defValue; + value = value.toUpperCase().replace("B", ""); + if (value.endsWith("G")) return Long.decode(value.replace("G", "")) * 1024 * 1024 * 1024; + if (value.endsWith("M")) return Long.decode(value.replace("M", "")) * 1024 * 1024; + if (value.endsWith("K")) return Long.decode(value.replace("K", "")) * 1024; + return Long.decode(value); + } + + @Override + public void execute(HttpRequest request, HttpResponse response) throws IOException { + String uri = request.getRequestURI(); + if (uri.contains("../")) { + if (logger.isLoggable(Level.FINEST)) logger.log(Level.FINEST, "Not found resource (404) be " + uri + ", request = " + request); + response.finish404(); + return; + } + if (locationRewrites != null) { + for (SimpleEntry entry : locationRewrites) { + Matcher matcher = entry.getKey().matcher(uri); + if (matcher.find()) { + StringBuffer sb = new StringBuffer(uri.length()); + matcher.appendReplacement(sb, entry.getValue()); + matcher.appendTail(sb); + uri = sb.toString(); + break; + } + } + } + if (uri.length() == 0 || uri.equals("/")) { + uri = this.indexHtml.indexOf('/') == 0 ? this.indexHtml : ("/" + this.indexHtml); + } + //璺宠繃妯℃澘寮曟搸鐨勫悗缂鏂囦欢 + if (renderSuffixs != null) { + String suri = uri.toLowerCase(); + for (String suffix : renderSuffixs) { + if (suri.endsWith(suffix)) { + response.finish404(); + return; + } + } + } + //System.out.println(request); + FileEntry entry; + if (watchThread == null && files.isEmpty()) { + entry = createFileEntry(uri); + } else { //鏈夌紦瀛 + entry = files.computeIfAbsent(uri, x -> createFileEntry(x)); + } + if (entry == null) { + if (logger.isLoggable(Level.FINER)) logger.log(Level.FINER, "Not found resource (404), url = " + request.getRequestURI()); + response.finish404(); + } else { + //file = null 琛ㄧず璧勬簮鍐呭鍦ㄥ唴瀛樿屼笉鏄湪File涓 + //file = null 鏃跺繀椤讳紶 filename + response.finishFile(entry.file == null ? entry.filename : null, entry.file, entry.content); + } + } + + protected FileEntry createFileEntry(String uri) { + File rfile = new File(root, uri); + File file = rfile; + if (file.isDirectory()) file = new File(rfile, this.indexHtml); + if (file.isDirectory()) file = new File(rfile, "index.html"); + if (!file.isFile() || !file.canRead()) return null; + FileEntry en = new FileEntry(this, file); + if (watchThread == null) return en; + try { + Path p = file.getParentFile().toPath(); + keymaps.put(p.register(watchThread.watcher, ENTRY_MODIFY, ENTRY_DELETE), p); + } catch (IOException e) { + logger.log(Level.INFO, HttpResourceServlet.class.getSimpleName() + " watch FileEntry(" + uri + ") erroneous", e); + } + return en; + } + + protected static class FileEntry { + + protected final String filename; + + protected final File file; //濡傛灉鎵鏈夎祫婧愭枃浠舵墦鍖呮垚zip鏂囦欢鍒檉ile=null + + protected final HttpResourceServlet servlet; + + protected ByteArray content; + + @SuppressWarnings("OverridableMethodCallInConstructor") + public FileEntry(final HttpResourceServlet servlet, File file) { + this.servlet = servlet; + this.file = file; + this.filename = file.getName(); + update(); + } + + public FileEntry(final HttpResourceServlet servlet, String filename, ByteArray content) { + this.servlet = servlet; + this.file = null; + this.filename = filename; + this.content = content; + this.servlet.cachedLength.add(this.content.length()); + } + + public FileEntry(final HttpResourceServlet servlet, String filename, InputStream in) throws IOException { + ByteArray out = new ByteArray(); + byte[] bytes = new byte[10240]; + int pos; + while ((pos = in.read(bytes)) != -1) { + out.put(bytes, 0, pos); + } + this.servlet = servlet; + this.file = null; + this.filename = filename; + this.content = out; + this.servlet.cachedLength.add(this.content.length()); + } + + public void update() { + if (this.file == null) return; + if (this.content != null) { + this.servlet.cachedLength.add(0L - this.content.length()); + this.content = null; + } + long length = this.file.length(); + if (length > this.servlet.cachelengthmax) return; + if (this.servlet.cachedLength.longValue() + length > this.servlet.cachelimit) return; //瓒呰繃缂撳瓨鎬诲閲 + try { + FileInputStream in = new FileInputStream(file); + ByteArray out = new ByteArray((int) file.length()); + byte[] bytes = new byte[10240]; + int pos; + while ((pos = in.read(bytes)) != -1) { + out.put(bytes, 0, pos); + } + in.close(); + this.content = out; + this.servlet.cachedLength.add(this.content.length()); + } catch (Exception e) { + this.servlet.logger.log(Level.INFO, HttpResourceServlet.class.getSimpleName() + " update FileEntry(" + file + ") erroneous", e); + } + } + + public void remove() { + if (this.content != null) this.servlet.cachedLength.add(0L - this.content.length()); + } + + public long getCachedLength() { + return this.content == null ? 0L : this.content.length(); + } + + } +} diff --git a/src/main/java/org/redkale/net/http/HttpResponse.java b/src/main/java/org/redkale/net/http/HttpResponse.java index 48ea6b8eb..853b848ba 100644 --- a/src/main/java/org/redkale/net/http/HttpResponse.java +++ b/src/main/java/org/redkale/net/http/HttpResponse.java @@ -1,1579 +1,1579 @@ -/* - * 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 java.io.*; -import java.lang.reflect.Type; -import java.net.*; -import java.nio.ByteBuffer; -import java.nio.channels.*; -import java.nio.file.*; -import java.time.ZoneId; -import static java.time.format.DateTimeFormatter.RFC_1123_DATE_TIME; -import java.util.*; -import java.util.concurrent.*; -import java.util.function.*; -import java.util.logging.*; -import org.redkale.convert.*; -import org.redkale.convert.json.*; -import org.redkale.net.*; -import org.redkale.util.AnyValue.DefaultAnyValue; -import org.redkale.util.AnyValue.Entry; -import org.redkale.util.*; -import static org.redkale.util.Utility.append; - -/** - * Http鍝嶅簲鍖 涓巎avax.servlet.http.HttpServletResponse 鍩烘湰绫讳技銆
- * 鍚屾椂鎻愪緵鍙戦乯son鐨勭郴鍒楁帴鍙: public void finishJson(Type type, Object obj)
- * Redkale鎻愬ttp+json鐨勬帴鍙i鏍硷紝 鎵浠ヤ富瑕佽緭鍑虹殑鏁版嵁鏍煎紡涓簀son锛 鍚屾椂鎻愪緵寮傛鎺ュ彛銆
- *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public class HttpResponse extends Response { - - protected static final byte[] bytes304 = "HTTP/1.1 304 Not Modified\r\nContent-Length:0\r\n\r\n".getBytes(); - - protected static final byte[] bytes404 = "HTTP/1.1 404 Not Found\r\nContent-Length:0\r\n\r\n".getBytes(); - - protected static final byte[] bytes500 = "HTTP/1.1 500 Internal Server Error\r\nContent-Length:0\r\n\r\n".getBytes(); - - protected static final byte[] bytes504 = "HTTP/1.1 504 Gateway Timeout\r\nContent-Length:0\r\n\r\n".getBytes(); - - protected static final byte[] status200Bytes = "HTTP/1.1 200 OK\r\n".getBytes(); - - protected static final byte[] LINE = new byte[]{'\r', '\n'}; - - protected static final byte[] serverNameBytes = ("Server: " + System.getProperty("redkale.http.response.header.server", "redkale" + "/" + Redkale.getDotedVersion()) + "\r\n").getBytes(); - - protected static final byte[] connectCloseBytes = "none".equalsIgnoreCase(System.getProperty("redkale.http.response.header.connection")) ? new byte[0] : "Connection: close\r\n".getBytes(); - - protected static final byte[] connectAliveBytes = "none".equalsIgnoreCase(System.getProperty("redkale.http.response.header.connection")) ? new byte[0] : "Connection: keep-alive\r\n".getBytes(); - - protected static final String contentTypeHtmlUTF8 = "text/html; charset=utf-8"; - - private static final int cacheMaxContentLength = 1000; - - private static final byte[] status200_server_live_Bytes = append(append(status200Bytes, serverNameBytes), connectAliveBytes); - - private static final byte[] status200_server_close_Bytes = append(append(status200Bytes, serverNameBytes), connectCloseBytes); - - private static final ZoneId ZONE_GMT = ZoneId.of("GMT"); - - private static final OpenOption[] options = new OpenOption[]{StandardOpenOption.READ}; - - private static final Map httpCodes = new HashMap<>(); - - private static final byte[][] contentLengthArray = new byte[cacheMaxContentLength][]; - - private static final JsonConvert jsonRootConvert = JsonConvert.root(); - - static { - - httpCodes.put(100, "Continue"); - httpCodes.put(101, "Switching Protocols"); - - httpCodes.put(200, "OK"); - httpCodes.put(201, "Created"); - httpCodes.put(202, "Accepted"); - httpCodes.put(203, "Non-Authoritative Information"); - httpCodes.put(204, "No Content"); - httpCodes.put(205, "Reset Content"); - httpCodes.put(206, "Partial Content"); - - httpCodes.put(300, "Multiple Choices"); - httpCodes.put(301, "Moved Permanently"); - httpCodes.put(302, "Found"); - httpCodes.put(303, "See Other"); - httpCodes.put(304, "Not Modified"); - httpCodes.put(305, "Use Proxy"); - httpCodes.put(307, "Temporary Redirect"); - - httpCodes.put(400, "Bad Request"); - httpCodes.put(401, "Unauthorized"); - httpCodes.put(402, "Payment Required"); - httpCodes.put(403, "Forbidden"); - httpCodes.put(404, "Not Found"); - httpCodes.put(405, "Method Not Allowed"); - httpCodes.put(406, "Not Acceptable"); - httpCodes.put(407, "Proxy Authentication Required"); - httpCodes.put(408, "Request Timeout"); - httpCodes.put(409, "Conflict"); - httpCodes.put(410, "Gone"); - httpCodes.put(411, "Length Required"); - httpCodes.put(412, "Precondition Failed"); - httpCodes.put(413, "Request Entity Too Large"); - httpCodes.put(414, "Request URI Too Long"); - httpCodes.put(415, "Unsupported Media Type"); - httpCodes.put(416, "Requested Range Not Satisfiable"); - httpCodes.put(417, "Expectation Failed"); - - httpCodes.put(500, "Internal Server Error"); - httpCodes.put(501, "Not Implemented"); - httpCodes.put(502, "Bad Gateway"); - httpCodes.put(503, "Service Unavailable"); - httpCodes.put(504, "Gateway Timeout"); - httpCodes.put(505, "HTTP Version Not Supported"); - - for (int i = 0; i < cacheMaxContentLength; i++) { - contentLengthArray[i] = ("Content-Length: " + i + "\r\n").getBytes(); - } - } - - private int status = 200; - - private String contentType = ""; - - private long contentLength = -1; - - private HttpCookie[] cookies; - - private boolean respHeadContainsConnection; - - private int headWritedSize = -1; //0琛ㄧず璺宠繃header锛屾鏁拌〃绀篽eader鐨勫瓧鑺傞暱搴︺ - - private BiConsumer cacheHandler; - - private BiFunction retResultHandler; - - //------------------------------------------------ - private final String plainContentType; - - private final byte[] plainContentTypeBytes; - - private final String jsonContentType; - - private final byte[] jsonContentTypeBytes; - - private final DefaultAnyValue header = new DefaultAnyValue(); - - private final String[][] defaultAddHeaders; - - private final String[][] defaultSetHeaders; - - private final boolean autoOptions; - - private final Supplier dateSupplier; - - private final HttpCookie defaultCookie; - - private final HttpRender httpRender; - - private final ByteArray headerArray = new ByteArray(); - - private final byte[][] plainLiveContentLengthArray; - - private final byte[][] jsonLiveContentLengthArray; - - private final byte[][] plainCloseContentLengthArray; - - private final byte[][] jsonCloseContentLengthArray; - - private final JsonBytesWriter jsonWriter = new JsonBytesWriter(); - - protected final CompletionHandler pipelineWriteHandler = new CompletionHandler() { - - @Override - public void completed(Integer result, Void attachment) { - finish(); - } - - @Override - public void failed(Throwable exc, Void attachment) { - finish(true); - } - }; - - @SuppressWarnings("Convert2Lambda") - protected final ConvertBytesHandler convertHandler = new ConvertBytesHandler() { - @Override - public void completed(byte[] bs, int offset, int length, Consumer callback, A attachment) { - finish(bs, offset, length, callback, attachment); - } - }; - - public HttpResponse(HttpContext context, HttpRequest request, HttpResponseConfig config) { - super(context, request); - this.defaultAddHeaders = config == null ? null : config.defaultAddHeaders; - this.defaultSetHeaders = config == null ? null : config.defaultSetHeaders; - this.defaultCookie = config == null ? null : config.defaultCookie; - this.autoOptions = config == null ? false : config.autoOptions; - this.dateSupplier = config == null ? null : config.dateSupplier; - this.httpRender = config == null ? null : config.httpRender; - - this.plainContentType = config == null ? "text/plain; charset=utf-8" : config.plainContentType; - this.jsonContentType = config == null ? "application/json; charset=utf-8" : config.jsonContentType; - this.plainContentTypeBytes = config == null ? ("Content-Type: " + this.plainContentType + "\r\n").getBytes() : config.plainContentTypeBytes; - this.jsonContentTypeBytes = config == null ? ("Content-Type: " + this.jsonContentType + "\r\n").getBytes() : config.jsonContentTypeBytes; - this.plainLiveContentLengthArray = config == null ? null : config.plainLiveContentLengthArray; - this.plainCloseContentLengthArray = config == null ? null : config.plainCloseContentLengthArray; - this.jsonLiveContentLengthArray = config == null ? null : config.jsonLiveContentLengthArray; - this.jsonCloseContentLengthArray = config == null ? null : config.jsonCloseContentLengthArray; - this.contentType = this.plainContentType; - } - - @Override - protected AsyncConnection removeChannel() { - return super.removeChannel(); - } - - protected AsyncConnection getChannel() { - return channel; - } - - @Override - protected void prepare() { - super.prepare(); - } - - @Override - protected boolean recycle() { - this.status = 200; - this.contentLength = -1; - this.contentType = null; - this.cookies = null; - this.headWritedSize = -1; - //this.headBuffer = null; - this.header.clear(); - this.headerArray.clear(); - this.cacheHandler = null; - this.retResultHandler = null; - this.respHeadContainsConnection = false; - this.jsonWriter.recycle(); - return super.recycle(); - } - -// protected Supplier getBodyBufferSupplier() { -// return bodyBufferSupplier; -// } - @Override - protected void init(AsyncConnection channel) { - super.init(channel); - } - - /** - * 鑾峰彇鐘舵佺爜瀵瑰簲鐨勭姸鎬佹弿杩 - * - * @param status 鐘舵佺爜 - * - * @return 鐘舵佹弿杩 - */ - protected String getHttpCode(int status) { - return httpCodes.get(status); - } - - protected HttpRequest getRequest() { - return request; - } - - protected String getHttpCode(int status, String defValue) { - String v = httpCodes.get(status); - return v == null ? defValue : v; - } - - @Override - @SuppressWarnings("unchecked") - protected void thenEvent(Servlet servlet) { - this.servlet = servlet; - } - - protected boolean isAutoOptions() { - return this.autoOptions; - } - - /** - * 澧炲姞Cookie鍊 - * - * @param cookies cookie - * - * @return HttpResponse - */ - public HttpResponse addCookie(HttpCookie... cookies) { - this.cookies = Utility.append(this.cookies, cookies); - return this; - } - - /** - * 澧炲姞Cookie鍊 - * - * @param cookies cookie - * - * @return HttpResponse - */ - public HttpResponse addCookie(Collection cookies) { - this.cookies = Utility.append(this.cookies, cookies); - return this; - } - - /** - * 鍒涘缓CompletionHandler瀹炰緥 - * - * @return CompletionHandler - */ - public CompletionHandler createAsyncHandler() { - return Utility.createAsyncHandler((v, a) -> { - finish(v); - }, (t, a) -> { - context.getLogger().log(Level.WARNING, "Servlet occur, force to close channel. request = " + request + ", result is CompletionHandler", (Throwable) t); - finish(500, null); - }); - } - - /** - * 鍒涘缓CompletionHandler瀛愮被鐨勫疄渚
- * - * 浼犲叆鐨凜ompletionHandler瀛愮被蹇呴』鏄痯ublic锛屼笖淇濊瘉鍏跺瓙绫诲彲琚户鎵夸笖completed銆乫ailed鍙閲嶈浇涓斿寘鍚┖鍙傛暟鐨勬瀯閫犲嚱鏁般 - * - * @param 娉涘瀷 - * @param handlerClass CompletionHandler瀛愮被 - * - * @return CompletionHandler - */ - @SuppressWarnings("unchecked") - public H createAsyncHandler(Class handlerClass) { - if (handlerClass == null || handlerClass == CompletionHandler.class) return (H) createAsyncHandler(); - return context.loadAsyncHandlerCreator(handlerClass).create(createAsyncHandler()); - } - - /** - * 灏嗗璞′互JSON鏍煎紡杈撳嚭 - * - * @param obj 杈撳嚭瀵硅薄 - */ - public void finishJson(final Object obj) { - this.contentType = this.jsonContentType; - if (this.recycleListener != null) this.output = obj; - Convert c = request.getRespConvert(); - if (c == jsonRootConvert) { - JsonBytesWriter writer = jsonWriter; - c.convertTo(writer.clear(), obj); - finish(false, (String) null, writer.content(), writer.offset(), writer.length(), null, null); - } else { - c.convertToBytes(obj, convertHandler); - } - } - - /** - * 灏嗗璞′互JSON鏍煎紡杈撳嚭 - * - * @param convert 鎸囧畾鐨凧sonConvert - * @param obj 杈撳嚭瀵硅薄 - */ - public void finishJson(final JsonConvert convert, final Object obj) { - this.contentType = this.jsonContentType; - if (this.recycleListener != null) this.output = obj; - if (convert == jsonRootConvert) { - JsonBytesWriter writer = jsonWriter; - convert.convertTo(writer.clear(), obj); - finish(false, (String) null, writer.content(), writer.offset(), writer.length(), null, null); - } else { - convert.convertToBytes(obj, convertHandler); - } - } - - /** - * 灏嗗璞′互JSON鏍煎紡杈撳嚭 - * - * @param type 鎸囧畾鐨勭被鍨 - * @param obj 杈撳嚭瀵硅薄 - */ - public void finishJson(final Type type, final Object obj) { - this.contentType = this.jsonContentType; - if (this.recycleListener != null) this.output = obj; - Convert c = request.getRespConvert(); - if (c == jsonRootConvert) { - JsonBytesWriter writer = jsonWriter; - c.convertTo(writer.clear(), type, obj); - finish(false, (String) null, writer.content(), writer.offset(), writer.length(), null, null); - } else { - c.convertToBytes(type, obj, convertHandler); - } - } - - /** - * 灏嗗璞′互JSON鏍煎紡杈撳嚭 - * - * @param convert 鎸囧畾鐨凧sonConvert - * @param type 鎸囧畾鐨勭被鍨 - * @param obj 杈撳嚭瀵硅薄 - */ - public void finishJson(final JsonConvert convert, final Type type, final Object obj) { - this.contentType = this.jsonContentType; - if (this.recycleListener != null) this.output = obj; - if (convert == jsonRootConvert) { - JsonBytesWriter writer = jsonWriter; - convert.convertTo(writer.clear(), type, obj); - finish(false, (String) null, writer.content(), writer.offset(), writer.length(), null, null); - } else { - convert.convertToBytes(type, obj, convertHandler); - } - } - - /** - * 灏嗗璞′互JSON鏍煎紡杈撳嚭 - * - * @param objs 杈撳嚭瀵硅薄 - */ -// @Deprecated //@since 2.3.0 -// void finishJson(final Object... objs) { -// this.contentType = this.jsonContentType; -// if (this.recycleListener != null) this.output = objs; -// request.getRespConvert().convertToBytes(objs, convertHandler); -// } - /** - * 灏哛etResult瀵硅薄浠SON鏍煎紡杈撳嚭 - * - * @param type 鎸囧畾鐨凴etResult娉涘瀷绫诲瀷 - * @param ret RetResult杈撳嚭瀵硅薄 - */ - @Deprecated //@since 2.5.0 - public void finishJson(Type type, org.redkale.service.RetResult ret) { - this.contentType = this.jsonContentType; - if (this.retResultHandler != null) { - ret = this.retResultHandler.apply(this.request, ret); - } - if (this.recycleListener != null) this.output = ret; - if (ret != null && !ret.isSuccess()) { - this.header.addValue("retcode", String.valueOf(ret.getRetcode())); - this.header.addValue("retinfo", ret.getRetinfo()); - } - Convert convert = ret == null ? null : ret.convert(); - if (convert == null) convert = request.getRespConvert(); - if (convert == jsonRootConvert) { - JsonBytesWriter writer = jsonWriter; - convert.convertTo(writer.clear(), type, ret); - finish(false, (String) null, writer.content(), writer.offset(), writer.length(), null, null); - } else { - convert.convertToBytes(type, ret, convertHandler); - } - } - - /** - * 灏哛etResult瀵硅薄浠SON鏍煎紡杈撳嚭 - * - * @param convert 鎸囧畾鐨凧sonConvert - * @param type 鎸囧畾鐨凴etResult娉涘瀷绫诲瀷 - * @param ret RetResult杈撳嚭瀵硅薄 - */ - @Deprecated //@since 2.5.0 - public void finishJson(final JsonConvert convert, Type type, org.redkale.service.RetResult ret) { - this.contentType = this.jsonContentType; - if (this.retResultHandler != null) { - ret = this.retResultHandler.apply(this.request, ret); - } - if (this.recycleListener != null) this.output = ret; - if (ret != null && !ret.isSuccess()) { - this.header.addValue("retcode", String.valueOf(ret.getRetcode())); - this.header.addValue("retinfo", ret.getRetinfo()); - } - if (convert == jsonRootConvert) { - JsonBytesWriter writer = jsonWriter; - convert.convertTo(writer.clear(), type, ret); - finish(false, (String) null, writer.content(), writer.offset(), writer.length(), null, null); - } else { - convert.convertToBytes(type, ret, convertHandler); - } - } - - /** - * 灏咰ompletableFuture鐨勭粨鏋滃璞′互JSON鏍煎紡杈撳嚭 - * - * @param convert 鎸囧畾鐨凧sonConvert - * @param valueType 鎸囧畾CompletableFuture.value鐨勬硾鍨嬬被鍨 - * @param future 杈撳嚭瀵硅薄鐨勫彞鏌 - */ - @Deprecated //@since 2.5.0 - @SuppressWarnings("unchecked") - public void finishJson(final JsonConvert convert, final Type valueType, final CompletableFuture future) { - finish(convert, valueType, future); - } - - /** - * 灏哛etResult瀵硅薄杈撳嚭 - * - * @param type 鎸囧畾鐨凴etResult娉涘瀷绫诲瀷 - * @param ret RetResult杈撳嚭瀵硅薄 - */ - @SuppressWarnings("null") - public void finish(Type type, org.redkale.service.RetResult ret) { - if (this.retResultHandler != null) { - ret = this.retResultHandler.apply(this.request, ret); - } - if (this.recycleListener != null) this.output = ret; - if (ret != null && !ret.isSuccess()) { - this.header.addValue("retcode", String.valueOf(ret.getRetcode())); - this.header.addValue("retinfo", ret.getRetinfo()); - } - Convert cc = ret == null ? null : ret.convert(); - if (cc == null) cc = request.getRespConvert(); - if (cc instanceof JsonConvert) { - this.contentType = this.jsonContentType; - } else if (cc instanceof TextConvert) { - this.contentType = this.plainContentType; - } - if (cc == jsonRootConvert) { - JsonBytesWriter writer = jsonWriter; - cc.convertTo(writer.clear(), type, ret); - finish(false, (String) null, writer.content(), writer.offset(), writer.length(), null, null); - } else { - cc.convertToBytes(type, ret, convertHandler); - } - } - - /** - * 灏哛etResult瀵硅薄杈撳嚭 - * - * @param convert 鎸囧畾鐨凜onvert - * @param type 鎸囧畾鐨凴etResult娉涘瀷绫诲瀷 - * @param ret RetResult杈撳嚭瀵硅薄 - */ - @SuppressWarnings("null") - public void finish(final Convert convert, Type type, org.redkale.service.RetResult ret) { - if (this.retResultHandler != null) { - ret = this.retResultHandler.apply(this.request, ret); - } - if (this.recycleListener != null) this.output = ret; - if (ret != null && !ret.isSuccess()) { - this.header.addValue("retcode", String.valueOf(ret.getRetcode())); - this.header.addValue("retinfo", ret.getRetinfo()); - } - Convert cc = convert; - if (cc == null && ret != null) cc = ret.convert(); - if (cc == null) cc = request.getRespConvert(); - if (cc instanceof JsonConvert) { - this.contentType = this.jsonContentType; - } else if (cc instanceof TextConvert) { - this.contentType = this.plainContentType; - } - if (cc == jsonRootConvert) { - JsonBytesWriter writer = jsonWriter; - cc.convertTo(writer.clear(), type, ret); - finish(false, (String) null, writer.content(), writer.offset(), writer.length(), null, null); - } else { - cc.convertToBytes(type, ret, convertHandler); - } - } - - /** - * 灏咹ttpResult瀵硅薄杈撳嚭 - * - * @param resultType HttpResult.result鐨勬硾鍨嬬被鍨 - * @param result HttpResult杈撳嚭瀵硅薄 - */ - public void finish(Type resultType, HttpResult result) { - finish(request.getRespConvert(), resultType, result); - } - - /** - * 灏咹ttpResult瀵硅薄杈撳嚭 - * - * @param convert 鎸囧畾鐨凜onvert - * @param resultType HttpResult.result鐨勬硾鍨嬬被鍨 - * @param result HttpResult杈撳嚭瀵硅薄 - */ - public void finish(final Convert convert, Type resultType, HttpResult result) { - if (result.getContentType() != null) setContentType(result.getContentType()); - addHeader(result.getHeaders()).addCookie(result.getCookies()).setStatus(result.getStatus() < 1 ? 200 : result.getStatus()); - Object val = result.getResult(); - if (val == null) { - finish(""); - } else if (val instanceof CharSequence) { - finish(val.toString()); - } else { - Convert cc = result.convert(); - if (cc == null) cc = convert; - finish(cc, resultType, val); - } - } - - /** - * 灏咰ompletionStage瀵硅薄杈撳嚭 - * - * @param valueType CompletionFuture.value鐨勬硾鍨嬬被鍨 - * @param future CompletionStage杈撳嚭瀵硅薄 - */ - public void finish(Type valueType, CompletionStage future) { - finish(request.getRespConvert(), valueType, future); - } - - /** - * 灏咰ompletionStage瀵硅薄杈撳嚭 - * - * @param convert 鎸囧畾鐨凜onvert - * @param valueType CompletionFuture.value鐨勬硾鍨嬬被鍨 - * @param future CompletionStage杈撳嚭瀵硅薄 - */ - public void finish(final Convert convert, Type valueType, CompletionStage future) { - future.whenComplete((v, e) -> { - if (e != null) { - context.getLogger().log(Level.WARNING, "Servlet occur, force to close channel. request = " + request + ", result is CompletionStage", (Throwable) e); - if (e instanceof TimeoutException) { - finish504(); - } else { - finish500(); - } - return; - } - finish(convert, valueType, v); - }); - } - - /** - * 灏咶low.Publisher瀵硅薄杈撳嚭 - * - * @param 娉涘瀷 - * @param valueType Publisher鐨勬硾鍨嬬被鍨 - * @param publisher Publisher杈撳嚭瀵硅薄 - */ - public void finishPublisher(Type valueType, Flow.Publisher publisher) { - finishPublisher(request.getRespConvert(), valueType, publisher); - } - - /** - * 灏咶low.Publisher瀵硅薄杈撳嚭 - * - * @param 娉涘瀷 - * @param convert 鎸囧畾鐨凜onvert - * @param valueType Publisher鐨勬硾鍨嬬被鍨 - * @param publisher Publisher杈撳嚭瀵硅薄 - */ - public void finishPublisher(final Convert convert, Type valueType, Flow.Publisher publisher) { - finish(convert, valueType, (CompletionStage) Flows.createMonoFuture(publisher)); - } - - /** - * 灏嗙涓夋柟绫籉low.Publisher瀵硅薄(濡: Mono/Flux)杈撳嚭 - * - * @param valueType Publisher鐨勬硾鍨嬬被鍨 - * @param publisher Publisher杈撳嚭瀵硅薄 - */ - public void finishPublisher(Type valueType, Object publisher) { - finishPublisher(request.getRespConvert(), valueType, publisher); - } - - /** - * 灏嗙涓夋柟绫籉low.Publisher瀵硅薄(濡: Mono/Flux)杈撳嚭 - * - * @param convert 鎸囧畾鐨凜onvert - * @param valueType Publisher鐨勬硾鍨嬬被鍨 - * @param publisher Publisher杈撳嚭瀵硅薄 - */ - public void finishPublisher(final Convert convert, Type valueType, Object publisher) { - finish(convert, valueType, (CompletionStage) Flows.maybePublisherToFuture(publisher)); - } - - /** - * 灏咹ttpScope瀵硅薄杈撳嚭 - * - * @param result HttpScope杈撳嚭瀵硅薄 - */ - public void finish(HttpScope result) { - finish(request.getRespConvert(), result); - } - - /** - * 灏咹ttpScope瀵硅薄杈撳嚭 - * - * @param convert 鎸囧畾鐨凜onvert - * @param result HttpScope杈撳嚭瀵硅薄 - */ - public void finish(final Convert convert, HttpScope result) { - if (result == null) { - finish("null"); - return; - } - if (httpRender != null) { - setContentType(contentTypeHtmlUTF8); - if (result.getHeaders() != null) addHeader(result.getHeaders()); - if (result.getCookies() != null) addCookie(result.getCookies()); - httpRender.renderTo(this.request, this, convert, result); - return; - } - finish(""); - } - - /** - * 灏嗙粨鏋滃璞¤緭鍑 - * - * @param obj 杈撳嚭瀵硅薄 - */ - @SuppressWarnings("unchecked") - public void finish(final Object obj) { - finish(request.getRespConvert(), (Type) null, obj); - } - - /** - * 灏嗙粨鏋滃璞¤緭鍑 - * - * @param convert 鎸囧畾鐨凜onvert - * @param obj 杈撳嚭瀵硅薄 - */ - @SuppressWarnings("unchecked") - public void finish(final Convert convert, final Object obj) { - finish(convert, (Type) null, obj); - } - - /** - * 灏嗙粨鏋滃璞¤緭鍑 - * - * @param type 鎸囧畾鐨勭被鍨, 涓嶄竴瀹氭槸obj鐨勬暟鎹被鍨嬶紝蹇呯劧obj涓篊ompletableFuture锛 type搴旇涓篎uture鐨勫厓绱犵被鍨 - * @param obj 杈撳嚭瀵硅薄 - */ - @SuppressWarnings("unchecked") - public void finish(final Type type, Object obj) { - finish((Convert) null, type, obj); - } - - /** - * 灏嗙粨鏋滃璞¤緭鍑 - * - * @param convert 鎸囧畾鐨凜onvert - * @param type 鎸囧畾鐨勭被鍨, 涓嶄竴瀹氭槸obj鐨勬暟鎹被鍨嬶紝蹇呯劧obj涓篊ompletionStage锛 type搴旇涓篎uture鐨勫厓绱犵被鍨 - * @param obj 杈撳嚭瀵硅薄 - */ - @SuppressWarnings({"unchecked", "null"}) - public void finish(final Convert convert, final Type type, Object obj) { - Object val = obj; - //浠ヤ笅if鏉′欢浼氳Rest绫荤2440琛屽乏鍙崇殑鍦版柟鐢ㄥ埌 - if (val == null) { - Convert cc = convert; - if (cc == null) cc = request.getRespConvert(); - if (cc instanceof JsonConvert) { - this.contentType = this.jsonContentType; - } else if (cc instanceof TextConvert) { - this.contentType = this.plainContentType; - } - finish("null"); - } else if (val instanceof CompletionStage) { - finish(convert, val == obj ? type : null, (CompletionStage) val); - } else if (val instanceof CharSequence) { - finish((String) val.toString()); - } else if (val instanceof byte[]) { - finish((byte[]) val); - } else if (val instanceof File) { - try { - finish((File) val); - } catch (IOException e) { - context.getLogger().log(Level.WARNING, "HttpServlet finish File occur, force to close channel. request = " + getRequest(), e); - finish(500, null); - } - } else if (val instanceof org.redkale.service.RetResult) { - finish(convert, type, (org.redkale.service.RetResult) val); - } else if (val instanceof HttpResult) { - finish(convert, type, (HttpResult) val); - } else if (val instanceof HttpScope) { - finish(convert, (HttpScope) val); - } else { - Convert cc = convert; - if (cc == null) cc = request.getRespConvert(); - if (cc instanceof JsonConvert) { - this.contentType = this.jsonContentType; - } else if (cc instanceof TextConvert) { - this.contentType = this.plainContentType; - } - if (this.recycleListener != null) this.output = val; - //this.channel == null涓鸿櫄鎷熺殑HttpResponse - if (type == null) { - if (cc == jsonRootConvert) { - JsonBytesWriter writer = jsonWriter; - cc.convertTo(writer.clear(), val); - finish(false, (String) null, writer.content(), writer.offset(), writer.length(), null, null); - } else { - cc.convertToBytes(val, convertHandler); - } - } else { - if (cc == jsonRootConvert) { - JsonBytesWriter writer = jsonWriter; - cc.convertTo(writer.clear(), type, val); - finish(false, (String) null, writer.content(), writer.offset(), writer.length(), null, null); - } else { - cc.convertToBytes(type, val, convertHandler); - } - } - } - } - - /** - * 灏嗘寚瀹氬瓧绗︿覆浠ュ搷搴旂粨鏋滆緭鍑 - * - * @param obj 杈撳嚭鍐呭 - */ - public void finish(String obj) { - finish(200, obj); - } - - /** - * 浠ユ寚瀹氬搷搴旂爜闄勫甫鍐呭杈撳嚭 - * - * @param status 鍝嶅簲鐮 - * @param message 杈撳嚭鍐呭 - */ - public void finish(int status, String message) { - if (isClosed()) return; - this.status = status; - //if (status != 200) super.refuseAlive(); - final byte[] val = message == null ? HttpRequest.EMPTY_BYTES : (context.getCharset() == null ? Utility.encodeUTF8(message) : message.getBytes(context.getCharset())); - finish(false, null, val, 0, val.length, null, null); - } - - @Override - public void finish(boolean kill, final byte[] bs, int offset, int length) { - finish(false, null, bs, offset, length, null, null); - } - - public
void finish(final byte[] bs, int offset, int length, Consumer callback, A attachment) { - finish(false, null, bs, offset, length, callback, attachment); - } - - /** - * 灏嗘寚瀹歜yte[]鎸夊搷搴旂粨鏋滆緭鍑 - * - * @param contentType ContentType - * @param bs 杈撳嚭鍐呭 - */ - public void finish(final String contentType, final byte[] bs) { - finish(false, contentType, bs, 0, bs == null ? 0 : bs.length, null, null); - } - - /** - * 灏咮yteTuple鎸夊搷搴旂粨鏋滆緭鍑 - * - * @param contentType ContentType - * @param array 杈撳嚭鍐呭 - */ - public void finish(final String contentType, final ByteTuple array) { - finish(false, contentType, array.content(), array.offset(), array.length(), null, null); - } - - /** - * 灏嗘寚瀹歜yte[]鎸夊搷搴旂粨鏋滆緭鍑 - * - * @param kill kill - * @param contentType ContentType - * @param bs 杈撳嚭鍐呭 - * @param offset 鍋忕Щ閲 - * @param length 闀垮害 - */ - protected void finish(boolean kill, final String contentType, final byte[] bs, int offset, int length) { - finish(kill, contentType, bs, offset, length, null, null); - } - - /** - * 灏嗘寚瀹歜yte[]鎸夊搷搴旂粨鏋滆緭鍑 - * - * @param kill kill - * @param contentType ContentType - * @param bs 杈撳嚭鍐呭 - * @param offset 鍋忕Щ閲 - * @param length 闀垮害 - * @param callback Consumer - * @param attachment ConvertWriter - * @param A - */ - protected void finish(boolean kill, final String contentType, final byte[] bs, int offset, int length, Consumer callback, A attachment) { - if (isClosed()) return; //閬垮厤閲嶅鍏抽棴 - if (this.headWritedSize < 0) { - if (contentType != null) this.contentType = contentType; - this.contentLength = length; - createHeader(); - } - ByteArray data = headerArray; - data.put(bs, offset, length); - if (callback != null) callback.accept(attachment); - if (cacheHandler != null) cacheHandler.accept(this, data.getBytes()); - - int pipelineIndex = request.getPipelineIndex(); - if (pipelineIndex > 0) { - boolean over = this.channel.writePipelineData(pipelineIndex, request.getPipelineCount(), data); - if (over) { - request.setPipelineOver(true); - this.channel.flushPipelineData(this.pipelineWriteHandler); - } else { - removeChannel(); - this.responseConsumer.accept(this); - } - } else { - if (this.channel.hasPipelineData()) { - this.channel.writePipelineData(pipelineIndex, request.getPipelineCount(), data); - this.channel.flushPipelineData(this.pipelineWriteHandler); - } else { - //涓嶈兘鐢╢inish(boolean kill, final ByteTuple array) 鍚﹀垯浼氳皟this.finish - super.finish(false, data.content(), 0, data.length()); - } - } - -// ByteArray data = headerArray; -// int pipelineIndex = request.getPipelineIndex(); -// if (pipelineIndex > 0) { -// boolean over = this.channel.writePipelineData(pipelineIndex, request.getPipelineCount(), data.content(), 0, data.length(), bs, offset, length); -// if (callback != null) callback.accept(attachment); -// if (cacheHandler != null) cacheHandler.accept(this, Utility.append(data.getBytes(), bs, offset, length)); -// -// if (over) { -// request.setPipelineOver(true); -// this.channel.flushPipelineData(this.pipelineWriteHandler); -// } else { -// removeChannel(); -// this.responseConsumer.accept(this); -// } -// } else { -// if (this.channel.hasPipelineData()) { -// this.channel.writePipelineData(pipelineIndex, request.getPipelineCount(), data.content(), 0, data.length(), bs, offset, length); -// if (callback != null) callback.accept(attachment); -// if (cacheHandler != null) cacheHandler.accept(this, Utility.append(data.getBytes(), bs, offset, length)); -// this.channel.flushPipelineData(this.pipelineWriteHandler); -// } else { -// //涓嶈兘鐢╢inish(boolean kill, final ByteTuple array) 鍚﹀垯浼氳皟this.finish -// super.finish(false, data.content(), 0, data.length(), bs, offset, length, callback, attachment); -// } -// } - } - - /** - * 浠304鐘舵佺爜杈撳嚭 - */ - public void finish304() { - skipHeader(); - super.finish(false, bytes304); - } - - /** - * 浠404鐘舵佺爜杈撳嚭 - */ - public void finish404() { - skipHeader(); - super.finish(false, bytes404); - } - - /** - * 浠500鐘舵佺爜杈撳嚭 - */ - public void finish500() { - skipHeader(); - super.finish(false, bytes500); - } - - /** - * 浠504鐘舵佺爜杈撳嚭 - */ - public void finish504() { - skipHeader(); - super.finish(false, bytes504); - } - - //Header澶у皬 - protected void createHeader() { - if (this.status == 200 && !this.respHeadContainsConnection && !this.request.isWebSocket() - && (this.contentType == null || this.contentType == this.jsonContentType || this.contentType == this.plainContentType) - && (this.contentLength >= 0 && this.contentLength < jsonLiveContentLengthArray.length)) { - byte[][] lengthArray = this.plainLiveContentLengthArray; - if (this.request.isKeepAlive()) { - if (this.contentType == this.jsonContentType) { - lengthArray = this.jsonLiveContentLengthArray; - } - } else { - if (this.contentType == this.jsonContentType) { - lengthArray = this.jsonCloseContentLengthArray; - } else { - lengthArray = this.plainCloseContentLengthArray; - } - } - headerArray.put(lengthArray[(int) this.contentLength]); - } else { - if (this.status == 200 && !this.respHeadContainsConnection && !this.request.isWebSocket()) { - if (this.request.isKeepAlive()) { - headerArray.put(status200_server_live_Bytes); - } else { - headerArray.put(status200_server_close_Bytes); - } - } else { - if (this.status == 200) { - headerArray.put(status200Bytes); - } else { - headerArray.put(("HTTP/1.1 " + this.status + " " + httpCodes.get(this.status) + "\r\n").getBytes()); - } - headerArray.put(serverNameBytes); - if (!this.respHeadContainsConnection) { - byte[] bs = this.request.isKeepAlive() ? connectAliveBytes : connectCloseBytes; - if (bs.length > 0) headerArray.put(bs); - } - } - if (!this.request.isWebSocket()) { - if (this.contentType == this.jsonContentType) { - headerArray.put(this.jsonContentTypeBytes); - } else if (this.contentType == null || this.contentType == this.plainContentType) { - headerArray.put(this.plainContentTypeBytes); - } else { - headerArray.put(("Content-Type: " + this.contentType + "\r\n").getBytes()); - } - } - if (this.contentLength >= 0) { - if (this.contentLength < contentLengthArray.length) { - headerArray.put(contentLengthArray[(int) this.contentLength]); - } else { - headerArray.put(("Content-Length: " + this.contentLength + "\r\n").getBytes()); - } - } - } - if (dateSupplier != null) headerArray.put(dateSupplier.get()); - - if (this.defaultAddHeaders != null) { - for (String[] headers : this.defaultAddHeaders) { - if (headers.length > 3) { - String v = request.getParameter(headers[2]); - if (v != null) this.header.addValue(headers[0], v); - } else if (headers.length > 2) { - String v = request.getHeader(headers[2]); - if (v != null) this.header.addValue(headers[0], v); - } else { - this.header.addValue(headers[0], headers[1]); - } - } - } - if (this.defaultSetHeaders != null) { - for (String[] headers : this.defaultSetHeaders) { - if (headers.length > 3) { - String v = request.getParameter(headers[2]); - if (v != null) this.header.setValue(headers[0], v); - } else if (headers.length > 2) { - String v = request.getHeader(headers[2]); - if (v != null) this.header.setValue(headers[0], v); - } else { - this.header.setValue(headers[0], headers[1]); - } - } - } - for (Entry en : this.header.getStringEntrys()) { - headerArray.put((en.name + ": " + en.getValue() + "\r\n").getBytes()); - } - if (request.newsessionid != null) { - String domain = defaultCookie == null ? null : defaultCookie.getDomain(); - if (domain == null || domain.isEmpty()) { - domain = ""; - } else { - domain = "Domain=" + domain + "; "; - } - String path = defaultCookie == null ? null : defaultCookie.getPath(); - if (path == null || path.isEmpty()) path = "/"; - if (request.newsessionid.isEmpty()) { - headerArray.put(("Set-Cookie: " + HttpRequest.SESSIONID_NAME + "=; " + domain + "Path=/; Max-Age=0; HttpOnly\r\n").getBytes()); - } else { - headerArray.put(("Set-Cookie: " + HttpRequest.SESSIONID_NAME + "=" + request.newsessionid + "; " + domain + "Path=/; HttpOnly\r\n").getBytes()); - } - } - if (this.cookies != null) { - for (HttpCookie cookie : this.cookies) { - if (cookie == null) continue; - if (defaultCookie != null) { - if (defaultCookie.getDomain() != null && cookie.getDomain() == null) cookie.setDomain(defaultCookie.getDomain()); - if (defaultCookie.getPath() != null && cookie.getPath() == null) cookie.setPath(defaultCookie.getPath()); - } - headerArray.put(("Set-Cookie: " + cookieString(cookie) + "\r\n").getBytes()); - } - } - headerArray.put(LINE); - this.headWritedSize = headerArray.length(); - } - - private CharSequence cookieString(HttpCookie cookie) { - StringBuilder sb = new StringBuilder(); - sb.append(cookie.getName()).append("=").append(cookie.getValue()).append("; Version=1"); - if (cookie.getDomain() != null) sb.append("; Domain=").append(cookie.getDomain()); - if (cookie.getPath() != null) sb.append("; Path=").append(cookie.getPath()); - if (cookie.getPortlist() != null) sb.append("; Port=").append(cookie.getPortlist()); - if (cookie.getMaxAge() > 0) { - sb.append("; Max-Age=").append(cookie.getMaxAge()); - sb.append("; Expires=").append(RFC_1123_DATE_TIME.format(java.time.ZonedDateTime.now(ZONE_GMT).plusSeconds(cookie.getMaxAge()))); - } - if (cookie.getSecure()) sb.append("; Secure"); - if (cookie.isHttpOnly()) sb.append("; HttpOnly"); - return sb; - } - - /** - * 寮傛杈撳嚭鎸囧畾鍐呭 - * - * @param 娉涘瀷 - * @param buffer 杈撳嚭鍐呭 - * @param handler 寮傛鍥炶皟鍑芥暟 - */ - protected void sendBody(ByteBuffer buffer, CompletionHandler handler) { - if (this.headWritedSize < 0) { - if (this.contentLength < 0) this.contentLength = buffer == null ? 0 : buffer.remaining(); - createHeader(); - if (buffer == null) { - super.send(headerArray, handler); - } else { - ByteBuffer headbuf = channel.pollWriteBuffer(); - headbuf.put(headerArray.content(), 0, headerArray.length()); - headbuf.flip(); - super.send(new ByteBuffer[]{headbuf, buffer}, null, handler); - } - } else { - super.send(buffer, null, handler); - } - } - - /** - * 灏嗘寚瀹氭枃浠舵寜鍝嶅簲缁撴灉杈撳嚭 - * - * @param file 杈撳嚭鏂囦欢 - * - * @throws IOException IO寮傚父 - */ - public void finish(File file) throws IOException { - finishFile(null, file, null); - } - - /** - * 灏嗘枃浠舵寜鎸囧畾鏂囦欢鍚嶈緭鍑 - * - * @param filename 杈撳嚭鏂囦欢鍚 - * @param file 杈撳嚭鏂囦欢 - * - * @throws IOException IO寮傚父 - */ - public void finish(final String filename, File file) throws IOException { - finishFile(filename, file, null); - } - - /** - * 灏嗘寚瀹氭枃浠跺彞鏌勬垨鏂囦欢鍐呭鎸夊搷搴旂粨鏋滆緭鍑猴紝鑻ileBody涓嶄负null鍒欏彧杈撳嚭fileBody鍐呭 - * - * @param file 杈撳嚭鏂囦欢 - * @param fileBody 鏂囦欢鍐呭锛 娌℃湁鍒欒緭鍑篺ile - * - * @throws IOException IO寮傚父 - */ - protected void finishFile(final File file, ByteArray fileBody) throws IOException { - finishFile(null, file, fileBody); - } - - /** - * 灏嗘寚瀹氭枃浠跺彞鏌勬垨鏂囦欢鍐呭鎸夋寚瀹氭枃浠跺悕杈撳嚭锛岃嫢fileBody涓嶄负null鍒欏彧杈撳嚭fileBody鍐呭 - * file 涓 fileBody 涓嶈兘鍚屾椂涓虹┖ - * file 涓 filename 涔熶笉鑳藉悓鏃朵负绌 - * - * @param filename 杈撳嚭鏂囦欢鍚 - * @param file 杈撳嚭鏂囦欢 - * @param fileBody 鏂囦欢鍐呭锛 娌℃湁鍒欒緭鍑篺ile - * - * @throws IOException IO寮傚父 - */ - protected void finishFile(final String filename, final File file, ByteArray fileBody) throws IOException { - if ((file == null || !file.isFile() || !file.canRead()) && fileBody == null) { - finish404(); - return; - } - final long length = file == null ? fileBody.length() : file.length(); - final String match = request.getHeader("If-None-Match"); - final String etag = (file == null ? 0L : file.lastModified()) + "-" + length; - if (match != null && etag.equals(match)) { - //finish304(); - //return; - } - this.contentLength = length; - if (filename != null && !filename.isEmpty() && file != null) { - if (this.header.getValue("Content-Disposition") == null) { - addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8")); - } - } - this.contentType = MimeType.getByFilename(filename == null || filename.isEmpty() ? file.getName() : filename); - if (this.contentType == null) this.contentType = "application/octet-stream"; - String range = request.getHeader("Range"); - if (range != null && (!range.startsWith("bytes=") || range.indexOf(',') >= 0)) range = null; - long start = -1; - long len = -1; - if (range != null) { - range = range.substring("bytes=".length()); - int pos = range.indexOf('-'); - start = pos == 0 ? 0 : Integer.parseInt(range.substring(0, pos)); - long end = (pos == range.length() - 1) ? -1 : Long.parseLong(range.substring(pos + 1)); - long clen = end > 0 ? (end - start + 1) : (length - start); - this.status = 206; - addHeader("Accept-Ranges", "bytes"); - addHeader("Content-Range", "bytes " + start + "-" + (end > 0 ? end : length - 1) + "/" + length); - this.contentLength = clen; - len = end > 0 ? clen : end; - } - this.addHeader("ETag", etag); - createHeader(); - ByteArray data = headerArray; - if (fileBody == null) { - if (this.recycleListener != null) this.output = file; - finishFile(data, file, start, len); - } else { //涓鑸琀ttpResourceServlet缂撳瓨file鍐呭鏃秄ileBody涓嶄负绌 - if (start >= 0) data.put(fileBody, (int) start, (int) ((len > 0) ? len : fileBody.length() - start)); - super.finish(false, data.content(), 0, data.length()); - } - } - - //offset銆乴ength 涓 -1 琛ㄧず杈撳嚭鏁翠釜鏂囦欢 - private void finishFile(ByteArray headerData, File file, long offset, long length) throws IOException { - //this.channel.write(headerData, new TransferFileHandler(file, offset, length)); - final Logger logger = context.getLogger(); - this.channel.write(headerData, new CompletionHandler() { - - FileChannel fileChannel; - - long limit; - - long sends; - - ByteBuffer buffer; - - @Override - public void completed(Integer result, Void attachment) { - try { - if (fileChannel != null && sends >= limit) { - if (buffer != null) channel.offerBuffer(buffer); - try { - fileChannel.close(); - } catch (IOException ie) { - } - finish(); - return; - } - if (fileChannel == null) { - fileChannel = FileChannel.open(file.toPath(), StandardOpenOption.READ); - if (offset > 0) fileChannel = fileChannel.position(offset); - limit = length > 0 ? length : (file.length() - (offset > 0 ? offset : 0)); - sends = 0; - buffer = channel.ssl() ? channel.pollWriteSSLBuffer() : channel.pollWriteBuffer(); - } - - buffer.clear(); - int len = fileChannel.read(buffer); - if (len < 1) throw new IOException("read " + file + " error: " + len); - buffer.flip(); - if (sends + len > limit) { - buffer.limit((int) (len - limit + sends)); - sends = limit; - } else { - sends += len; - } - channel.write(buffer, attachment, this); - } catch (Exception e) { - if (fileChannel != null) { - try { - fileChannel.close(); - } catch (IOException ie) { - } - } - failed(e, attachment); - } - } - - @Override - public void failed(Throwable exc, Void attachment) { - if (buffer != null) channel.offerBuffer(buffer); - if (logger.isLoggable(Level.FINER)) logger.log(Level.FINER, "finishFile error", exc); - finish(true); - } - }); - } - - /** - * 璺宠繃header鐨勮緭鍑 - * 閫氬父搴旂敤鍦烘櫙鏄紝璋冪敤鑰呯殑杈撳嚭鍐呭閲屽凡缁忓寘鍚簡HTTP鐨勫搷搴斿ご淇℃伅锛屽洜姝ら渶瑕佽皟鐢ㄦ鏂规硶閬垮厤閲嶅杈撳嚭HTTP鍝嶅簲澶翠俊鎭 - * - * @return HttpResponse - */ - public HttpResponse skipHeader() { - this.headWritedSize = 0; - return this; - } - - protected DefaultAnyValue duplicateHeader() { - return this.header.duplicate(); - } - - /** - * 璁剧疆Header鍊 - * - * @param name header鍚 - * @param value header鍊 - * - * @return HttpResponse - */ - public HttpResponse setHeader(String name, Object value) { - this.header.setValue(name, String.valueOf(value)); - if ("Connection".equalsIgnoreCase(name)) this.respHeadContainsConnection = true; - return this; - } - - /** - * 娣诲姞Header鍊 - * - * @param name header鍚 - * @param value header鍊 - * - * @return HttpResponse - */ - public HttpResponse addHeader(String name, Object value) { - this.header.addValue(name, String.valueOf(value)); - if ("Connection".equalsIgnoreCase(name)) this.respHeadContainsConnection = true; - return this; - } - - /** - * 娣诲姞Header鍊 - * - * @param map header鍊 - * - * @return HttpResponse - */ - public HttpResponse addHeader(Map map) { - if (map == null || map.isEmpty()) return this; - for (Map.Entry en : map.entrySet()) { - this.header.addValue(en.getKey(), String.valueOf(en.getValue())); - if (!respHeadContainsConnection && "Connection".equalsIgnoreCase(en.getKey())) { - this.respHeadContainsConnection = true; - } - } - return this; - } - - /** - * 璁剧疆鐘舵佺爜 - * - * @param status 鐘舵佺爜 - * - * @return HttpResponse - */ - public HttpResponse setStatus(int status) { - this.status = status; - return this; - } - - /** - * 鑾峰彇鐘舵佺爜 - * - * @return 鐘舵佺爜 - */ - public int getStatus() { - return this.status; - } - - /** - * 鑾峰彇 ContentType - * - * @return ContentType - */ - public String getContentType() { - return contentType; - } - - /** - * 璁剧疆 ContentType - * - * @param contentType ContentType - * - * @return HttpResponse - */ - public HttpResponse setContentType(String contentType) { - this.contentType = contentType; - return this; - } - - /** - * 鑾峰彇鍐呭闀垮害 - * - * @return 鍐呭闀垮害 - */ - public long getContentLength() { - return contentLength; - } - - /** - * 璁剧疆鍐呭闀垮害 - * - * @param contentLength 鍐呭闀垮害 - * - * @return HttpResponse - */ - public HttpResponse setContentLength(long contentLength) { - this.contentLength = contentLength; - return this; - } - - /** - * 鑾峰彇杈撳嚭鏃剁殑鎷︽埅鍣 - * - * @return 鎷︽埅鍣 - */ - protected BiConsumer getCacheHandler() { - return cacheHandler; - } - - /** - * 璁剧疆杈撳嚭鏃剁殑鎷︽埅鍣 - * - * @param cacheHandler 鎷︽埅鍣 - */ - protected void setCacheHandler(BiConsumer cacheHandler) { - this.cacheHandler = cacheHandler; - } - - /** - * 鑾峰彇杈撳嚭RetResult鏃剁殑鎷︽埅鍣 - * - * @return 鎷︽埅鍣 - */ - protected BiFunction getRetResultHandler() { - return retResultHandler; - } - - /** - * 璁剧疆杈撳嚭RetResult鏃剁殑鎷︽埅鍣 - * - * @param retResultHandler 鎷︽埅鍣 - */ - public void retResultHandler(BiFunction retResultHandler) { - this.retResultHandler = retResultHandler; - } - -// protected final class TransferFileHandler implements CompletionHandler { -// -// private final File file; -// -// private final AsynchronousFileChannel filechannel; -// -// private final long max; //闇瑕佽鍙栫殑瀛楄妭鏁帮紝 -1琛ㄧず璇诲埌鏂囦欢缁撳熬 -// -// private long count;//璇诲彇鏂囦欢鐨勫瓧鑺傛暟 -// -// private long readpos = 0; -// -// private boolean hdwrite = true; //鍐欏叆Header -// -// private boolean read = false; -// -// public TransferFileHandler(File file) throws IOException { -// this.file = file; -// this.filechannel = AsynchronousFileChannel.open(file.toPath(), options); -// this.readpos = 0; -// this.max = file.length(); -// } -// -// public TransferFileHandler(File file, long offset, long len) throws IOException { -// this.file = file; -// this.filechannel = AsynchronousFileChannel.open(file.toPath(), options); -// this.readpos = offset <= 0 ? 0 : offset; -// this.max = len <= 0 ? file.length() : len; -// } -// -// @Override -// public void completed(Integer result, Void attachment) { -// //(Utility.now() + "---" + Thread.currentThread().getName() + "-----------" + file + "-------------------result: " + result + ", max = " + max + ", readpos = " + readpos + ", count = " + count + ", " + (hdwrite ? "姝e湪鍐橦eader" : (read ? "鍑嗗璇" : "鍑嗗鍐"))); -// if (result < 0 || count >= max) { -// failed(null, attachment); -// return; -// } -// if (hdwrite && attachment.hasRemaining()) { //Header杩樻病鍐欏畬 -// channel.write(attachment, attachment, this); -// return; -// } -// if (hdwrite) { -// //(Utility.now() + "---" + Thread.currentThread().getName() + "-----------" + file + "-------------------Header鍐欏叆瀹屾瘯锛 鍑嗗璇诲彇鏂囦欢."); -// hdwrite = false; -// read = true; -// result = 0; -// } -// if (read) { -// count += result; -// } else { -// readpos += result; -// } -// if (read && attachment.hasRemaining()) { //Buffer杩樻病鍐欏畬 -// channel.write(attachment, attachment, this); -// return; -// } -// -// if (read) { -// read = false; -// attachment.clear(); -// filechannel.read(attachment, readpos, attachment, this); -// } else { -// read = true; -// if (count > max) { -// attachment.limit((int) (attachment.position() + max - count)); -// } -// attachment.flip(); -// if (attachment.hasRemaining()) { -// channel.write(attachment, attachment, this); -// } else { -// failed(null, attachment); -// } -// } -// } -// -// @Override -// public void failed(Throwable exc, Void attachment) { -// finish(true); -// try { -// filechannel.close(); -// } catch (IOException e) { -// } -// } -// -// } - public static class HttpResponseConfig { - - public String plainContentType; - - public String jsonContentType; - - public byte[] plainContentTypeBytes; - - public byte[] jsonContentTypeBytes; - - public String[][] defaultAddHeaders; - - public String[][] defaultSetHeaders; - - public HttpCookie defaultCookie; - - public boolean autoOptions; - - public Supplier dateSupplier; - - public HttpRender httpRender; - - public final byte[][] plainLiveContentLengthArray = new byte[cacheMaxContentLength][]; - - public final byte[][] jsonLiveContentLengthArray = new byte[cacheMaxContentLength][]; - - public final byte[][] plainCloseContentLengthArray = new byte[cacheMaxContentLength][]; - - public final byte[][] jsonCloseContentLengthArray = new byte[cacheMaxContentLength][]; - - public HttpResponseConfig init(AnyValue config) { - if (this.plainContentTypeBytes == null) { - String plainct = plainContentType == null || plainContentType.isEmpty() ? "text/plain; charset=utf-8" : plainContentType; - String jsonct = jsonContentType == null || jsonContentType.isEmpty() ? "application/json; charset=utf-8" : jsonContentType; - this.plainContentType = plainct; - this.jsonContentType = jsonct; - this.plainContentTypeBytes = ("Content-Type: " + plainct + "\r\n").getBytes(); - this.jsonContentTypeBytes = ("Content-Type: " + jsonct + "\r\n").getBytes(); - for (int i = 0; i < cacheMaxContentLength; i++) { - byte[] lenbytes = ("Content-Length: " + i + "\r\n").getBytes(); - plainLiveContentLengthArray[i] = append(append(status200_server_live_Bytes, plainContentTypeBytes), lenbytes); - plainCloseContentLengthArray[i] = append(append(status200_server_close_Bytes, plainContentTypeBytes), lenbytes); - jsonLiveContentLengthArray[i] = append(append(status200_server_live_Bytes, jsonContentTypeBytes), lenbytes); - jsonCloseContentLengthArray[i] = append(append(status200_server_close_Bytes, jsonContentTypeBytes), lenbytes); - } - } - return this; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - } -} +/* + * 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 java.io.*; +import java.lang.reflect.Type; +import java.net.*; +import java.nio.ByteBuffer; +import java.nio.channels.*; +import java.nio.file.*; +import java.time.ZoneId; +import static java.time.format.DateTimeFormatter.RFC_1123_DATE_TIME; +import java.util.*; +import java.util.concurrent.*; +import java.util.function.*; +import java.util.logging.*; +import org.redkale.convert.*; +import org.redkale.convert.json.*; +import org.redkale.net.*; +import org.redkale.util.AnyValue.DefaultAnyValue; +import org.redkale.util.AnyValue.Entry; +import org.redkale.util.*; +import static org.redkale.util.Utility.append; + +/** + * Http鍝嶅簲鍖 涓巎avax.servlet.http.HttpServletResponse 鍩烘湰绫讳技銆
+ * 鍚屾椂鎻愪緵鍙戦乯son鐨勭郴鍒楁帴鍙: public void finishJson(Type type, Object obj)
+ * Redkale鎻愬ttp+json鐨勬帴鍙i鏍硷紝 鎵浠ヤ富瑕佽緭鍑虹殑鏁版嵁鏍煎紡涓簀son锛 鍚屾椂鎻愪緵寮傛鎺ュ彛銆
+ *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public class HttpResponse extends Response { + + protected static final byte[] bytes304 = "HTTP/1.1 304 Not Modified\r\nContent-Length:0\r\n\r\n".getBytes(); + + protected static final byte[] bytes404 = "HTTP/1.1 404 Not Found\r\nContent-Length:0\r\n\r\n".getBytes(); + + protected static final byte[] bytes500 = "HTTP/1.1 500 Internal Server Error\r\nContent-Length:0\r\n\r\n".getBytes(); + + protected static final byte[] bytes504 = "HTTP/1.1 504 Gateway Timeout\r\nContent-Length:0\r\n\r\n".getBytes(); + + protected static final byte[] status200Bytes = "HTTP/1.1 200 OK\r\n".getBytes(); + + protected static final byte[] LINE = new byte[]{'\r', '\n'}; + + protected static final byte[] serverNameBytes = ("Server: " + System.getProperty("redkale.http.response.header.server", "redkale" + "/" + Redkale.getDotedVersion()) + "\r\n").getBytes(); + + protected static final byte[] connectCloseBytes = "none".equalsIgnoreCase(System.getProperty("redkale.http.response.header.connection")) ? new byte[0] : "Connection: close\r\n".getBytes(); + + protected static final byte[] connectAliveBytes = "none".equalsIgnoreCase(System.getProperty("redkale.http.response.header.connection")) ? new byte[0] : "Connection: keep-alive\r\n".getBytes(); + + protected static final String contentTypeHtmlUTF8 = "text/html; charset=utf-8"; + + private static final int cacheMaxContentLength = 1000; + + private static final byte[] status200_server_live_Bytes = append(append(status200Bytes, serverNameBytes), connectAliveBytes); + + private static final byte[] status200_server_close_Bytes = append(append(status200Bytes, serverNameBytes), connectCloseBytes); + + private static final ZoneId ZONE_GMT = ZoneId.of("GMT"); + + private static final OpenOption[] options = new OpenOption[]{StandardOpenOption.READ}; + + private static final Map httpCodes = new HashMap<>(); + + private static final byte[][] contentLengthArray = new byte[cacheMaxContentLength][]; + + private static final JsonConvert jsonRootConvert = JsonConvert.root(); + + static { + + httpCodes.put(100, "Continue"); + httpCodes.put(101, "Switching Protocols"); + + httpCodes.put(200, "OK"); + httpCodes.put(201, "Created"); + httpCodes.put(202, "Accepted"); + httpCodes.put(203, "Non-Authoritative Information"); + httpCodes.put(204, "No Content"); + httpCodes.put(205, "Reset Content"); + httpCodes.put(206, "Partial Content"); + + httpCodes.put(300, "Multiple Choices"); + httpCodes.put(301, "Moved Permanently"); + httpCodes.put(302, "Found"); + httpCodes.put(303, "See Other"); + httpCodes.put(304, "Not Modified"); + httpCodes.put(305, "Use Proxy"); + httpCodes.put(307, "Temporary Redirect"); + + httpCodes.put(400, "Bad Request"); + httpCodes.put(401, "Unauthorized"); + httpCodes.put(402, "Payment Required"); + httpCodes.put(403, "Forbidden"); + httpCodes.put(404, "Not Found"); + httpCodes.put(405, "Method Not Allowed"); + httpCodes.put(406, "Not Acceptable"); + httpCodes.put(407, "Proxy Authentication Required"); + httpCodes.put(408, "Request Timeout"); + httpCodes.put(409, "Conflict"); + httpCodes.put(410, "Gone"); + httpCodes.put(411, "Length Required"); + httpCodes.put(412, "Precondition Failed"); + httpCodes.put(413, "Request Entity Too Large"); + httpCodes.put(414, "Request URI Too Long"); + httpCodes.put(415, "Unsupported Media Type"); + httpCodes.put(416, "Requested Range Not Satisfiable"); + httpCodes.put(417, "Expectation Failed"); + + httpCodes.put(500, "Internal Server Error"); + httpCodes.put(501, "Not Implemented"); + httpCodes.put(502, "Bad Gateway"); + httpCodes.put(503, "Service Unavailable"); + httpCodes.put(504, "Gateway Timeout"); + httpCodes.put(505, "HTTP Version Not Supported"); + + for (int i = 0; i < cacheMaxContentLength; i++) { + contentLengthArray[i] = ("Content-Length: " + i + "\r\n").getBytes(); + } + } + + private int status = 200; + + private String contentType = ""; + + private long contentLength = -1; + + private HttpCookie[] cookies; + + private boolean respHeadContainsConnection; + + private int headWritedSize = -1; //0琛ㄧず璺宠繃header锛屾鏁拌〃绀篽eader鐨勫瓧鑺傞暱搴︺ + + private BiConsumer cacheHandler; + + private BiFunction retResultHandler; + + //------------------------------------------------ + private final String plainContentType; + + private final byte[] plainContentTypeBytes; + + private final String jsonContentType; + + private final byte[] jsonContentTypeBytes; + + private final DefaultAnyValue header = new DefaultAnyValue(); + + private final String[][] defaultAddHeaders; + + private final String[][] defaultSetHeaders; + + private final boolean autoOptions; + + private final Supplier dateSupplier; + + private final HttpCookie defaultCookie; + + private final HttpRender httpRender; + + private final ByteArray headerArray = new ByteArray(); + + private final byte[][] plainLiveContentLengthArray; + + private final byte[][] jsonLiveContentLengthArray; + + private final byte[][] plainCloseContentLengthArray; + + private final byte[][] jsonCloseContentLengthArray; + + private final JsonBytesWriter jsonWriter = new JsonBytesWriter(); + + protected final CompletionHandler pipelineWriteHandler = new CompletionHandler() { + + @Override + public void completed(Integer result, Void attachment) { + finish(); + } + + @Override + public void failed(Throwable exc, Void attachment) { + finish(true); + } + }; + + @SuppressWarnings("Convert2Lambda") + protected final ConvertBytesHandler convertHandler = new ConvertBytesHandler() { + @Override + public void completed(byte[] bs, int offset, int length, Consumer callback, A attachment) { + finish(bs, offset, length, callback, attachment); + } + }; + + public HttpResponse(HttpContext context, HttpRequest request, HttpResponseConfig config) { + super(context, request); + this.defaultAddHeaders = config == null ? null : config.defaultAddHeaders; + this.defaultSetHeaders = config == null ? null : config.defaultSetHeaders; + this.defaultCookie = config == null ? null : config.defaultCookie; + this.autoOptions = config == null ? false : config.autoOptions; + this.dateSupplier = config == null ? null : config.dateSupplier; + this.httpRender = config == null ? null : config.httpRender; + + this.plainContentType = config == null ? "text/plain; charset=utf-8" : config.plainContentType; + this.jsonContentType = config == null ? "application/json; charset=utf-8" : config.jsonContentType; + this.plainContentTypeBytes = config == null ? ("Content-Type: " + this.plainContentType + "\r\n").getBytes() : config.plainContentTypeBytes; + this.jsonContentTypeBytes = config == null ? ("Content-Type: " + this.jsonContentType + "\r\n").getBytes() : config.jsonContentTypeBytes; + this.plainLiveContentLengthArray = config == null ? null : config.plainLiveContentLengthArray; + this.plainCloseContentLengthArray = config == null ? null : config.plainCloseContentLengthArray; + this.jsonLiveContentLengthArray = config == null ? null : config.jsonLiveContentLengthArray; + this.jsonCloseContentLengthArray = config == null ? null : config.jsonCloseContentLengthArray; + this.contentType = this.plainContentType; + } + + @Override + protected AsyncConnection removeChannel() { + return super.removeChannel(); + } + + protected AsyncConnection getChannel() { + return channel; + } + + @Override + protected void prepare() { + super.prepare(); + } + + @Override + protected boolean recycle() { + this.status = 200; + this.contentLength = -1; + this.contentType = null; + this.cookies = null; + this.headWritedSize = -1; + //this.headBuffer = null; + this.header.clear(); + this.headerArray.clear(); + this.cacheHandler = null; + this.retResultHandler = null; + this.respHeadContainsConnection = false; + this.jsonWriter.recycle(); + return super.recycle(); + } + +// protected Supplier getBodyBufferSupplier() { +// return bodyBufferSupplier; +// } + @Override + protected void init(AsyncConnection channel) { + super.init(channel); + } + + /** + * 鑾峰彇鐘舵佺爜瀵瑰簲鐨勭姸鎬佹弿杩 + * + * @param status 鐘舵佺爜 + * + * @return 鐘舵佹弿杩 + */ + protected String getHttpCode(int status) { + return httpCodes.get(status); + } + + protected HttpRequest getRequest() { + return request; + } + + protected String getHttpCode(int status, String defValue) { + String v = httpCodes.get(status); + return v == null ? defValue : v; + } + + @Override + @SuppressWarnings("unchecked") + protected void thenEvent(Servlet servlet) { + this.servlet = servlet; + } + + protected boolean isAutoOptions() { + return this.autoOptions; + } + + /** + * 澧炲姞Cookie鍊 + * + * @param cookies cookie + * + * @return HttpResponse + */ + public HttpResponse addCookie(HttpCookie... cookies) { + this.cookies = Utility.append(this.cookies, cookies); + return this; + } + + /** + * 澧炲姞Cookie鍊 + * + * @param cookies cookie + * + * @return HttpResponse + */ + public HttpResponse addCookie(Collection cookies) { + this.cookies = Utility.append(this.cookies, cookies); + return this; + } + + /** + * 鍒涘缓CompletionHandler瀹炰緥 + * + * @return CompletionHandler + */ + public CompletionHandler createAsyncHandler() { + return Utility.createAsyncHandler((v, a) -> { + finish(v); + }, (t, a) -> { + context.getLogger().log(Level.WARNING, "Servlet occur, force to close channel. request = " + request + ", result is CompletionHandler", (Throwable) t); + finish(500, null); + }); + } + + /** + * 鍒涘缓CompletionHandler瀛愮被鐨勫疄渚
+ * + * 浼犲叆鐨凜ompletionHandler瀛愮被蹇呴』鏄痯ublic锛屼笖淇濊瘉鍏跺瓙绫诲彲琚户鎵夸笖completed銆乫ailed鍙閲嶈浇涓斿寘鍚┖鍙傛暟鐨勬瀯閫犲嚱鏁般 + * + * @param 娉涘瀷 + * @param handlerClass CompletionHandler瀛愮被 + * + * @return CompletionHandler + */ + @SuppressWarnings("unchecked") + public H createAsyncHandler(Class handlerClass) { + if (handlerClass == null || handlerClass == CompletionHandler.class) return (H) createAsyncHandler(); + return context.loadAsyncHandlerCreator(handlerClass).create(createAsyncHandler()); + } + + /** + * 灏嗗璞′互JSON鏍煎紡杈撳嚭 + * + * @param obj 杈撳嚭瀵硅薄 + */ + public void finishJson(final Object obj) { + this.contentType = this.jsonContentType; + if (this.recycleListener != null) this.output = obj; + Convert c = request.getRespConvert(); + if (c == jsonRootConvert) { + JsonBytesWriter writer = jsonWriter; + c.convertTo(writer.clear(), obj); + finish(false, (String) null, writer.content(), writer.offset(), writer.length(), null, null); + } else { + c.convertToBytes(obj, convertHandler); + } + } + + /** + * 灏嗗璞′互JSON鏍煎紡杈撳嚭 + * + * @param convert 鎸囧畾鐨凧sonConvert + * @param obj 杈撳嚭瀵硅薄 + */ + public void finishJson(final JsonConvert convert, final Object obj) { + this.contentType = this.jsonContentType; + if (this.recycleListener != null) this.output = obj; + if (convert == jsonRootConvert) { + JsonBytesWriter writer = jsonWriter; + convert.convertTo(writer.clear(), obj); + finish(false, (String) null, writer.content(), writer.offset(), writer.length(), null, null); + } else { + convert.convertToBytes(obj, convertHandler); + } + } + + /** + * 灏嗗璞′互JSON鏍煎紡杈撳嚭 + * + * @param type 鎸囧畾鐨勭被鍨 + * @param obj 杈撳嚭瀵硅薄 + */ + public void finishJson(final Type type, final Object obj) { + this.contentType = this.jsonContentType; + if (this.recycleListener != null) this.output = obj; + Convert c = request.getRespConvert(); + if (c == jsonRootConvert) { + JsonBytesWriter writer = jsonWriter; + c.convertTo(writer.clear(), type, obj); + finish(false, (String) null, writer.content(), writer.offset(), writer.length(), null, null); + } else { + c.convertToBytes(type, obj, convertHandler); + } + } + + /** + * 灏嗗璞′互JSON鏍煎紡杈撳嚭 + * + * @param convert 鎸囧畾鐨凧sonConvert + * @param type 鎸囧畾鐨勭被鍨 + * @param obj 杈撳嚭瀵硅薄 + */ + public void finishJson(final JsonConvert convert, final Type type, final Object obj) { + this.contentType = this.jsonContentType; + if (this.recycleListener != null) this.output = obj; + if (convert == jsonRootConvert) { + JsonBytesWriter writer = jsonWriter; + convert.convertTo(writer.clear(), type, obj); + finish(false, (String) null, writer.content(), writer.offset(), writer.length(), null, null); + } else { + convert.convertToBytes(type, obj, convertHandler); + } + } + + /** + * 灏嗗璞′互JSON鏍煎紡杈撳嚭 + * + * @param objs 杈撳嚭瀵硅薄 + */ +// @Deprecated //@since 2.3.0 +// void finishJson(final Object... objs) { +// this.contentType = this.jsonContentType; +// if (this.recycleListener != null) this.output = objs; +// request.getRespConvert().convertToBytes(objs, convertHandler); +// } + /** + * 灏哛etResult瀵硅薄浠SON鏍煎紡杈撳嚭 + * + * @param type 鎸囧畾鐨凴etResult娉涘瀷绫诲瀷 + * @param ret RetResult杈撳嚭瀵硅薄 + */ + @Deprecated //@since 2.5.0 + public void finishJson(Type type, org.redkale.service.RetResult ret) { + this.contentType = this.jsonContentType; + if (this.retResultHandler != null) { + ret = this.retResultHandler.apply(this.request, ret); + } + if (this.recycleListener != null) this.output = ret; + if (ret != null && !ret.isSuccess()) { + this.header.addValue("retcode", String.valueOf(ret.getRetcode())); + this.header.addValue("retinfo", ret.getRetinfo()); + } + Convert convert = ret == null ? null : ret.convert(); + if (convert == null) convert = request.getRespConvert(); + if (convert == jsonRootConvert) { + JsonBytesWriter writer = jsonWriter; + convert.convertTo(writer.clear(), type, ret); + finish(false, (String) null, writer.content(), writer.offset(), writer.length(), null, null); + } else { + convert.convertToBytes(type, ret, convertHandler); + } + } + + /** + * 灏哛etResult瀵硅薄浠SON鏍煎紡杈撳嚭 + * + * @param convert 鎸囧畾鐨凧sonConvert + * @param type 鎸囧畾鐨凴etResult娉涘瀷绫诲瀷 + * @param ret RetResult杈撳嚭瀵硅薄 + */ + @Deprecated //@since 2.5.0 + public void finishJson(final JsonConvert convert, Type type, org.redkale.service.RetResult ret) { + this.contentType = this.jsonContentType; + if (this.retResultHandler != null) { + ret = this.retResultHandler.apply(this.request, ret); + } + if (this.recycleListener != null) this.output = ret; + if (ret != null && !ret.isSuccess()) { + this.header.addValue("retcode", String.valueOf(ret.getRetcode())); + this.header.addValue("retinfo", ret.getRetinfo()); + } + if (convert == jsonRootConvert) { + JsonBytesWriter writer = jsonWriter; + convert.convertTo(writer.clear(), type, ret); + finish(false, (String) null, writer.content(), writer.offset(), writer.length(), null, null); + } else { + convert.convertToBytes(type, ret, convertHandler); + } + } + + /** + * 灏咰ompletableFuture鐨勭粨鏋滃璞′互JSON鏍煎紡杈撳嚭 + * + * @param convert 鎸囧畾鐨凧sonConvert + * @param valueType 鎸囧畾CompletableFuture.value鐨勬硾鍨嬬被鍨 + * @param future 杈撳嚭瀵硅薄鐨勫彞鏌 + */ + @Deprecated //@since 2.5.0 + @SuppressWarnings("unchecked") + public void finishJson(final JsonConvert convert, final Type valueType, final CompletableFuture future) { + finish(convert, valueType, future); + } + + /** + * 灏哛etResult瀵硅薄杈撳嚭 + * + * @param type 鎸囧畾鐨凴etResult娉涘瀷绫诲瀷 + * @param ret RetResult杈撳嚭瀵硅薄 + */ + @SuppressWarnings("null") + public void finish(Type type, org.redkale.service.RetResult ret) { + if (this.retResultHandler != null) { + ret = this.retResultHandler.apply(this.request, ret); + } + if (this.recycleListener != null) this.output = ret; + if (ret != null && !ret.isSuccess()) { + this.header.addValue("retcode", String.valueOf(ret.getRetcode())); + this.header.addValue("retinfo", ret.getRetinfo()); + } + Convert cc = ret == null ? null : ret.convert(); + if (cc == null) cc = request.getRespConvert(); + if (cc instanceof JsonConvert) { + this.contentType = this.jsonContentType; + } else if (cc instanceof TextConvert) { + this.contentType = this.plainContentType; + } + if (cc == jsonRootConvert) { + JsonBytesWriter writer = jsonWriter; + cc.convertTo(writer.clear(), type, ret); + finish(false, (String) null, writer.content(), writer.offset(), writer.length(), null, null); + } else { + cc.convertToBytes(type, ret, convertHandler); + } + } + + /** + * 灏哛etResult瀵硅薄杈撳嚭 + * + * @param convert 鎸囧畾鐨凜onvert + * @param type 鎸囧畾鐨凴etResult娉涘瀷绫诲瀷 + * @param ret RetResult杈撳嚭瀵硅薄 + */ + @SuppressWarnings("null") + public void finish(final Convert convert, Type type, org.redkale.service.RetResult ret) { + if (this.retResultHandler != null) { + ret = this.retResultHandler.apply(this.request, ret); + } + if (this.recycleListener != null) this.output = ret; + if (ret != null && !ret.isSuccess()) { + this.header.addValue("retcode", String.valueOf(ret.getRetcode())); + this.header.addValue("retinfo", ret.getRetinfo()); + } + Convert cc = convert; + if (cc == null && ret != null) cc = ret.convert(); + if (cc == null) cc = request.getRespConvert(); + if (cc instanceof JsonConvert) { + this.contentType = this.jsonContentType; + } else if (cc instanceof TextConvert) { + this.contentType = this.plainContentType; + } + if (cc == jsonRootConvert) { + JsonBytesWriter writer = jsonWriter; + cc.convertTo(writer.clear(), type, ret); + finish(false, (String) null, writer.content(), writer.offset(), writer.length(), null, null); + } else { + cc.convertToBytes(type, ret, convertHandler); + } + } + + /** + * 灏咹ttpResult瀵硅薄杈撳嚭 + * + * @param resultType HttpResult.result鐨勬硾鍨嬬被鍨 + * @param result HttpResult杈撳嚭瀵硅薄 + */ + public void finish(Type resultType, HttpResult result) { + finish(request.getRespConvert(), resultType, result); + } + + /** + * 灏咹ttpResult瀵硅薄杈撳嚭 + * + * @param convert 鎸囧畾鐨凜onvert + * @param resultType HttpResult.result鐨勬硾鍨嬬被鍨 + * @param result HttpResult杈撳嚭瀵硅薄 + */ + public void finish(final Convert convert, Type resultType, HttpResult result) { + if (result.getContentType() != null) setContentType(result.getContentType()); + addHeader(result.getHeaders()).addCookie(result.getCookies()).setStatus(result.getStatus() < 1 ? 200 : result.getStatus()); + Object val = result.getResult(); + if (val == null) { + finish(""); + } else if (val instanceof CharSequence) { + finish(val.toString()); + } else { + Convert cc = result.convert(); + if (cc == null) cc = convert; + finish(cc, resultType, val); + } + } + + /** + * 灏咰ompletionStage瀵硅薄杈撳嚭 + * + * @param valueType CompletionFuture.value鐨勬硾鍨嬬被鍨 + * @param future CompletionStage杈撳嚭瀵硅薄 + */ + public void finish(Type valueType, CompletionStage future) { + finish(request.getRespConvert(), valueType, future); + } + + /** + * 灏咰ompletionStage瀵硅薄杈撳嚭 + * + * @param convert 鎸囧畾鐨凜onvert + * @param valueType CompletionFuture.value鐨勬硾鍨嬬被鍨 + * @param future CompletionStage杈撳嚭瀵硅薄 + */ + public void finish(final Convert convert, Type valueType, CompletionStage future) { + future.whenComplete((v, e) -> { + if (e != null) { + context.getLogger().log(Level.WARNING, "Servlet occur, force to close channel. request = " + request + ", result is CompletionStage", (Throwable) e); + if (e instanceof TimeoutException) { + finish504(); + } else { + finish500(); + } + return; + } + finish(convert, valueType, v); + }); + } + + /** + * 灏咶low.Publisher瀵硅薄杈撳嚭 + * + * @param 娉涘瀷 + * @param valueType Publisher鐨勬硾鍨嬬被鍨 + * @param publisher Publisher杈撳嚭瀵硅薄 + */ + public void finishPublisher(Type valueType, Flow.Publisher publisher) { + finishPublisher(request.getRespConvert(), valueType, publisher); + } + + /** + * 灏咶low.Publisher瀵硅薄杈撳嚭 + * + * @param 娉涘瀷 + * @param convert 鎸囧畾鐨凜onvert + * @param valueType Publisher鐨勬硾鍨嬬被鍨 + * @param publisher Publisher杈撳嚭瀵硅薄 + */ + public void finishPublisher(final Convert convert, Type valueType, Flow.Publisher publisher) { + finish(convert, valueType, (CompletionStage) Flows.createMonoFuture(publisher)); + } + + /** + * 灏嗙涓夋柟绫籉low.Publisher瀵硅薄(濡: Mono/Flux)杈撳嚭 + * + * @param valueType Publisher鐨勬硾鍨嬬被鍨 + * @param publisher Publisher杈撳嚭瀵硅薄 + */ + public void finishPublisher(Type valueType, Object publisher) { + finishPublisher(request.getRespConvert(), valueType, publisher); + } + + /** + * 灏嗙涓夋柟绫籉low.Publisher瀵硅薄(濡: Mono/Flux)杈撳嚭 + * + * @param convert 鎸囧畾鐨凜onvert + * @param valueType Publisher鐨勬硾鍨嬬被鍨 + * @param publisher Publisher杈撳嚭瀵硅薄 + */ + public void finishPublisher(final Convert convert, Type valueType, Object publisher) { + finish(convert, valueType, (CompletionStage) Flows.maybePublisherToFuture(publisher)); + } + + /** + * 灏咹ttpScope瀵硅薄杈撳嚭 + * + * @param result HttpScope杈撳嚭瀵硅薄 + */ + public void finish(HttpScope result) { + finish(request.getRespConvert(), result); + } + + /** + * 灏咹ttpScope瀵硅薄杈撳嚭 + * + * @param convert 鎸囧畾鐨凜onvert + * @param result HttpScope杈撳嚭瀵硅薄 + */ + public void finish(final Convert convert, HttpScope result) { + if (result == null) { + finish("null"); + return; + } + if (httpRender != null) { + setContentType(contentTypeHtmlUTF8); + if (result.getHeaders() != null) addHeader(result.getHeaders()); + if (result.getCookies() != null) addCookie(result.getCookies()); + httpRender.renderTo(this.request, this, convert, result); + return; + } + finish(""); + } + + /** + * 灏嗙粨鏋滃璞¤緭鍑 + * + * @param obj 杈撳嚭瀵硅薄 + */ + @SuppressWarnings("unchecked") + public void finish(final Object obj) { + finish(request.getRespConvert(), (Type) null, obj); + } + + /** + * 灏嗙粨鏋滃璞¤緭鍑 + * + * @param convert 鎸囧畾鐨凜onvert + * @param obj 杈撳嚭瀵硅薄 + */ + @SuppressWarnings("unchecked") + public void finish(final Convert convert, final Object obj) { + finish(convert, (Type) null, obj); + } + + /** + * 灏嗙粨鏋滃璞¤緭鍑 + * + * @param type 鎸囧畾鐨勭被鍨, 涓嶄竴瀹氭槸obj鐨勬暟鎹被鍨嬶紝蹇呯劧obj涓篊ompletableFuture锛 type搴旇涓篎uture鐨勫厓绱犵被鍨 + * @param obj 杈撳嚭瀵硅薄 + */ + @SuppressWarnings("unchecked") + public void finish(final Type type, Object obj) { + finish((Convert) null, type, obj); + } + + /** + * 灏嗙粨鏋滃璞¤緭鍑 + * + * @param convert 鎸囧畾鐨凜onvert + * @param type 鎸囧畾鐨勭被鍨, 涓嶄竴瀹氭槸obj鐨勬暟鎹被鍨嬶紝蹇呯劧obj涓篊ompletionStage锛 type搴旇涓篎uture鐨勫厓绱犵被鍨 + * @param obj 杈撳嚭瀵硅薄 + */ + @SuppressWarnings({"unchecked", "null"}) + public void finish(final Convert convert, final Type type, Object obj) { + Object val = obj; + //浠ヤ笅if鏉′欢浼氳Rest绫荤2440琛屽乏鍙崇殑鍦版柟鐢ㄥ埌 + if (val == null) { + Convert cc = convert; + if (cc == null) cc = request.getRespConvert(); + if (cc instanceof JsonConvert) { + this.contentType = this.jsonContentType; + } else if (cc instanceof TextConvert) { + this.contentType = this.plainContentType; + } + finish("null"); + } else if (val instanceof CompletionStage) { + finish(convert, val == obj ? type : null, (CompletionStage) val); + } else if (val instanceof CharSequence) { + finish((String) val.toString()); + } else if (val instanceof byte[]) { + finish((byte[]) val); + } else if (val instanceof File) { + try { + finish((File) val); + } catch (IOException e) { + context.getLogger().log(Level.WARNING, "HttpServlet finish File occur, force to close channel. request = " + getRequest(), e); + finish(500, null); + } + } else if (val instanceof org.redkale.service.RetResult) { + finish(convert, type, (org.redkale.service.RetResult) val); + } else if (val instanceof HttpResult) { + finish(convert, type, (HttpResult) val); + } else if (val instanceof HttpScope) { + finish(convert, (HttpScope) val); + } else { + Convert cc = convert; + if (cc == null) cc = request.getRespConvert(); + if (cc instanceof JsonConvert) { + this.contentType = this.jsonContentType; + } else if (cc instanceof TextConvert) { + this.contentType = this.plainContentType; + } + if (this.recycleListener != null) this.output = val; + //this.channel == null涓鸿櫄鎷熺殑HttpResponse + if (type == null) { + if (cc == jsonRootConvert) { + JsonBytesWriter writer = jsonWriter; + cc.convertTo(writer.clear(), val); + finish(false, (String) null, writer.content(), writer.offset(), writer.length(), null, null); + } else { + cc.convertToBytes(val, convertHandler); + } + } else { + if (cc == jsonRootConvert) { + JsonBytesWriter writer = jsonWriter; + cc.convertTo(writer.clear(), type, val); + finish(false, (String) null, writer.content(), writer.offset(), writer.length(), null, null); + } else { + cc.convertToBytes(type, val, convertHandler); + } + } + } + } + + /** + * 灏嗘寚瀹氬瓧绗︿覆浠ュ搷搴旂粨鏋滆緭鍑 + * + * @param obj 杈撳嚭鍐呭 + */ + public void finish(String obj) { + finish(200, obj); + } + + /** + * 浠ユ寚瀹氬搷搴旂爜闄勫甫鍐呭杈撳嚭 + * + * @param status 鍝嶅簲鐮 + * @param message 杈撳嚭鍐呭 + */ + public void finish(int status, String message) { + if (isClosed()) return; + this.status = status; + //if (status != 200) super.refuseAlive(); + final byte[] val = message == null ? HttpRequest.EMPTY_BYTES : (context.getCharset() == null ? Utility.encodeUTF8(message) : message.getBytes(context.getCharset())); + finish(false, null, val, 0, val.length, null, null); + } + + @Override + public void finish(boolean kill, final byte[] bs, int offset, int length) { + finish(false, null, bs, offset, length, null, null); + } + + public
void finish(final byte[] bs, int offset, int length, Consumer callback, A attachment) { + finish(false, null, bs, offset, length, callback, attachment); + } + + /** + * 灏嗘寚瀹歜yte[]鎸夊搷搴旂粨鏋滆緭鍑 + * + * @param contentType ContentType + * @param bs 杈撳嚭鍐呭 + */ + public void finish(final String contentType, final byte[] bs) { + finish(false, contentType, bs, 0, bs == null ? 0 : bs.length, null, null); + } + + /** + * 灏咮yteTuple鎸夊搷搴旂粨鏋滆緭鍑 + * + * @param contentType ContentType + * @param array 杈撳嚭鍐呭 + */ + public void finish(final String contentType, final ByteTuple array) { + finish(false, contentType, array.content(), array.offset(), array.length(), null, null); + } + + /** + * 灏嗘寚瀹歜yte[]鎸夊搷搴旂粨鏋滆緭鍑 + * + * @param kill kill + * @param contentType ContentType + * @param bs 杈撳嚭鍐呭 + * @param offset 鍋忕Щ閲 + * @param length 闀垮害 + */ + protected void finish(boolean kill, final String contentType, final byte[] bs, int offset, int length) { + finish(kill, contentType, bs, offset, length, null, null); + } + + /** + * 灏嗘寚瀹歜yte[]鎸夊搷搴旂粨鏋滆緭鍑 + * + * @param kill kill + * @param contentType ContentType + * @param bs 杈撳嚭鍐呭 + * @param offset 鍋忕Щ閲 + * @param length 闀垮害 + * @param callback Consumer + * @param attachment ConvertWriter + * @param A + */ + protected void finish(boolean kill, final String contentType, final byte[] bs, int offset, int length, Consumer callback, A attachment) { + if (isClosed()) return; //閬垮厤閲嶅鍏抽棴 + if (this.headWritedSize < 0) { + if (contentType != null) this.contentType = contentType; + this.contentLength = length; + createHeader(); + } + ByteArray data = headerArray; + data.put(bs, offset, length); + if (callback != null) callback.accept(attachment); + if (cacheHandler != null) cacheHandler.accept(this, data.getBytes()); + + int pipelineIndex = request.getPipelineIndex(); + if (pipelineIndex > 0) { + boolean over = this.channel.writePipelineData(pipelineIndex, request.getPipelineCount(), data); + if (over) { + request.setPipelineOver(true); + this.channel.flushPipelineData(this.pipelineWriteHandler); + } else { + removeChannel(); + this.responseConsumer.accept(this); + } + } else { + if (this.channel.hasPipelineData()) { + this.channel.writePipelineData(pipelineIndex, request.getPipelineCount(), data); + this.channel.flushPipelineData(this.pipelineWriteHandler); + } else { + //涓嶈兘鐢╢inish(boolean kill, final ByteTuple array) 鍚﹀垯浼氳皟this.finish + super.finish(false, data.content(), 0, data.length()); + } + } + +// ByteArray data = headerArray; +// int pipelineIndex = request.getPipelineIndex(); +// if (pipelineIndex > 0) { +// boolean over = this.channel.writePipelineData(pipelineIndex, request.getPipelineCount(), data.content(), 0, data.length(), bs, offset, length); +// if (callback != null) callback.accept(attachment); +// if (cacheHandler != null) cacheHandler.accept(this, Utility.append(data.getBytes(), bs, offset, length)); +// +// if (over) { +// request.setPipelineOver(true); +// this.channel.flushPipelineData(this.pipelineWriteHandler); +// } else { +// removeChannel(); +// this.responseConsumer.accept(this); +// } +// } else { +// if (this.channel.hasPipelineData()) { +// this.channel.writePipelineData(pipelineIndex, request.getPipelineCount(), data.content(), 0, data.length(), bs, offset, length); +// if (callback != null) callback.accept(attachment); +// if (cacheHandler != null) cacheHandler.accept(this, Utility.append(data.getBytes(), bs, offset, length)); +// this.channel.flushPipelineData(this.pipelineWriteHandler); +// } else { +// //涓嶈兘鐢╢inish(boolean kill, final ByteTuple array) 鍚﹀垯浼氳皟this.finish +// super.finish(false, data.content(), 0, data.length(), bs, offset, length, callback, attachment); +// } +// } + } + + /** + * 浠304鐘舵佺爜杈撳嚭 + */ + public void finish304() { + skipHeader(); + super.finish(false, bytes304); + } + + /** + * 浠404鐘舵佺爜杈撳嚭 + */ + public void finish404() { + skipHeader(); + super.finish(false, bytes404); + } + + /** + * 浠500鐘舵佺爜杈撳嚭 + */ + public void finish500() { + skipHeader(); + super.finish(false, bytes500); + } + + /** + * 浠504鐘舵佺爜杈撳嚭 + */ + public void finish504() { + skipHeader(); + super.finish(false, bytes504); + } + + //Header澶у皬 + protected void createHeader() { + if (this.status == 200 && !this.respHeadContainsConnection && !this.request.isWebSocket() + && (this.contentType == null || this.contentType == this.jsonContentType || this.contentType == this.plainContentType) + && (this.contentLength >= 0 && this.contentLength < jsonLiveContentLengthArray.length)) { + byte[][] lengthArray = this.plainLiveContentLengthArray; + if (this.request.isKeepAlive()) { + if (this.contentType == this.jsonContentType) { + lengthArray = this.jsonLiveContentLengthArray; + } + } else { + if (this.contentType == this.jsonContentType) { + lengthArray = this.jsonCloseContentLengthArray; + } else { + lengthArray = this.plainCloseContentLengthArray; + } + } + headerArray.put(lengthArray[(int) this.contentLength]); + } else { + if (this.status == 200 && !this.respHeadContainsConnection && !this.request.isWebSocket()) { + if (this.request.isKeepAlive()) { + headerArray.put(status200_server_live_Bytes); + } else { + headerArray.put(status200_server_close_Bytes); + } + } else { + if (this.status == 200) { + headerArray.put(status200Bytes); + } else { + headerArray.put(("HTTP/1.1 " + this.status + " " + httpCodes.get(this.status) + "\r\n").getBytes()); + } + headerArray.put(serverNameBytes); + if (!this.respHeadContainsConnection) { + byte[] bs = this.request.isKeepAlive() ? connectAliveBytes : connectCloseBytes; + if (bs.length > 0) headerArray.put(bs); + } + } + if (!this.request.isWebSocket()) { + if (this.contentType == this.jsonContentType) { + headerArray.put(this.jsonContentTypeBytes); + } else if (this.contentType == null || this.contentType == this.plainContentType) { + headerArray.put(this.plainContentTypeBytes); + } else { + headerArray.put(("Content-Type: " + this.contentType + "\r\n").getBytes()); + } + } + if (this.contentLength >= 0) { + if (this.contentLength < contentLengthArray.length) { + headerArray.put(contentLengthArray[(int) this.contentLength]); + } else { + headerArray.put(("Content-Length: " + this.contentLength + "\r\n").getBytes()); + } + } + } + if (dateSupplier != null) headerArray.put(dateSupplier.get()); + + if (this.defaultAddHeaders != null) { + for (String[] headers : this.defaultAddHeaders) { + if (headers.length > 3) { + String v = request.getParameter(headers[2]); + if (v != null) this.header.addValue(headers[0], v); + } else if (headers.length > 2) { + String v = request.getHeader(headers[2]); + if (v != null) this.header.addValue(headers[0], v); + } else { + this.header.addValue(headers[0], headers[1]); + } + } + } + if (this.defaultSetHeaders != null) { + for (String[] headers : this.defaultSetHeaders) { + if (headers.length > 3) { + String v = request.getParameter(headers[2]); + if (v != null) this.header.setValue(headers[0], v); + } else if (headers.length > 2) { + String v = request.getHeader(headers[2]); + if (v != null) this.header.setValue(headers[0], v); + } else { + this.header.setValue(headers[0], headers[1]); + } + } + } + for (Entry en : this.header.getStringEntrys()) { + headerArray.put((en.name + ": " + en.getValue() + "\r\n").getBytes()); + } + if (request.newsessionid != null) { + String domain = defaultCookie == null ? null : defaultCookie.getDomain(); + if (domain == null || domain.isEmpty()) { + domain = ""; + } else { + domain = "Domain=" + domain + "; "; + } + String path = defaultCookie == null ? null : defaultCookie.getPath(); + if (path == null || path.isEmpty()) path = "/"; + if (request.newsessionid.isEmpty()) { + headerArray.put(("Set-Cookie: " + HttpRequest.SESSIONID_NAME + "=; " + domain + "Path=/; Max-Age=0; HttpOnly\r\n").getBytes()); + } else { + headerArray.put(("Set-Cookie: " + HttpRequest.SESSIONID_NAME + "=" + request.newsessionid + "; " + domain + "Path=/; HttpOnly\r\n").getBytes()); + } + } + if (this.cookies != null) { + for (HttpCookie cookie : this.cookies) { + if (cookie == null) continue; + if (defaultCookie != null) { + if (defaultCookie.getDomain() != null && cookie.getDomain() == null) cookie.setDomain(defaultCookie.getDomain()); + if (defaultCookie.getPath() != null && cookie.getPath() == null) cookie.setPath(defaultCookie.getPath()); + } + headerArray.put(("Set-Cookie: " + cookieString(cookie) + "\r\n").getBytes()); + } + } + headerArray.put(LINE); + this.headWritedSize = headerArray.length(); + } + + private CharSequence cookieString(HttpCookie cookie) { + StringBuilder sb = new StringBuilder(); + sb.append(cookie.getName()).append("=").append(cookie.getValue()).append("; Version=1"); + if (cookie.getDomain() != null) sb.append("; Domain=").append(cookie.getDomain()); + if (cookie.getPath() != null) sb.append("; Path=").append(cookie.getPath()); + if (cookie.getPortlist() != null) sb.append("; Port=").append(cookie.getPortlist()); + if (cookie.getMaxAge() > 0) { + sb.append("; Max-Age=").append(cookie.getMaxAge()); + sb.append("; Expires=").append(RFC_1123_DATE_TIME.format(java.time.ZonedDateTime.now(ZONE_GMT).plusSeconds(cookie.getMaxAge()))); + } + if (cookie.getSecure()) sb.append("; Secure"); + if (cookie.isHttpOnly()) sb.append("; HttpOnly"); + return sb; + } + + /** + * 寮傛杈撳嚭鎸囧畾鍐呭 + * + * @param 娉涘瀷 + * @param buffer 杈撳嚭鍐呭 + * @param handler 寮傛鍥炶皟鍑芥暟 + */ + protected void sendBody(ByteBuffer buffer, CompletionHandler handler) { + if (this.headWritedSize < 0) { + if (this.contentLength < 0) this.contentLength = buffer == null ? 0 : buffer.remaining(); + createHeader(); + if (buffer == null) { + super.send(headerArray, handler); + } else { + ByteBuffer headbuf = channel.pollWriteBuffer(); + headbuf.put(headerArray.content(), 0, headerArray.length()); + headbuf.flip(); + super.send(new ByteBuffer[]{headbuf, buffer}, null, handler); + } + } else { + super.send(buffer, null, handler); + } + } + + /** + * 灏嗘寚瀹氭枃浠舵寜鍝嶅簲缁撴灉杈撳嚭 + * + * @param file 杈撳嚭鏂囦欢 + * + * @throws IOException IO寮傚父 + */ + public void finish(File file) throws IOException { + finishFile(null, file, null); + } + + /** + * 灏嗘枃浠舵寜鎸囧畾鏂囦欢鍚嶈緭鍑 + * + * @param filename 杈撳嚭鏂囦欢鍚 + * @param file 杈撳嚭鏂囦欢 + * + * @throws IOException IO寮傚父 + */ + public void finish(final String filename, File file) throws IOException { + finishFile(filename, file, null); + } + + /** + * 灏嗘寚瀹氭枃浠跺彞鏌勬垨鏂囦欢鍐呭鎸夊搷搴旂粨鏋滆緭鍑猴紝鑻ileBody涓嶄负null鍒欏彧杈撳嚭fileBody鍐呭 + * + * @param file 杈撳嚭鏂囦欢 + * @param fileBody 鏂囦欢鍐呭锛 娌℃湁鍒欒緭鍑篺ile + * + * @throws IOException IO寮傚父 + */ + protected void finishFile(final File file, ByteArray fileBody) throws IOException { + finishFile(null, file, fileBody); + } + + /** + * 灏嗘寚瀹氭枃浠跺彞鏌勬垨鏂囦欢鍐呭鎸夋寚瀹氭枃浠跺悕杈撳嚭锛岃嫢fileBody涓嶄负null鍒欏彧杈撳嚭fileBody鍐呭 + * file 涓 fileBody 涓嶈兘鍚屾椂涓虹┖ + * file 涓 filename 涔熶笉鑳藉悓鏃朵负绌 + * + * @param filename 杈撳嚭鏂囦欢鍚 + * @param file 杈撳嚭鏂囦欢 + * @param fileBody 鏂囦欢鍐呭锛 娌℃湁鍒欒緭鍑篺ile + * + * @throws IOException IO寮傚父 + */ + protected void finishFile(final String filename, final File file, ByteArray fileBody) throws IOException { + if ((file == null || !file.isFile() || !file.canRead()) && fileBody == null) { + finish404(); + return; + } + final long length = file == null ? fileBody.length() : file.length(); + final String match = request.getHeader("If-None-Match"); + final String etag = (file == null ? 0L : file.lastModified()) + "-" + length; + if (match != null && etag.equals(match)) { + //finish304(); + //return; + } + this.contentLength = length; + if (filename != null && !filename.isEmpty() && file != null) { + if (this.header.getValue("Content-Disposition") == null) { + addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8")); + } + } + this.contentType = MimeType.getByFilename(filename == null || filename.isEmpty() ? file.getName() : filename); + if (this.contentType == null) this.contentType = "application/octet-stream"; + String range = request.getHeader("Range"); + if (range != null && (!range.startsWith("bytes=") || range.indexOf(',') >= 0)) range = null; + long start = -1; + long len = -1; + if (range != null) { + range = range.substring("bytes=".length()); + int pos = range.indexOf('-'); + start = pos == 0 ? 0 : Integer.parseInt(range.substring(0, pos)); + long end = (pos == range.length() - 1) ? -1 : Long.parseLong(range.substring(pos + 1)); + long clen = end > 0 ? (end - start + 1) : (length - start); + this.status = 206; + addHeader("Accept-Ranges", "bytes"); + addHeader("Content-Range", "bytes " + start + "-" + (end > 0 ? end : length - 1) + "/" + length); + this.contentLength = clen; + len = end > 0 ? clen : end; + } + this.addHeader("ETag", etag); + createHeader(); + ByteArray data = headerArray; + if (fileBody == null) { + if (this.recycleListener != null) this.output = file; + finishFile(data, file, start, len); + } else { //涓鑸琀ttpResourceServlet缂撳瓨file鍐呭鏃秄ileBody涓嶄负绌 + if (start >= 0) data.put(fileBody, (int) start, (int) ((len > 0) ? len : fileBody.length() - start)); + super.finish(false, data.content(), 0, data.length()); + } + } + + //offset銆乴ength 涓 -1 琛ㄧず杈撳嚭鏁翠釜鏂囦欢 + private void finishFile(ByteArray headerData, File file, long offset, long length) throws IOException { + //this.channel.write(headerData, new TransferFileHandler(file, offset, length)); + final Logger logger = context.getLogger(); + this.channel.write(headerData, new CompletionHandler() { + + FileChannel fileChannel; + + long limit; + + long sends; + + ByteBuffer buffer; + + @Override + public void completed(Integer result, Void attachment) { + try { + if (fileChannel != null && sends >= limit) { + if (buffer != null) channel.offerBuffer(buffer); + try { + fileChannel.close(); + } catch (IOException ie) { + } + finish(); + return; + } + if (fileChannel == null) { + fileChannel = FileChannel.open(file.toPath(), StandardOpenOption.READ); + if (offset > 0) fileChannel = fileChannel.position(offset); + limit = length > 0 ? length : (file.length() - (offset > 0 ? offset : 0)); + sends = 0; + buffer = channel.ssl() ? channel.pollWriteSSLBuffer() : channel.pollWriteBuffer(); + } + + buffer.clear(); + int len = fileChannel.read(buffer); + if (len < 1) throw new IOException("read " + file + " error: " + len); + buffer.flip(); + if (sends + len > limit) { + buffer.limit((int) (len - limit + sends)); + sends = limit; + } else { + sends += len; + } + channel.write(buffer, attachment, this); + } catch (Exception e) { + if (fileChannel != null) { + try { + fileChannel.close(); + } catch (IOException ie) { + } + } + failed(e, attachment); + } + } + + @Override + public void failed(Throwable exc, Void attachment) { + if (buffer != null) channel.offerBuffer(buffer); + if (logger.isLoggable(Level.FINER)) logger.log(Level.FINER, "finishFile error", exc); + finish(true); + } + }); + } + + /** + * 璺宠繃header鐨勮緭鍑 + * 閫氬父搴旂敤鍦烘櫙鏄紝璋冪敤鑰呯殑杈撳嚭鍐呭閲屽凡缁忓寘鍚簡HTTP鐨勫搷搴斿ご淇℃伅锛屽洜姝ら渶瑕佽皟鐢ㄦ鏂规硶閬垮厤閲嶅杈撳嚭HTTP鍝嶅簲澶翠俊鎭 + * + * @return HttpResponse + */ + public HttpResponse skipHeader() { + this.headWritedSize = 0; + return this; + } + + protected DefaultAnyValue duplicateHeader() { + return this.header.duplicate(); + } + + /** + * 璁剧疆Header鍊 + * + * @param name header鍚 + * @param value header鍊 + * + * @return HttpResponse + */ + public HttpResponse setHeader(String name, Object value) { + this.header.setValue(name, String.valueOf(value)); + if ("Connection".equalsIgnoreCase(name)) this.respHeadContainsConnection = true; + return this; + } + + /** + * 娣诲姞Header鍊 + * + * @param name header鍚 + * @param value header鍊 + * + * @return HttpResponse + */ + public HttpResponse addHeader(String name, Object value) { + this.header.addValue(name, String.valueOf(value)); + if ("Connection".equalsIgnoreCase(name)) this.respHeadContainsConnection = true; + return this; + } + + /** + * 娣诲姞Header鍊 + * + * @param map header鍊 + * + * @return HttpResponse + */ + public HttpResponse addHeader(Map map) { + if (map == null || map.isEmpty()) return this; + for (Map.Entry en : map.entrySet()) { + this.header.addValue(en.getKey(), String.valueOf(en.getValue())); + if (!respHeadContainsConnection && "Connection".equalsIgnoreCase(en.getKey())) { + this.respHeadContainsConnection = true; + } + } + return this; + } + + /** + * 璁剧疆鐘舵佺爜 + * + * @param status 鐘舵佺爜 + * + * @return HttpResponse + */ + public HttpResponse setStatus(int status) { + this.status = status; + return this; + } + + /** + * 鑾峰彇鐘舵佺爜 + * + * @return 鐘舵佺爜 + */ + public int getStatus() { + return this.status; + } + + /** + * 鑾峰彇 ContentType + * + * @return ContentType + */ + public String getContentType() { + return contentType; + } + + /** + * 璁剧疆 ContentType + * + * @param contentType ContentType + * + * @return HttpResponse + */ + public HttpResponse setContentType(String contentType) { + this.contentType = contentType; + return this; + } + + /** + * 鑾峰彇鍐呭闀垮害 + * + * @return 鍐呭闀垮害 + */ + public long getContentLength() { + return contentLength; + } + + /** + * 璁剧疆鍐呭闀垮害 + * + * @param contentLength 鍐呭闀垮害 + * + * @return HttpResponse + */ + public HttpResponse setContentLength(long contentLength) { + this.contentLength = contentLength; + return this; + } + + /** + * 鑾峰彇杈撳嚭鏃剁殑鎷︽埅鍣 + * + * @return 鎷︽埅鍣 + */ + protected BiConsumer getCacheHandler() { + return cacheHandler; + } + + /** + * 璁剧疆杈撳嚭鏃剁殑鎷︽埅鍣 + * + * @param cacheHandler 鎷︽埅鍣 + */ + protected void setCacheHandler(BiConsumer cacheHandler) { + this.cacheHandler = cacheHandler; + } + + /** + * 鑾峰彇杈撳嚭RetResult鏃剁殑鎷︽埅鍣 + * + * @return 鎷︽埅鍣 + */ + protected BiFunction getRetResultHandler() { + return retResultHandler; + } + + /** + * 璁剧疆杈撳嚭RetResult鏃剁殑鎷︽埅鍣 + * + * @param retResultHandler 鎷︽埅鍣 + */ + public void retResultHandler(BiFunction retResultHandler) { + this.retResultHandler = retResultHandler; + } + +// protected final class TransferFileHandler implements CompletionHandler { +// +// private final File file; +// +// private final AsynchronousFileChannel filechannel; +// +// private final long max; //闇瑕佽鍙栫殑瀛楄妭鏁帮紝 -1琛ㄧず璇诲埌鏂囦欢缁撳熬 +// +// private long count;//璇诲彇鏂囦欢鐨勫瓧鑺傛暟 +// +// private long readpos = 0; +// +// private boolean hdwrite = true; //鍐欏叆Header +// +// private boolean read = false; +// +// public TransferFileHandler(File file) throws IOException { +// this.file = file; +// this.filechannel = AsynchronousFileChannel.open(file.toPath(), options); +// this.readpos = 0; +// this.max = file.length(); +// } +// +// public TransferFileHandler(File file, long offset, long len) throws IOException { +// this.file = file; +// this.filechannel = AsynchronousFileChannel.open(file.toPath(), options); +// this.readpos = offset <= 0 ? 0 : offset; +// this.max = len <= 0 ? file.length() : len; +// } +// +// @Override +// public void completed(Integer result, Void attachment) { +// //(Utility.now() + "---" + Thread.currentThread().getName() + "-----------" + file + "-------------------result: " + result + ", max = " + max + ", readpos = " + readpos + ", count = " + count + ", " + (hdwrite ? "姝e湪鍐橦eader" : (read ? "鍑嗗璇" : "鍑嗗鍐"))); +// if (result < 0 || count >= max) { +// failed(null, attachment); +// return; +// } +// if (hdwrite && attachment.hasRemaining()) { //Header杩樻病鍐欏畬 +// channel.write(attachment, attachment, this); +// return; +// } +// if (hdwrite) { +// //(Utility.now() + "---" + Thread.currentThread().getName() + "-----------" + file + "-------------------Header鍐欏叆瀹屾瘯锛 鍑嗗璇诲彇鏂囦欢."); +// hdwrite = false; +// read = true; +// result = 0; +// } +// if (read) { +// count += result; +// } else { +// readpos += result; +// } +// if (read && attachment.hasRemaining()) { //Buffer杩樻病鍐欏畬 +// channel.write(attachment, attachment, this); +// return; +// } +// +// if (read) { +// read = false; +// attachment.clear(); +// filechannel.read(attachment, readpos, attachment, this); +// } else { +// read = true; +// if (count > max) { +// attachment.limit((int) (attachment.position() + max - count)); +// } +// attachment.flip(); +// if (attachment.hasRemaining()) { +// channel.write(attachment, attachment, this); +// } else { +// failed(null, attachment); +// } +// } +// } +// +// @Override +// public void failed(Throwable exc, Void attachment) { +// finish(true); +// try { +// filechannel.close(); +// } catch (IOException e) { +// } +// } +// +// } + public static class HttpResponseConfig { + + public String plainContentType; + + public String jsonContentType; + + public byte[] plainContentTypeBytes; + + public byte[] jsonContentTypeBytes; + + public String[][] defaultAddHeaders; + + public String[][] defaultSetHeaders; + + public HttpCookie defaultCookie; + + public boolean autoOptions; + + public Supplier dateSupplier; + + public HttpRender httpRender; + + public final byte[][] plainLiveContentLengthArray = new byte[cacheMaxContentLength][]; + + public final byte[][] jsonLiveContentLengthArray = new byte[cacheMaxContentLength][]; + + public final byte[][] plainCloseContentLengthArray = new byte[cacheMaxContentLength][]; + + public final byte[][] jsonCloseContentLengthArray = new byte[cacheMaxContentLength][]; + + public HttpResponseConfig init(AnyValue config) { + if (this.plainContentTypeBytes == null) { + String plainct = plainContentType == null || plainContentType.isEmpty() ? "text/plain; charset=utf-8" : plainContentType; + String jsonct = jsonContentType == null || jsonContentType.isEmpty() ? "application/json; charset=utf-8" : jsonContentType; + this.plainContentType = plainct; + this.jsonContentType = jsonct; + this.plainContentTypeBytes = ("Content-Type: " + plainct + "\r\n").getBytes(); + this.jsonContentTypeBytes = ("Content-Type: " + jsonct + "\r\n").getBytes(); + for (int i = 0; i < cacheMaxContentLength; i++) { + byte[] lenbytes = ("Content-Length: " + i + "\r\n").getBytes(); + plainLiveContentLengthArray[i] = append(append(status200_server_live_Bytes, plainContentTypeBytes), lenbytes); + plainCloseContentLengthArray[i] = append(append(status200_server_close_Bytes, plainContentTypeBytes), lenbytes); + jsonLiveContentLengthArray[i] = append(append(status200_server_live_Bytes, jsonContentTypeBytes), lenbytes); + jsonCloseContentLengthArray[i] = append(append(status200_server_close_Bytes, jsonContentTypeBytes), lenbytes); + } + } + return this; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + } +} diff --git a/src/main/java/org/redkale/net/http/HttpResult.java b/src/main/java/org/redkale/net/http/HttpResult.java index 30daf2ce4..9a2a2c973 100644 --- a/src/main/java/org/redkale/net/http/HttpResult.java +++ b/src/main/java/org/redkale/net/http/HttpResult.java @@ -1,177 +1,177 @@ -/* - * 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 java.io.Serializable; -import java.net.HttpCookie; -import java.nio.charset.StandardCharsets; -import java.util.*; -import java.util.concurrent.CompletableFuture; -import org.redkale.convert.*; -import org.redkale.convert.json.JsonConvert; - -/** - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param 缁撴灉瀵硅薄鐨勭被鍨 - */ -public class HttpResult { - - public static final String SESSIONID_COOKIENAME = HttpRequest.SESSIONID_NAME; - - @ConvertColumn(index = 1) - protected int status = 200; //涓嶈缃垯涓 200 - - @ConvertColumn(index = 2) - protected String contentType; - - @ConvertColumn(index = 3) - protected Map headers; - - @ConvertColumn(index = 4) - protected List cookies; - - @ConvertColumn(index = 5) - protected T result; - - protected Convert convert; - - public HttpResult() { - } - - public HttpResult(Convert convert, T result) { - this.convert = convert; - this.result = result; - } - - public HttpResult(T result) { - this.result = result; - } - - public HttpResult(String contentType, T result) { - this.contentType = contentType; - this.result = result; - } - - public HttpResult header(String name, Serializable value) { - if (this.headers == null) this.headers = new HashMap<>(); - this.headers.put(name, String.valueOf(value)); - return this; - } - - public HttpResult cookie(String name, Serializable value) { - return cookie(new HttpCookie(name, String.valueOf(value))); - } - - public HttpResult cookie(String name, Serializable value, boolean httpOnly) { - HttpCookie c = new HttpCookie(name, String.valueOf(value)); - c.setHttpOnly(httpOnly); - return cookie(c); - } - - public HttpResult cookie(HttpCookie cookie) { - if (this.cookies == null) this.cookies = new ArrayList<>(); - this.cookies.add(cookie); - return this; - } - - public HttpResult contentType(String contentType) { - this.contentType = contentType; - return this; - } - - public HttpResult result(T result) { - this.result = result; - return this; - } - - public HttpResult status(int status) { - this.status = status; - return this; - } - - public Convert convert() { - return convert; - } - - public HttpResult convert(Convert convert) { - this.convert = convert; - return this; - } - - public String getHeader(String name) { - return headers == null ? null : headers.get(name); - } - - public String getHeader(String name, String dfvalue) { - return headers == null ? dfvalue : headers.getOrDefault(name, dfvalue); - } - - public CompletableFuture> toFuture() { - return CompletableFuture.completedFuture(this); - } - - public CompletableFuture toAnyFuture() { - return CompletableFuture.completedFuture(this); - } - - public Map getHeaders() { - return headers; - } - - public void setHeaders(Map headers) { - this.headers = headers; - } - - public List getCookies() { - return cookies; - } - - public void setCookies(List cookies) { - this.cookies = cookies; - } - - public String getContentType() { - return contentType; - } - - public void setContentType(String contentType) { - this.contentType = contentType; - } - - public T getResult() { - return result; - } - - public void setResult(T result) { - this.result = result; - } - - public int getStatus() { - return status; - } - - public void setStatus(int status) { - this.status = status; - } - - @Override - public String toString() { - if (this.result instanceof byte[]) { - HttpResult tmp = new HttpResult(); - tmp.contentType = this.contentType; - tmp.cookies = this.cookies; - tmp.headers = this.headers; - tmp.status = this.status; - tmp.result = new String((byte[]) this.result, StandardCharsets.UTF_8); - return JsonConvert.root().convertTo(tmp); - } - return JsonConvert.root().convertTo(this); - } -} +/* + * 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 java.io.Serializable; +import java.net.HttpCookie; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import org.redkale.convert.*; +import org.redkale.convert.json.JsonConvert; + +/** + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param 缁撴灉瀵硅薄鐨勭被鍨 + */ +public class HttpResult { + + public static final String SESSIONID_COOKIENAME = HttpRequest.SESSIONID_NAME; + + @ConvertColumn(index = 1) + protected int status = 200; //涓嶈缃垯涓 200 + + @ConvertColumn(index = 2) + protected String contentType; + + @ConvertColumn(index = 3) + protected Map headers; + + @ConvertColumn(index = 4) + protected List cookies; + + @ConvertColumn(index = 5) + protected T result; + + protected Convert convert; + + public HttpResult() { + } + + public HttpResult(Convert convert, T result) { + this.convert = convert; + this.result = result; + } + + public HttpResult(T result) { + this.result = result; + } + + public HttpResult(String contentType, T result) { + this.contentType = contentType; + this.result = result; + } + + public HttpResult header(String name, Serializable value) { + if (this.headers == null) this.headers = new HashMap<>(); + this.headers.put(name, String.valueOf(value)); + return this; + } + + public HttpResult cookie(String name, Serializable value) { + return cookie(new HttpCookie(name, String.valueOf(value))); + } + + public HttpResult cookie(String name, Serializable value, boolean httpOnly) { + HttpCookie c = new HttpCookie(name, String.valueOf(value)); + c.setHttpOnly(httpOnly); + return cookie(c); + } + + public HttpResult cookie(HttpCookie cookie) { + if (this.cookies == null) this.cookies = new ArrayList<>(); + this.cookies.add(cookie); + return this; + } + + public HttpResult contentType(String contentType) { + this.contentType = contentType; + return this; + } + + public HttpResult result(T result) { + this.result = result; + return this; + } + + public HttpResult status(int status) { + this.status = status; + return this; + } + + public Convert convert() { + return convert; + } + + public HttpResult convert(Convert convert) { + this.convert = convert; + return this; + } + + public String getHeader(String name) { + return headers == null ? null : headers.get(name); + } + + public String getHeader(String name, String dfvalue) { + return headers == null ? dfvalue : headers.getOrDefault(name, dfvalue); + } + + public CompletableFuture> toFuture() { + return CompletableFuture.completedFuture(this); + } + + public CompletableFuture toAnyFuture() { + return CompletableFuture.completedFuture(this); + } + + public Map getHeaders() { + return headers; + } + + public void setHeaders(Map headers) { + this.headers = headers; + } + + public List getCookies() { + return cookies; + } + + public void setCookies(List cookies) { + this.cookies = cookies; + } + + public String getContentType() { + return contentType; + } + + public void setContentType(String contentType) { + this.contentType = contentType; + } + + public T getResult() { + return result; + } + + public void setResult(T result) { + this.result = result; + } + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + } + + @Override + public String toString() { + if (this.result instanceof byte[]) { + HttpResult tmp = new HttpResult(); + tmp.contentType = this.contentType; + tmp.cookies = this.cookies; + tmp.headers = this.headers; + tmp.status = this.status; + tmp.result = new String((byte[]) this.result, StandardCharsets.UTF_8); + return JsonConvert.root().convertTo(tmp); + } + return JsonConvert.root().convertTo(this); + } +} diff --git a/src/main/java/org/redkale/net/http/HttpScope.java b/src/main/java/org/redkale/net/http/HttpScope.java index 91ec5061c..3c177beb8 100644 --- a/src/main/java/org/redkale/net/http/HttpScope.java +++ b/src/main/java/org/redkale/net/http/HttpScope.java @@ -1,249 +1,249 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this referid file, choose Tools | Templates - * and open the referid in the editor. - */ -package org.redkale.net.http; - -import java.io.Serializable; -import java.net.HttpCookie; -import java.util.*; -import java.util.function.*; -import javax.persistence.Transient; -import org.redkale.convert.*; -import org.redkale.convert.json.JsonConvert; - -/** - * HTTP杈撳嚭寮曟搸鐨勫璞″煙
- * 杈撳嚭寮曟搸鐨勬牳蹇冪被, 涓氬姟寮鍙戜汉鍛樺彧鏈夐氳繃鏈被瀵硅薄鎵嶈兘璋冪敤鍒拌緭鍑哄紩鎿庡姛鑳姐
- *

- * HttpServlet璋冪敤:
- *

- *    @HttpMapping(url = "/hello.html", auth = false)
- *    public void hello(HttpRequest req, HttpResponse resp) throws IOException {
- *        resp.finish(HttpScope.refer("/hello.html").attr("content", "鍝堝搱"));
- *    }
- * 
- *

- * RestService璋冪敤:
- *

- *    @RestMapping(name = "hello.html", auth = false)
- *    public HttpScope hello() {
- *       return HttpScope.refer("hello.html").attr("content", "鍝堝搱");
- *    }
- * 
- * - * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public class HttpScope { - - public static final Object NIL = new Object(); - - @ConvertColumn(index = 1) - protected String referid; - - @ConvertColumn(index = 2) - protected Map attributes; - - //@since 2.4.0 - @Transient - protected Function attrFunction; - - //@since 2.4.0 - @ConvertColumn(index = 3) - protected Map headers; - - //@since 2.4.0 - @ConvertColumn(index = 4) - protected List cookies; - - public static HttpScope refer(String template) { - HttpScope rs = new HttpScope(); - rs.setReferid(template); - return rs; - } - - public static HttpScope create(String template, String name, Object value) { - HttpScope rs = new HttpScope(); - rs.setReferid(template); - rs.attr(name, value); - return rs; - } - - public static HttpScope create(String template, String name1, Object value1, String name2, Object value2) { - HttpScope rs = new HttpScope(); - rs.setReferid(template); - rs.attr(name1, value1).attr(name2, value2); - return rs; - } - - public static HttpScope create(String template, String name1, Object value1, String name2, Object value2, String name3, Object value3) { - HttpScope rs = new HttpScope(); - rs.setReferid(template); - rs.attr(name1, value1).attr(name2, value2).attr(name3, value3); - return rs; - } - - public static HttpScope create(String template, String name1, Object value1, String name2, Object value2, String name3, Object value3, String name4, Object value4) { - HttpScope rs = new HttpScope(); - rs.setReferid(template); - rs.attr(name1, value1).attr(name2, value2).attr(name3, value3).attr(name4, value4); - return rs; - } - - public static HttpScope create(String template, String name1, Object value1, String name2, Object value2, String name3, Object value3, String name4, Object value4, String name5, Object value5) { - HttpScope rs = new HttpScope(); - rs.setReferid(template); - rs.attr(name1, value1).attr(name2, value2).attr(name3, value3).attr(name4, value4).attr(name5, value5); - return rs; - } - - public static HttpScope create(String template, Function attrFunction) { - HttpScope rs = new HttpScope(); - rs.setReferid(template); - rs.attrFunction = attrFunction; - return rs; - } - - public HttpScope attrFunc(Function attrFunction) { - this.attrFunction = attrFunction; - return this; - } - - public HttpScope appendAttrFunc(final String key, Supplier supplier) { - if (supplier == null) return this; - return appendAttrFunc(k -> k.equals(key) ? supplier.get() : null); - } - - public HttpScope appendAttrFunc(final Function attrFunc) { - if (attrFunc == null) return this; - final Function old = this.attrFunction; - if (old == null) { - this.attrFunction = attrFunc; - } else { - this.attrFunction = key -> { - Object r = old.apply(key); - return r == null ? attrFunc.apply(key) : r; - }; - } - return this; - } - - public HttpScope attr(Map map) { - if (map == null) return this; - if (this.attributes == null) this.attributes = new LinkedHashMap<>(); - this.attributes.putAll(map); - return this; - } - - public HttpScope attr(String name, Object value) { - if (name == null || value == null) return this; - if (this.attributes == null) this.attributes = new LinkedHashMap<>(); - this.attributes.put(name, value); - return this; - } - - @SuppressWarnings("unchecked") - public T find(String name) { - return this.attributes == null ? null : (T) this.attributes.get(name); - } - - @SuppressWarnings("unchecked") - public T find(HttpScope parent, String name) { - T rs = this.attributes == null ? null : (T) this.attributes.get(name); - if (rs != null) return rs; - return parent == null ? null : parent.find(name); - } - - public void forEach(BiConsumer action) { - if (this.attributes == null) return; - this.attributes.forEach(action); - } - - public HttpScope header(String name, Serializable value) { - if (this.headers == null) this.headers = new HashMap<>(); - this.headers.put(name, String.valueOf(value)); - return this; - } - - public HttpScope cookie(String name, Serializable value) { - return cookie(new HttpCookie(name, String.valueOf(value))); - } - - public HttpScope cookie(String name, Serializable value, boolean httpOnly) { - HttpCookie c = new HttpCookie(name, String.valueOf(value)); - c.setHttpOnly(httpOnly); - return cookie(c); - } - - public HttpScope cookie(HttpCookie cookie) { - if (this.cookies == null) this.cookies = new ArrayList<>(); - this.cookies.add(cookie); - return this; - } - - public String getHeader(String name) { - return headers == null ? null : headers.get(name); - } - - public String getHeader(String name, String dfvalue) { - return headers == null ? null : headers.getOrDefault(name, dfvalue); - } - - public Map getHeaders() { - return headers; - } - - public void setHeaders(Map headers) { - this.headers = headers; - } - - public List getCookies() { - return cookies; - } - - public void setCookies(List cookies) { - this.cookies = cookies; - } - - public String getReferid() { - return referid; - } - - public void setReferid(String referid) { - this.referid = referid; - } - - public Map getAttributes() { - final Function attrFunc = this.attrFunction; - if (attrFunc != null) { - if (this.attributes == null) this.attributes = new LinkedHashMap<>(); - return new LinkedHashMap(this.attributes) { - @Override - public Object get(Object key) { - if (containsKey(key)) { - return super.get(key); - } else { - Object val = attrFunc.apply(key.toString()); - if (val == NIL) return null; - put(key.toString(), val); - return val; - } - } - }; - } - return this.attributes; - } - - @ConvertDisabled(type = ConvertType.JSON) - public void setAttributes(Map attributes) { - this.attributes = attributes; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } -} +/* + * To change this license header, choose License Headers in Project Properties. + * To change this referid file, choose Tools | Templates + * and open the referid in the editor. + */ +package org.redkale.net.http; + +import java.io.Serializable; +import java.net.HttpCookie; +import java.util.*; +import java.util.function.*; +import javax.persistence.Transient; +import org.redkale.convert.*; +import org.redkale.convert.json.JsonConvert; + +/** + * HTTP杈撳嚭寮曟搸鐨勫璞″煙
+ * 杈撳嚭寮曟搸鐨勬牳蹇冪被, 涓氬姟寮鍙戜汉鍛樺彧鏈夐氳繃鏈被瀵硅薄鎵嶈兘璋冪敤鍒拌緭鍑哄紩鎿庡姛鑳姐
+ *

+ * HttpServlet璋冪敤:
+ *

+ *    @HttpMapping(url = "/hello.html", auth = false)
+ *    public void hello(HttpRequest req, HttpResponse resp) throws IOException {
+ *        resp.finish(HttpScope.refer("/hello.html").attr("content", "鍝堝搱"));
+ *    }
+ * 
+ *

+ * RestService璋冪敤:
+ *

+ *    @RestMapping(name = "hello.html", auth = false)
+ *    public HttpScope hello() {
+ *       return HttpScope.refer("hello.html").attr("content", "鍝堝搱");
+ *    }
+ * 
+ * + * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public class HttpScope { + + public static final Object NIL = new Object(); + + @ConvertColumn(index = 1) + protected String referid; + + @ConvertColumn(index = 2) + protected Map attributes; + + //@since 2.4.0 + @Transient + protected Function attrFunction; + + //@since 2.4.0 + @ConvertColumn(index = 3) + protected Map headers; + + //@since 2.4.0 + @ConvertColumn(index = 4) + protected List cookies; + + public static HttpScope refer(String template) { + HttpScope rs = new HttpScope(); + rs.setReferid(template); + return rs; + } + + public static HttpScope create(String template, String name, Object value) { + HttpScope rs = new HttpScope(); + rs.setReferid(template); + rs.attr(name, value); + return rs; + } + + public static HttpScope create(String template, String name1, Object value1, String name2, Object value2) { + HttpScope rs = new HttpScope(); + rs.setReferid(template); + rs.attr(name1, value1).attr(name2, value2); + return rs; + } + + public static HttpScope create(String template, String name1, Object value1, String name2, Object value2, String name3, Object value3) { + HttpScope rs = new HttpScope(); + rs.setReferid(template); + rs.attr(name1, value1).attr(name2, value2).attr(name3, value3); + return rs; + } + + public static HttpScope create(String template, String name1, Object value1, String name2, Object value2, String name3, Object value3, String name4, Object value4) { + HttpScope rs = new HttpScope(); + rs.setReferid(template); + rs.attr(name1, value1).attr(name2, value2).attr(name3, value3).attr(name4, value4); + return rs; + } + + public static HttpScope create(String template, String name1, Object value1, String name2, Object value2, String name3, Object value3, String name4, Object value4, String name5, Object value5) { + HttpScope rs = new HttpScope(); + rs.setReferid(template); + rs.attr(name1, value1).attr(name2, value2).attr(name3, value3).attr(name4, value4).attr(name5, value5); + return rs; + } + + public static HttpScope create(String template, Function attrFunction) { + HttpScope rs = new HttpScope(); + rs.setReferid(template); + rs.attrFunction = attrFunction; + return rs; + } + + public HttpScope attrFunc(Function attrFunction) { + this.attrFunction = attrFunction; + return this; + } + + public HttpScope appendAttrFunc(final String key, Supplier supplier) { + if (supplier == null) return this; + return appendAttrFunc(k -> k.equals(key) ? supplier.get() : null); + } + + public HttpScope appendAttrFunc(final Function attrFunc) { + if (attrFunc == null) return this; + final Function old = this.attrFunction; + if (old == null) { + this.attrFunction = attrFunc; + } else { + this.attrFunction = key -> { + Object r = old.apply(key); + return r == null ? attrFunc.apply(key) : r; + }; + } + return this; + } + + public HttpScope attr(Map map) { + if (map == null) return this; + if (this.attributes == null) this.attributes = new LinkedHashMap<>(); + this.attributes.putAll(map); + return this; + } + + public HttpScope attr(String name, Object value) { + if (name == null || value == null) return this; + if (this.attributes == null) this.attributes = new LinkedHashMap<>(); + this.attributes.put(name, value); + return this; + } + + @SuppressWarnings("unchecked") + public T find(String name) { + return this.attributes == null ? null : (T) this.attributes.get(name); + } + + @SuppressWarnings("unchecked") + public T find(HttpScope parent, String name) { + T rs = this.attributes == null ? null : (T) this.attributes.get(name); + if (rs != null) return rs; + return parent == null ? null : parent.find(name); + } + + public void forEach(BiConsumer action) { + if (this.attributes == null) return; + this.attributes.forEach(action); + } + + public HttpScope header(String name, Serializable value) { + if (this.headers == null) this.headers = new HashMap<>(); + this.headers.put(name, String.valueOf(value)); + return this; + } + + public HttpScope cookie(String name, Serializable value) { + return cookie(new HttpCookie(name, String.valueOf(value))); + } + + public HttpScope cookie(String name, Serializable value, boolean httpOnly) { + HttpCookie c = new HttpCookie(name, String.valueOf(value)); + c.setHttpOnly(httpOnly); + return cookie(c); + } + + public HttpScope cookie(HttpCookie cookie) { + if (this.cookies == null) this.cookies = new ArrayList<>(); + this.cookies.add(cookie); + return this; + } + + public String getHeader(String name) { + return headers == null ? null : headers.get(name); + } + + public String getHeader(String name, String dfvalue) { + return headers == null ? null : headers.getOrDefault(name, dfvalue); + } + + public Map getHeaders() { + return headers; + } + + public void setHeaders(Map headers) { + this.headers = headers; + } + + public List getCookies() { + return cookies; + } + + public void setCookies(List cookies) { + this.cookies = cookies; + } + + public String getReferid() { + return referid; + } + + public void setReferid(String referid) { + this.referid = referid; + } + + public Map getAttributes() { + final Function attrFunc = this.attrFunction; + if (attrFunc != null) { + if (this.attributes == null) this.attributes = new LinkedHashMap<>(); + return new LinkedHashMap(this.attributes) { + @Override + public Object get(Object key) { + if (containsKey(key)) { + return super.get(key); + } else { + Object val = attrFunc.apply(key.toString()); + if (val == NIL) return null; + put(key.toString(), val); + return val; + } + } + }; + } + return this.attributes; + } + + @ConvertDisabled(type = ConvertType.JSON) + public void setAttributes(Map attributes) { + this.attributes = attributes; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } +} diff --git a/src/main/java/org/redkale/net/http/HttpServlet.java b/src/main/java/org/redkale/net/http/HttpServlet.java index 6159843b3..7a9e8b1a6 100644 --- a/src/main/java/org/redkale/net/http/HttpServlet.java +++ b/src/main/java/org/redkale/net/http/HttpServlet.java @@ -1,462 +1,462 @@ -/* - * 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 java.io.IOException; -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.function.*; -import org.redkale.asm.*; -import static org.redkale.asm.ClassWriter.COMPUTE_FRAMES; -import static org.redkale.asm.Opcodes.*; -import org.redkale.boot.Application; -import org.redkale.net.*; -import org.redkale.service.RetResult; -import org.redkale.util.*; - -/** - * HTTP鐗堢殑Servlet锛 鎵ц椤哄簭 execute --> preExecute --> authenticate --> HttpMapping瀵瑰簲鐨勬柟娉 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public class HttpServlet extends Servlet { - - public static final int RET_SERVER_ERROR = 1200_0001; - - public static final int RET_METHOD_ERROR = 1200_0002; - - String _prefix = ""; //褰撳墠HttpServlet鐨刾ath鍓嶇紑 - - String _reqtopic; //鏍规嵁RestService+MQ鐢熸垚鐨勫 @since 2.5.0 - - String _mmctopic; //鏍规嵁RestService+@MessageMultiConsumer鐢熸垚鐨勫 @since 2.5.0 - - HashMap _actionmap; //Rest鐢熸垚鏃惰祴鍊, 瀛楁鍚峈est鏈夌敤鍒 - - private Map.Entry[] mappings; //瀛楁鍚峈est鏈夌敤鍒 - - //杩欓噷涓嶈兘鐩存帴浣跨敤HttpServlet锛屼細閫犳垚姝诲惊鐜垵濮嬪寲HttpServlet - private final Servlet authSuccessServlet = new Servlet() { - @Override - public void execute(HttpRequest request, HttpResponse response) throws IOException { - ActionEntry entry = request.actionEntry; - if (entry.rpconly && !request.rpc) { - response.finish(503, null); - return; - } - if (entry.cacheseconds > 0) {//鏈夌紦瀛樿缃 - CacheEntry ce = entry.modeOneCache ? entry.oneCache : entry.cache.get(request.getRequestURI()); - if (ce != null && ce.time + entry.cacheseconds * 1000 > System.currentTimeMillis()) { //缂撳瓨鏈夋晥 - response.setStatus(ce.status); - response.setContentType(ce.contentType); - response.skipHeader(); - response.finish(ce.getBytes()); - return; - } - response.setCacheHandler(entry.cacheHandler); - } - entry.servlet.execute(request, response); - } - }; - - //preExecute杩愯瀹屽悗鎵ц鐨凷ervlet - private final Servlet preSuccessServlet = new Servlet() { - @Override - public void execute(HttpRequest request, HttpResponse response) throws IOException { - if (request.actionEntry != null) { - ActionEntry entry = request.actionEntry; - if (!entry.checkMethod(request.getMethod())) { - response.finishJson(new RetResult(RET_METHOD_ERROR, "Method(" + request.getMethod() + ") Error")); - return; - } - request.moduleid = entry.moduleid; - request.actionid = entry.actionid; - request.annotations = entry.annotations; - if (entry.auth) { - response.thenEvent(authSuccessServlet); - authenticate(request, response); - } else { - authSuccessServlet.execute(request, response); - } - return; - } - for (Map.Entry en : mappings) { - if (request.getRequestURI().startsWith(en.getKey())) { - ActionEntry entry = en.getValue(); - if (!entry.checkMethod(request.getMethod())) { - response.finishJson(new RetResult(RET_METHOD_ERROR, "Method(" + request.getMethod() + ") Error")); - return; - } - request.actionEntry = entry; - request.moduleid = entry.moduleid; - request.actionid = entry.actionid; - request.annotations = entry.annotations; - if (entry.auth) { - response.thenEvent(authSuccessServlet); - authenticate(request, response); - } else { - authSuccessServlet.execute(request, response); - } - return; - } - } - response.finish404(); - //throw new IOException(this.getClass().getName() + " not found method for URI(" + request.getRequestURI() + ")"); - } - }; - - @SuppressWarnings("unchecked") - void preInit(Application application, HttpContext context, AnyValue config) { - if (this.mappings != null) return; //鏃犻渶閲嶅preInit - String path = _prefix == null ? "" : _prefix; - WebServlet ws = this.getClass().getAnnotation(WebServlet.class); - if (ws != null && !ws.repair()) path = ""; - HashMap map = this._actionmap != null ? this._actionmap : loadActionEntry(); - this.mappings = new Map.Entry[map.size()]; - int i = -1; - for (Map.Entry en : map.entrySet()) { - mappings[++i] = new AbstractMap.SimpleEntry<>(path + en.getKey(), en.getValue()); - } - //蹇呴』瑕佸掓帓搴, /query /query1 /query12 纭繚鍚瓙闆嗙殑浼樺厛鍖归厤 /query12 /query1 /query - Arrays.sort(mappings, (o1, o2) -> o2.getKey().compareTo(o1.getKey())); - } - - void postDestroy(Application application, HttpContext context, AnyValue config) { - } - - //Server鎵цstart鍚庤繍琛屾鏂规硶 - public void postStart(HttpContext context, AnyValue config) { - } - - /** - *

- * 棰勬墽琛屾柟娉曪紝鍦╡xecute鏂规硶涔嬪墠杩愯锛岃缃綋鍓嶇敤鎴蜂俊鎭紝鎴栬呭姞鍏ュ父瑙勭粺璁″拰鍩虹妫娴嬶紝渚嬪 :
- *

-     *      @Override
-     *      public void preExecute(final HttpRequest request, final HttpResponse response) throws IOException {
-     *          //璁剧疆褰撳墠鐢ㄦ埛淇℃伅
-     *          final String sessionid = request.getSessionid(false);
-     *          if (sessionid != null) request.setCurrentUserid(userService.currentUserid(sessionid));
-     *
-     *          if (finer) response.recycleListener((req, resp) -> {  //璁板綍澶勭悊鏃堕棿姣旇緝闀跨殑璇锋眰
-     *              long e = System.currentTimeMillis() - ((HttpRequest) req).getCreatetime();
-     *              if (e > 200) logger.finer("http-execute-cost-time: " + e + " ms. request = " + req);
-     *          });
-     *          response.nextEvent();
-     *      }
-     * 
- *

- * - * @param request HttpRequest - * @param response HttpResponse - * - * @throws IOException IOException - */ - protected void preExecute(HttpRequest request, HttpResponse response) throws IOException { - response.nextEvent(); - } - - /** - *

- * 鐢ㄦ埛鐧诲綍鎴栨潈闄愰獙璇侊紝 娉ㄨВ涓@HttpMapping.auth == true 鐨勬柟娉曚細鎵цauthenticate鏂规硶, 鑻ラ獙璇佹垚鍔熷垯蹇呴』璋冪敤response.nextEvent();杩涜涓嬩竴姝ユ搷浣, 渚嬪:
- *

-     *      @Override
-     *      public void authenticate(HttpRequest request, HttpResponse response) throws IOException {
-     *          Serializable userid = request.currentUserid();
-     *          if (userid == null) {
-     *              response.finishJson(RET_UNLOGIN);
-     *              return;
-     *          }
-     *          response.nextEvent();
-     *      }
-     * 
- *

- * - * - * @param request HttpRequest - * @param response HttpResponse - * - * @throws IOException IOException - */ - protected void authenticate(HttpRequest request, HttpResponse response) throws IOException { - response.nextEvent(); - } - - @Override - public void execute(HttpRequest request, HttpResponse response) throws IOException { - response.thenEvent(preSuccessServlet); - preExecute(request, response); - } - - private HashMap loadActionEntry() { - WebServlet module = this.getClass().getAnnotation(WebServlet.class); - final int serviceid = module == null ? 0 : module.moduleid(); - final HashMap map = new HashMap<>(); - HashMap nameset = new HashMap<>(); - final Class selfClz = this.getClass(); - Class clz = this.getClass(); - do { - if (java.lang.reflect.Modifier.isAbstract(clz.getModifiers())) break; - RedkaleClassLoader.putReflectionPublicMethods(clz.getName()); - for (final Method method : clz.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 HttpMapping mapping = method.getAnnotation(HttpMapping.class); - if (mapping == null) continue; - final boolean inherited = mapping.inherited(); - if (!inherited && selfClz != clz) continue; //蹇界暐涓嶈缁ф壙鐨勬柟娉 - final int actionid = mapping.actionid(); - final String name = mapping.url().trim(); - final String[] methods = mapping.methods(); - if (nameset.containsKey(name)) { - if (nameset.get(name) != clz) continue; - throw new RuntimeException(this.getClass().getSimpleName() + " have two same " + HttpMapping.class.getSimpleName() + "(" + name + ")"); - } - nameset.put(name, clz); - map.put(name, new ActionEntry(serviceid, actionid, name, methods, method, createActionServlet(method))); - } - } while ((clz = clz.getSuperclass()) != HttpServlet.class); - return map; - } - - protected static final class ActionEntry { - - ActionEntry(int moduleid, int actionid, String name, String[] methods, Method method, HttpServlet servlet) { - this(moduleid, actionid, name, methods, method, rpconly(method), auth(method), cacheseconds(method), servlet); - this.annotations = annotations(method); - } - - //渚汻est绫讳娇鐢紝鍙傛暟涓嶈兘闅忎究鏇存敼 - public ActionEntry(int moduleid, int actionid, String name, String[] methods, Method method, boolean rpconly, boolean auth, int cacheseconds, HttpServlet servlet) { - this.moduleid = moduleid; - this.actionid = actionid; - this.name = name; - this.methods = methods; - this.method = method; //rest鏋勫缓浼氫负null - this.servlet = servlet; - this.rpconly = rpconly; - this.auth = auth; - this.cacheseconds = cacheseconds; - if (Utility.contains(name, '*', '{', '[', '(', '|', '^', '$', '+', '?', '\\') || name.endsWith("/")) { //鏄惁鏄鍒欒〃杈惧紡 - this.modeOneCache = false; - this.cache = cacheseconds > 0 ? new ConcurrentHashMap<>() : null; - this.cacheHandler = cacheseconds > 0 ? (HttpResponse response, byte[] content) -> { - int status = response.getStatus(); - if (status != 200) return; - CacheEntry ce = new CacheEntry(response.getStatus(), response.getContentType(), content); - cache.put(response.getRequest().getRequestURI(), ce); - } : null; - } else { //鍗曚竴url - this.modeOneCache = true; - this.cache = null; - this.cacheHandler = cacheseconds > 0 ? (HttpResponse response, byte[] content) -> { - int status = response.getStatus(); - if (status != 200) return; - oneCache = new CacheEntry(response.getStatus(), response.getContentType(), content); - } : null; - } - } - - protected static boolean auth(Method method) { - HttpMapping mapping = method.getAnnotation(HttpMapping.class); - return mapping == null || mapping.auth(); - } - - protected static boolean rpconly(Method method) { - HttpMapping mapping = method.getAnnotation(HttpMapping.class); - return mapping == null || mapping.rpconly(); - } - - protected static int cacheseconds(Method method) { - HttpMapping mapping = method.getAnnotation(HttpMapping.class); - return mapping == null ? 0 : mapping.cacheseconds(); - } - - //Rest.class浼氱敤鍒版鏂规硶 - protected static Annotation[] annotations(Method method) { - return method.getAnnotations(); - } - - boolean isNeedCheck() { - return this.moduleid != 0 || this.actionid != 0; - } - - boolean checkMethod(final String reqMethod) { - if (methods.length == 0) return true; - for (String m : methods) { - if (reqMethod.equalsIgnoreCase(m)) return true; - } - return false; - } - - final BiConsumer cacheHandler; - - final ConcurrentHashMap cache; - - final boolean modeOneCache; - - final int cacheseconds; - - final boolean rpconly; - - final boolean auth; - - final int moduleid; - - final int actionid; - - final String name; - - final String[] methods; - - final HttpServlet servlet; - - Method method; - - CacheEntry oneCache; - - Annotation[] annotations; - } - - private HttpServlet createActionServlet(final Method method) { - //------------------------------------------------------------------------------ - final String supDynName = HttpServlet.class.getName().replace('.', '/'); - final String interName = this.getClass().getName().replace('.', '/'); - final String interDesc = org.redkale.asm.Type.getDescriptor(this.getClass()); - final String requestSupDesc = org.redkale.asm.Type.getDescriptor(Request.class); - final String responseSupDesc = org.redkale.asm.Type.getDescriptor(Response.class); - final String requestDesc = org.redkale.asm.Type.getDescriptor(HttpRequest.class); - final String responseDesc = org.redkale.asm.Type.getDescriptor(HttpResponse.class); - final String factfield = "_factServlet"; - StringBuilder tmpps = new StringBuilder(); - for (Class cz : method.getParameterTypes()) { - tmpps.append("__").append(cz.getName().replace('.', '_')); - } - final String newDynName = "org/redkaledyn/http/servlet/action/_DynHttpActionServlet__" + this.getClass().getName().replace('.', '_').replace('$', '_') + "__" + method.getName() + tmpps; - try { - Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); - Class newClazz = clz == null ? Thread.currentThread().getContextClassLoader().loadClass(newDynName.replace('/', '.')) : clz; - HttpServlet instance = (HttpServlet) newClazz.getDeclaredConstructor().newInstance(); - instance.getClass().getField("_factServlet").set(instance, this); - return instance; - } catch (Throwable ex) { - } - //------------------------------------------------------------------------------ - ClassWriter cw = new ClassWriter(COMPUTE_FRAMES); - FieldVisitor fv; - MethodVisitor mv; - AnnotationVisitor av0; - cw.visit(V11, 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); - RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, newClazz); - RedkaleClassLoader.putReflectionDeclaredConstructors(newClazz, newDynName.replace('/', '.')); - try { - HttpServlet instance = (HttpServlet) newClazz.getDeclaredConstructor().newInstance(); - java.lang.reflect.Field field = instance.getClass().getField(factfield); - field.set(instance, this); - RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), field); - return instance; - } catch (Exception ex) { - throw new RuntimeException(ex); - } - } - - private static final class CacheEntry { - - public final long time = System.currentTimeMillis(); - - private final byte[] cacheBytes; - - private final int status; - - private final String contentType; - - public CacheEntry(int status, String contentType, byte[] cacheBytes) { - this.status = status; - this.contentType = contentType; - this.cacheBytes = cacheBytes; - } - - public byte[] getBytes() { - return cacheBytes; - } - } - - static class HttpActionServlet extends HttpServlet { - - final ActionEntry action; - - final HttpServlet servlet; - - public HttpActionServlet(ActionEntry actionEntry, HttpServlet servlet) { - this.action = actionEntry; - this.servlet = servlet; - } - - @Override - public void execute(HttpRequest request, HttpResponse response) throws IOException { - request.actionEntry = action; - servlet.execute(request, response); - } - } -} +/* + * 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 java.io.IOException; +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.*; +import org.redkale.asm.*; +import static org.redkale.asm.ClassWriter.COMPUTE_FRAMES; +import static org.redkale.asm.Opcodes.*; +import org.redkale.boot.Application; +import org.redkale.net.*; +import org.redkale.service.RetResult; +import org.redkale.util.*; + +/** + * HTTP鐗堢殑Servlet锛 鎵ц椤哄簭 execute --> preExecute --> authenticate --> HttpMapping瀵瑰簲鐨勬柟娉 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public class HttpServlet extends Servlet { + + public static final int RET_SERVER_ERROR = 1200_0001; + + public static final int RET_METHOD_ERROR = 1200_0002; + + String _prefix = ""; //褰撳墠HttpServlet鐨刾ath鍓嶇紑 + + String _reqtopic; //鏍规嵁RestService+MQ鐢熸垚鐨勫 @since 2.5.0 + + String _mmctopic; //鏍规嵁RestService+@MessageMultiConsumer鐢熸垚鐨勫 @since 2.5.0 + + HashMap _actionmap; //Rest鐢熸垚鏃惰祴鍊, 瀛楁鍚峈est鏈夌敤鍒 + + private Map.Entry[] mappings; //瀛楁鍚峈est鏈夌敤鍒 + + //杩欓噷涓嶈兘鐩存帴浣跨敤HttpServlet锛屼細閫犳垚姝诲惊鐜垵濮嬪寲HttpServlet + private final Servlet authSuccessServlet = new Servlet() { + @Override + public void execute(HttpRequest request, HttpResponse response) throws IOException { + ActionEntry entry = request.actionEntry; + if (entry.rpconly && !request.rpc) { + response.finish(503, null); + return; + } + if (entry.cacheseconds > 0) {//鏈夌紦瀛樿缃 + CacheEntry ce = entry.modeOneCache ? entry.oneCache : entry.cache.get(request.getRequestURI()); + if (ce != null && ce.time + entry.cacheseconds * 1000 > System.currentTimeMillis()) { //缂撳瓨鏈夋晥 + response.setStatus(ce.status); + response.setContentType(ce.contentType); + response.skipHeader(); + response.finish(ce.getBytes()); + return; + } + response.setCacheHandler(entry.cacheHandler); + } + entry.servlet.execute(request, response); + } + }; + + //preExecute杩愯瀹屽悗鎵ц鐨凷ervlet + private final Servlet preSuccessServlet = new Servlet() { + @Override + public void execute(HttpRequest request, HttpResponse response) throws IOException { + if (request.actionEntry != null) { + ActionEntry entry = request.actionEntry; + if (!entry.checkMethod(request.getMethod())) { + response.finishJson(new RetResult(RET_METHOD_ERROR, "Method(" + request.getMethod() + ") Error")); + return; + } + request.moduleid = entry.moduleid; + request.actionid = entry.actionid; + request.annotations = entry.annotations; + if (entry.auth) { + response.thenEvent(authSuccessServlet); + authenticate(request, response); + } else { + authSuccessServlet.execute(request, response); + } + return; + } + for (Map.Entry en : mappings) { + if (request.getRequestURI().startsWith(en.getKey())) { + ActionEntry entry = en.getValue(); + if (!entry.checkMethod(request.getMethod())) { + response.finishJson(new RetResult(RET_METHOD_ERROR, "Method(" + request.getMethod() + ") Error")); + return; + } + request.actionEntry = entry; + request.moduleid = entry.moduleid; + request.actionid = entry.actionid; + request.annotations = entry.annotations; + if (entry.auth) { + response.thenEvent(authSuccessServlet); + authenticate(request, response); + } else { + authSuccessServlet.execute(request, response); + } + return; + } + } + response.finish404(); + //throw new IOException(this.getClass().getName() + " not found method for URI(" + request.getRequestURI() + ")"); + } + }; + + @SuppressWarnings("unchecked") + void preInit(Application application, HttpContext context, AnyValue config) { + if (this.mappings != null) return; //鏃犻渶閲嶅preInit + String path = _prefix == null ? "" : _prefix; + WebServlet ws = this.getClass().getAnnotation(WebServlet.class); + if (ws != null && !ws.repair()) path = ""; + HashMap map = this._actionmap != null ? this._actionmap : loadActionEntry(); + this.mappings = new Map.Entry[map.size()]; + int i = -1; + for (Map.Entry en : map.entrySet()) { + mappings[++i] = new AbstractMap.SimpleEntry<>(path + en.getKey(), en.getValue()); + } + //蹇呴』瑕佸掓帓搴, /query /query1 /query12 纭繚鍚瓙闆嗙殑浼樺厛鍖归厤 /query12 /query1 /query + Arrays.sort(mappings, (o1, o2) -> o2.getKey().compareTo(o1.getKey())); + } + + void postDestroy(Application application, HttpContext context, AnyValue config) { + } + + //Server鎵цstart鍚庤繍琛屾鏂规硶 + public void postStart(HttpContext context, AnyValue config) { + } + + /** + *

+ * 棰勬墽琛屾柟娉曪紝鍦╡xecute鏂规硶涔嬪墠杩愯锛岃缃綋鍓嶇敤鎴蜂俊鎭紝鎴栬呭姞鍏ュ父瑙勭粺璁″拰鍩虹妫娴嬶紝渚嬪 :
+ *

+     *      @Override
+     *      public void preExecute(final HttpRequest request, final HttpResponse response) throws IOException {
+     *          //璁剧疆褰撳墠鐢ㄦ埛淇℃伅
+     *          final String sessionid = request.getSessionid(false);
+     *          if (sessionid != null) request.setCurrentUserid(userService.currentUserid(sessionid));
+     *
+     *          if (finer) response.recycleListener((req, resp) -> {  //璁板綍澶勭悊鏃堕棿姣旇緝闀跨殑璇锋眰
+     *              long e = System.currentTimeMillis() - ((HttpRequest) req).getCreatetime();
+     *              if (e > 200) logger.finer("http-execute-cost-time: " + e + " ms. request = " + req);
+     *          });
+     *          response.nextEvent();
+     *      }
+     * 
+ *

+ * + * @param request HttpRequest + * @param response HttpResponse + * + * @throws IOException IOException + */ + protected void preExecute(HttpRequest request, HttpResponse response) throws IOException { + response.nextEvent(); + } + + /** + *

+ * 鐢ㄦ埛鐧诲綍鎴栨潈闄愰獙璇侊紝 娉ㄨВ涓@HttpMapping.auth == true 鐨勬柟娉曚細鎵цauthenticate鏂规硶, 鑻ラ獙璇佹垚鍔熷垯蹇呴』璋冪敤response.nextEvent();杩涜涓嬩竴姝ユ搷浣, 渚嬪:
+ *

+     *      @Override
+     *      public void authenticate(HttpRequest request, HttpResponse response) throws IOException {
+     *          Serializable userid = request.currentUserid();
+     *          if (userid == null) {
+     *              response.finishJson(RET_UNLOGIN);
+     *              return;
+     *          }
+     *          response.nextEvent();
+     *      }
+     * 
+ *

+ * + * + * @param request HttpRequest + * @param response HttpResponse + * + * @throws IOException IOException + */ + protected void authenticate(HttpRequest request, HttpResponse response) throws IOException { + response.nextEvent(); + } + + @Override + public void execute(HttpRequest request, HttpResponse response) throws IOException { + response.thenEvent(preSuccessServlet); + preExecute(request, response); + } + + private HashMap loadActionEntry() { + WebServlet module = this.getClass().getAnnotation(WebServlet.class); + final int serviceid = module == null ? 0 : module.moduleid(); + final HashMap map = new HashMap<>(); + HashMap nameset = new HashMap<>(); + final Class selfClz = this.getClass(); + Class clz = this.getClass(); + do { + if (java.lang.reflect.Modifier.isAbstract(clz.getModifiers())) break; + RedkaleClassLoader.putReflectionPublicMethods(clz.getName()); + for (final Method method : clz.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 HttpMapping mapping = method.getAnnotation(HttpMapping.class); + if (mapping == null) continue; + final boolean inherited = mapping.inherited(); + if (!inherited && selfClz != clz) continue; //蹇界暐涓嶈缁ф壙鐨勬柟娉 + final int actionid = mapping.actionid(); + final String name = mapping.url().trim(); + final String[] methods = mapping.methods(); + if (nameset.containsKey(name)) { + if (nameset.get(name) != clz) continue; + throw new RuntimeException(this.getClass().getSimpleName() + " have two same " + HttpMapping.class.getSimpleName() + "(" + name + ")"); + } + nameset.put(name, clz); + map.put(name, new ActionEntry(serviceid, actionid, name, methods, method, createActionServlet(method))); + } + } while ((clz = clz.getSuperclass()) != HttpServlet.class); + return map; + } + + protected static final class ActionEntry { + + ActionEntry(int moduleid, int actionid, String name, String[] methods, Method method, HttpServlet servlet) { + this(moduleid, actionid, name, methods, method, rpconly(method), auth(method), cacheseconds(method), servlet); + this.annotations = annotations(method); + } + + //渚汻est绫讳娇鐢紝鍙傛暟涓嶈兘闅忎究鏇存敼 + public ActionEntry(int moduleid, int actionid, String name, String[] methods, Method method, boolean rpconly, boolean auth, int cacheseconds, HttpServlet servlet) { + this.moduleid = moduleid; + this.actionid = actionid; + this.name = name; + this.methods = methods; + this.method = method; //rest鏋勫缓浼氫负null + this.servlet = servlet; + this.rpconly = rpconly; + this.auth = auth; + this.cacheseconds = cacheseconds; + if (Utility.contains(name, '*', '{', '[', '(', '|', '^', '$', '+', '?', '\\') || name.endsWith("/")) { //鏄惁鏄鍒欒〃杈惧紡 + this.modeOneCache = false; + this.cache = cacheseconds > 0 ? new ConcurrentHashMap<>() : null; + this.cacheHandler = cacheseconds > 0 ? (HttpResponse response, byte[] content) -> { + int status = response.getStatus(); + if (status != 200) return; + CacheEntry ce = new CacheEntry(response.getStatus(), response.getContentType(), content); + cache.put(response.getRequest().getRequestURI(), ce); + } : null; + } else { //鍗曚竴url + this.modeOneCache = true; + this.cache = null; + this.cacheHandler = cacheseconds > 0 ? (HttpResponse response, byte[] content) -> { + int status = response.getStatus(); + if (status != 200) return; + oneCache = new CacheEntry(response.getStatus(), response.getContentType(), content); + } : null; + } + } + + protected static boolean auth(Method method) { + HttpMapping mapping = method.getAnnotation(HttpMapping.class); + return mapping == null || mapping.auth(); + } + + protected static boolean rpconly(Method method) { + HttpMapping mapping = method.getAnnotation(HttpMapping.class); + return mapping == null || mapping.rpconly(); + } + + protected static int cacheseconds(Method method) { + HttpMapping mapping = method.getAnnotation(HttpMapping.class); + return mapping == null ? 0 : mapping.cacheseconds(); + } + + //Rest.class浼氱敤鍒版鏂规硶 + protected static Annotation[] annotations(Method method) { + return method.getAnnotations(); + } + + boolean isNeedCheck() { + return this.moduleid != 0 || this.actionid != 0; + } + + boolean checkMethod(final String reqMethod) { + if (methods.length == 0) return true; + for (String m : methods) { + if (reqMethod.equalsIgnoreCase(m)) return true; + } + return false; + } + + final BiConsumer cacheHandler; + + final ConcurrentHashMap cache; + + final boolean modeOneCache; + + final int cacheseconds; + + final boolean rpconly; + + final boolean auth; + + final int moduleid; + + final int actionid; + + final String name; + + final String[] methods; + + final HttpServlet servlet; + + Method method; + + CacheEntry oneCache; + + Annotation[] annotations; + } + + private HttpServlet createActionServlet(final Method method) { + //------------------------------------------------------------------------------ + final String supDynName = HttpServlet.class.getName().replace('.', '/'); + final String interName = this.getClass().getName().replace('.', '/'); + final String interDesc = org.redkale.asm.Type.getDescriptor(this.getClass()); + final String requestSupDesc = org.redkale.asm.Type.getDescriptor(Request.class); + final String responseSupDesc = org.redkale.asm.Type.getDescriptor(Response.class); + final String requestDesc = org.redkale.asm.Type.getDescriptor(HttpRequest.class); + final String responseDesc = org.redkale.asm.Type.getDescriptor(HttpResponse.class); + final String factfield = "_factServlet"; + StringBuilder tmpps = new StringBuilder(); + for (Class cz : method.getParameterTypes()) { + tmpps.append("__").append(cz.getName().replace('.', '_')); + } + final String newDynName = "org/redkaledyn/http/servlet/action/_DynHttpActionServlet__" + this.getClass().getName().replace('.', '_').replace('$', '_') + "__" + method.getName() + tmpps; + try { + Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); + Class newClazz = clz == null ? Thread.currentThread().getContextClassLoader().loadClass(newDynName.replace('/', '.')) : clz; + HttpServlet instance = (HttpServlet) newClazz.getDeclaredConstructor().newInstance(); + instance.getClass().getField("_factServlet").set(instance, this); + return instance; + } catch (Throwable ex) { + } + //------------------------------------------------------------------------------ + ClassWriter cw = new ClassWriter(COMPUTE_FRAMES); + FieldVisitor fv; + MethodVisitor mv; + AnnotationVisitor av0; + cw.visit(V11, 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); + RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, newClazz); + RedkaleClassLoader.putReflectionDeclaredConstructors(newClazz, newDynName.replace('/', '.')); + try { + HttpServlet instance = (HttpServlet) newClazz.getDeclaredConstructor().newInstance(); + java.lang.reflect.Field field = instance.getClass().getField(factfield); + field.set(instance, this); + RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), field); + return instance; + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + + private static final class CacheEntry { + + public final long time = System.currentTimeMillis(); + + private final byte[] cacheBytes; + + private final int status; + + private final String contentType; + + public CacheEntry(int status, String contentType, byte[] cacheBytes) { + this.status = status; + this.contentType = contentType; + this.cacheBytes = cacheBytes; + } + + public byte[] getBytes() { + return cacheBytes; + } + } + + static class HttpActionServlet extends HttpServlet { + + final ActionEntry action; + + final HttpServlet servlet; + + public HttpActionServlet(ActionEntry actionEntry, HttpServlet servlet) { + this.action = actionEntry; + this.servlet = servlet; + } + + @Override + public void execute(HttpRequest request, HttpResponse response) throws IOException { + request.actionEntry = action; + servlet.execute(request, response); + } + } +} diff --git a/src/main/java/org/redkale/net/http/HttpSimpleRequest.java b/src/main/java/org/redkale/net/http/HttpSimpleRequest.java index 737fe1dbc..3ade55c29 100644 --- a/src/main/java/org/redkale/net/http/HttpSimpleRequest.java +++ b/src/main/java/org/redkale/net/http/HttpSimpleRequest.java @@ -1,396 +1,396 @@ -/* - * 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 java.io.*; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; -import java.util.*; -import java.util.concurrent.atomic.AtomicBoolean; -import org.redkale.convert.*; -import org.redkale.convert.json.JsonConvert; -import org.redkale.util.*; - -/** - * HttpRequest鐨勭缉鍑忕増, 鍙彁渚涢儴鍒嗗瓧娈 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * - * @since 2.1.0 - */ -public class HttpSimpleRequest implements java.io.Serializable { - - @ConvertColumn(index = 1) - @Comment("鏄惁RPC璇锋眰, 璇ョ被閫氬父鏄负RPC鍒涘缓鐨勶紝鏁呴粯璁ゆ槸true") - protected boolean rpc = true; - - @ConvertColumn(index = 2) - @Comment("鏄惁浠巄ody涓幏鍙栧弬鏁帮紝姣斿protobuf鏁版嵁鏍煎紡") - protected boolean frombody; - - @ConvertColumn(index = 3) - @Comment("璇锋眰鍙傛暟鐨凜onvertType") - protected ConvertType reqConvertType; - - @ConvertColumn(index = 4) - @Comment("杈撳嚭缁撴灉鐨凜onvertType") - protected ConvertType respConvertType; - - @ConvertColumn(index = 5) - @Comment("璇锋眰鐨刄RI") - protected String requestURI; - - @ConvertColumn(index = 6) - @Comment("璇锋眰鐨勫墠缂") - protected String path; - - @ConvertColumn(index = 7) - @Comment("瀹㈡埛绔疘P") - protected String remoteAddr; - - @ConvertColumn(index = 8) - @Comment("浼氳瘽ID") - protected String sessionid; - - @ConvertColumn(index = 9) - @Comment("Content-Type") - protected String contentType; - - @ConvertColumn(index = 10) - protected int hashid; - - @ConvertColumn(index = 11) //@since 2.5.0 鐢眎nt鏀规垚Serializable, 鍏蜂綋鏁版嵁绫诲瀷鍙兘鏄痠nt銆乴ong銆丼tring - protected Serializable currentUserid; - - @ConvertColumn(index = 12) - @Comment("http header淇℃伅") - protected Map headers; - - @ConvertColumn(index = 13) - @Comment("鍙傛暟淇℃伅") - protected Map params; - - @ConvertColumn(index = 14) - @Comment("http body淇℃伅") - protected byte[] body; //瀵瑰簲HttpRequest.array - - public static HttpSimpleRequest create(String requestURI) { - return new HttpSimpleRequest().requestURI(requestURI); - } - - public static HttpSimpleRequest create(String requestURI, Object... params) { - HttpSimpleRequest req = new HttpSimpleRequest().requestURI(requestURI); - int len = params.length / 2; - for (int i = 0; i < len; i++) { - req.param(params[i * 2].toString(), params[i * 2 + 1]); - } - return req; - } - - @ConvertDisabled - public String getParametersToString() { - if (this.params == null || this.params.isEmpty()) return null; - final StringBuilder sb = new StringBuilder(); - AtomicBoolean no2 = new AtomicBoolean(false); - this.params.forEach((n, v) -> { - if (no2.get()) sb.append('&'); - sb.append(n).append('=').append(URLEncoder.encode(v, StandardCharsets.UTF_8)); - no2.set(true); - }); - return sb.toString(); - } - - public HttpSimpleRequest rpc(boolean rpc) { - this.rpc = rpc; - return this; - } - - public HttpSimpleRequest requestURI(String requestURI) { - this.requestURI = requestURI; - return this; - } - - public HttpSimpleRequest path(String path) { - this.path = path; - return this; - } - - public HttpSimpleRequest requestURI(boolean frombody) { - this.frombody = frombody; - return this; - } - - public HttpSimpleRequest frombody(boolean frombody) { - this.frombody = frombody; - return this; - } - - public HttpSimpleRequest bothConvertType(ConvertType convertType) { - this.reqConvertType = convertType; - this.respConvertType = convertType; - return this; - } - - public HttpSimpleRequest reqConvertType(ConvertType reqConvertType) { - this.reqConvertType = reqConvertType; - return this; - } - - public HttpSimpleRequest respConvertType(ConvertType respConvertType) { - this.respConvertType = respConvertType; - return this; - } - - public HttpSimpleRequest remoteAddr(String remoteAddr) { - this.remoteAddr = remoteAddr; - return this; - } - - public HttpSimpleRequest sessionid(String sessionid) { - this.sessionid = sessionid; - return this; - } - - public HttpSimpleRequest contentType(String contentType) { - this.contentType = contentType; - return this; - } - - public HttpSimpleRequest hashid(int hashid) { - this.hashid = hashid; - return this; - } - - public HttpSimpleRequest currentUserid(Serializable userid) { - this.currentUserid = userid; - return this; - } - - public HttpSimpleRequest removeHeader(String name) { - if (this.headers != null) this.headers.remove(name); - return this; - } - - public HttpSimpleRequest removeParam(String name) { - if (this.params != null) this.params.remove(name); - return this; - } - - public HttpSimpleRequest headers(Map headers) { - this.headers = headers; - return this; - } - - public HttpSimpleRequest params(Map params) { - this.params = params; - return this; - } - - public HttpSimpleRequest header(String key, String value) { - if (this.headers == null) this.headers = new HashMap<>(); - this.headers.put(key, value); - return this; - } - - public HttpSimpleRequest header(String key, JsonConvert convert, Object value) { - if (value == null) return this; - if (this.headers == null) this.headers = new HashMap<>(); - if (convert == null) convert = JsonConvert.root(); - this.headers.put(key, convert.convertTo(value)); - return this; - } - - public HttpSimpleRequest header(String key, Object value) { - if (value == null) return this; - if (this.headers == null) this.headers = new HashMap<>(); - this.headers.put(key, JsonConvert.root().convertTo(value)); - return this; - } - - public HttpSimpleRequest header(String key, int value) { - if (this.headers == null) this.headers = new HashMap<>(); - this.headers.put(key, String.valueOf(value)); - return this; - } - - public HttpSimpleRequest header(String key, long value) { - if (this.headers == null) this.headers = new HashMap<>(); - this.headers.put(key, String.valueOf(value)); - return this; - } - - public HttpSimpleRequest param(String key, String value) { - if (this.params == null) this.params = new HashMap<>(); - this.params.put(key, value); - return this; - } - - public HttpSimpleRequest param(String key, JsonConvert convert, Object value) { - if (value == null) return this; - if (this.params == null) this.params = new HashMap<>(); - if (convert == null) convert = JsonConvert.root(); - this.params.put(key, convert.convertTo(value)); - return this; - } - - public HttpSimpleRequest param(String key, Object value) { - if (value == null) return this; - if (this.params == null) this.params = new HashMap<>(); - this.params.put(key, value instanceof CharSequence ? value.toString() : JsonConvert.root().convertTo(value)); - return this; - } - - public HttpSimpleRequest body(byte[] body) { - this.body = body; - return this; - } - - public HttpSimpleRequest clearParams() { - this.params = null; - return this; - } - - public HttpSimpleRequest clearHeaders() { - this.headers = null; - return this; - } - - public HttpSimpleRequest clearRemoteAddr() { - this.remoteAddr = null; - return this; - } - - public HttpSimpleRequest clearSessionid() { - this.sessionid = null; - return this; - } - - public HttpSimpleRequest clearContentType() { - this.contentType = null; - return this; - } - - public boolean isRpc() { - return rpc; - } - - public void setRpc(boolean rpc) { - this.rpc = rpc; - } - - public String getRequestURI() { - return requestURI; - } - - public void setRequestURI(String requestURI) { - this.requestURI = requestURI; - } - - public String getPath() { - return path; - } - - public void setPath(String path) { - this.path = path; - } - - public String getSessionid() { - return sessionid; - } - - public void setSessionid(String sessionid) { - this.sessionid = sessionid; - } - - public String getRemoteAddr() { - return remoteAddr; - } - - public void setRemoteAddr(String remoteAddr) { - this.remoteAddr = remoteAddr; - } - - public int getHashid() { - return hashid; - } - - public void setHashid(int hashid) { - this.hashid = hashid; - } - - public Serializable getCurrentUserid() { - return currentUserid; - } - - public void setCurrentUserid(Serializable currentUserid) { - this.currentUserid = currentUserid; - } - - public String getContentType() { - return contentType; - } - - public void setContentType(String contentType) { - this.contentType = contentType; - } - - public Map getHeaders() { - return headers; - } - - public void setHeaders(Map headers) { - this.headers = headers; - } - - public Map getParams() { - return params; - } - - public void setParams(Map params) { - this.params = params; - } - - public byte[] getBody() { - return body; - } - - public void setBody(byte[] body) { - this.body = body; - } - - public boolean isFrombody() { - return frombody; - } - - public void setFrombody(boolean frombody) { - this.frombody = frombody; - } - - public ConvertType getReqConvertType() { - return reqConvertType; - } - - public void setReqConvertType(ConvertType reqConvertType) { - this.reqConvertType = reqConvertType; - } - - public ConvertType getRespConvertType() { - return respConvertType; - } - - public void setRespConvertType(ConvertType respConvertType) { - this.respConvertType = respConvertType; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - -} +/* + * 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 java.io.*; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.concurrent.atomic.AtomicBoolean; +import org.redkale.convert.*; +import org.redkale.convert.json.JsonConvert; +import org.redkale.util.*; + +/** + * HttpRequest鐨勭缉鍑忕増, 鍙彁渚涢儴鍒嗗瓧娈 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.1.0 + */ +public class HttpSimpleRequest implements java.io.Serializable { + + @ConvertColumn(index = 1) + @Comment("鏄惁RPC璇锋眰, 璇ョ被閫氬父鏄负RPC鍒涘缓鐨勶紝鏁呴粯璁ゆ槸true") + protected boolean rpc = true; + + @ConvertColumn(index = 2) + @Comment("鏄惁浠巄ody涓幏鍙栧弬鏁帮紝姣斿protobuf鏁版嵁鏍煎紡") + protected boolean frombody; + + @ConvertColumn(index = 3) + @Comment("璇锋眰鍙傛暟鐨凜onvertType") + protected ConvertType reqConvertType; + + @ConvertColumn(index = 4) + @Comment("杈撳嚭缁撴灉鐨凜onvertType") + protected ConvertType respConvertType; + + @ConvertColumn(index = 5) + @Comment("璇锋眰鐨刄RI") + protected String requestURI; + + @ConvertColumn(index = 6) + @Comment("璇锋眰鐨勫墠缂") + protected String path; + + @ConvertColumn(index = 7) + @Comment("瀹㈡埛绔疘P") + protected String remoteAddr; + + @ConvertColumn(index = 8) + @Comment("浼氳瘽ID") + protected String sessionid; + + @ConvertColumn(index = 9) + @Comment("Content-Type") + protected String contentType; + + @ConvertColumn(index = 10) + protected int hashid; + + @ConvertColumn(index = 11) //@since 2.5.0 鐢眎nt鏀规垚Serializable, 鍏蜂綋鏁版嵁绫诲瀷鍙兘鏄痠nt銆乴ong銆丼tring + protected Serializable currentUserid; + + @ConvertColumn(index = 12) + @Comment("http header淇℃伅") + protected Map headers; + + @ConvertColumn(index = 13) + @Comment("鍙傛暟淇℃伅") + protected Map params; + + @ConvertColumn(index = 14) + @Comment("http body淇℃伅") + protected byte[] body; //瀵瑰簲HttpRequest.array + + public static HttpSimpleRequest create(String requestURI) { + return new HttpSimpleRequest().requestURI(requestURI); + } + + public static HttpSimpleRequest create(String requestURI, Object... params) { + HttpSimpleRequest req = new HttpSimpleRequest().requestURI(requestURI); + int len = params.length / 2; + for (int i = 0; i < len; i++) { + req.param(params[i * 2].toString(), params[i * 2 + 1]); + } + return req; + } + + @ConvertDisabled + public String getParametersToString() { + if (this.params == null || this.params.isEmpty()) return null; + final StringBuilder sb = new StringBuilder(); + AtomicBoolean no2 = new AtomicBoolean(false); + this.params.forEach((n, v) -> { + if (no2.get()) sb.append('&'); + sb.append(n).append('=').append(URLEncoder.encode(v, StandardCharsets.UTF_8)); + no2.set(true); + }); + return sb.toString(); + } + + public HttpSimpleRequest rpc(boolean rpc) { + this.rpc = rpc; + return this; + } + + public HttpSimpleRequest requestURI(String requestURI) { + this.requestURI = requestURI; + return this; + } + + public HttpSimpleRequest path(String path) { + this.path = path; + return this; + } + + public HttpSimpleRequest requestURI(boolean frombody) { + this.frombody = frombody; + return this; + } + + public HttpSimpleRequest frombody(boolean frombody) { + this.frombody = frombody; + return this; + } + + public HttpSimpleRequest bothConvertType(ConvertType convertType) { + this.reqConvertType = convertType; + this.respConvertType = convertType; + return this; + } + + public HttpSimpleRequest reqConvertType(ConvertType reqConvertType) { + this.reqConvertType = reqConvertType; + return this; + } + + public HttpSimpleRequest respConvertType(ConvertType respConvertType) { + this.respConvertType = respConvertType; + return this; + } + + public HttpSimpleRequest remoteAddr(String remoteAddr) { + this.remoteAddr = remoteAddr; + return this; + } + + public HttpSimpleRequest sessionid(String sessionid) { + this.sessionid = sessionid; + return this; + } + + public HttpSimpleRequest contentType(String contentType) { + this.contentType = contentType; + return this; + } + + public HttpSimpleRequest hashid(int hashid) { + this.hashid = hashid; + return this; + } + + public HttpSimpleRequest currentUserid(Serializable userid) { + this.currentUserid = userid; + return this; + } + + public HttpSimpleRequest removeHeader(String name) { + if (this.headers != null) this.headers.remove(name); + return this; + } + + public HttpSimpleRequest removeParam(String name) { + if (this.params != null) this.params.remove(name); + return this; + } + + public HttpSimpleRequest headers(Map headers) { + this.headers = headers; + return this; + } + + public HttpSimpleRequest params(Map params) { + this.params = params; + return this; + } + + public HttpSimpleRequest header(String key, String value) { + if (this.headers == null) this.headers = new HashMap<>(); + this.headers.put(key, value); + return this; + } + + public HttpSimpleRequest header(String key, JsonConvert convert, Object value) { + if (value == null) return this; + if (this.headers == null) this.headers = new HashMap<>(); + if (convert == null) convert = JsonConvert.root(); + this.headers.put(key, convert.convertTo(value)); + return this; + } + + public HttpSimpleRequest header(String key, Object value) { + if (value == null) return this; + if (this.headers == null) this.headers = new HashMap<>(); + this.headers.put(key, JsonConvert.root().convertTo(value)); + return this; + } + + public HttpSimpleRequest header(String key, int value) { + if (this.headers == null) this.headers = new HashMap<>(); + this.headers.put(key, String.valueOf(value)); + return this; + } + + public HttpSimpleRequest header(String key, long value) { + if (this.headers == null) this.headers = new HashMap<>(); + this.headers.put(key, String.valueOf(value)); + return this; + } + + public HttpSimpleRequest param(String key, String value) { + if (this.params == null) this.params = new HashMap<>(); + this.params.put(key, value); + return this; + } + + public HttpSimpleRequest param(String key, JsonConvert convert, Object value) { + if (value == null) return this; + if (this.params == null) this.params = new HashMap<>(); + if (convert == null) convert = JsonConvert.root(); + this.params.put(key, convert.convertTo(value)); + return this; + } + + public HttpSimpleRequest param(String key, Object value) { + if (value == null) return this; + if (this.params == null) this.params = new HashMap<>(); + this.params.put(key, value instanceof CharSequence ? value.toString() : JsonConvert.root().convertTo(value)); + return this; + } + + public HttpSimpleRequest body(byte[] body) { + this.body = body; + return this; + } + + public HttpSimpleRequest clearParams() { + this.params = null; + return this; + } + + public HttpSimpleRequest clearHeaders() { + this.headers = null; + return this; + } + + public HttpSimpleRequest clearRemoteAddr() { + this.remoteAddr = null; + return this; + } + + public HttpSimpleRequest clearSessionid() { + this.sessionid = null; + return this; + } + + public HttpSimpleRequest clearContentType() { + this.contentType = null; + return this; + } + + public boolean isRpc() { + return rpc; + } + + public void setRpc(boolean rpc) { + this.rpc = rpc; + } + + public String getRequestURI() { + return requestURI; + } + + public void setRequestURI(String requestURI) { + this.requestURI = requestURI; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public String getSessionid() { + return sessionid; + } + + public void setSessionid(String sessionid) { + this.sessionid = sessionid; + } + + public String getRemoteAddr() { + return remoteAddr; + } + + public void setRemoteAddr(String remoteAddr) { + this.remoteAddr = remoteAddr; + } + + public int getHashid() { + return hashid; + } + + public void setHashid(int hashid) { + this.hashid = hashid; + } + + public Serializable getCurrentUserid() { + return currentUserid; + } + + public void setCurrentUserid(Serializable currentUserid) { + this.currentUserid = currentUserid; + } + + public String getContentType() { + return contentType; + } + + public void setContentType(String contentType) { + this.contentType = contentType; + } + + public Map getHeaders() { + return headers; + } + + public void setHeaders(Map headers) { + this.headers = headers; + } + + public Map getParams() { + return params; + } + + public void setParams(Map params) { + this.params = params; + } + + public byte[] getBody() { + return body; + } + + public void setBody(byte[] body) { + this.body = body; + } + + public boolean isFrombody() { + return frombody; + } + + public void setFrombody(boolean frombody) { + this.frombody = frombody; + } + + public ConvertType getReqConvertType() { + return reqConvertType; + } + + public void setReqConvertType(ConvertType reqConvertType) { + this.reqConvertType = reqConvertType; + } + + public ConvertType getRespConvertType() { + return respConvertType; + } + + public void setRespConvertType(ConvertType respConvertType) { + this.respConvertType = respConvertType; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + +} diff --git a/src/main/java/org/redkale/net/http/HttpUserType.java b/src/main/java/org/redkale/net/http/HttpUserType.java index b39d27c30..f1579495e 100644 --- a/src/main/java/org/redkale/net/http/HttpUserType.java +++ b/src/main/java/org/redkale/net/http/HttpUserType.java @@ -1,30 +1,30 @@ -/* - * 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 static java.lang.annotation.ElementType.*; -import java.lang.annotation.*; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * 閰嶅悎 HttpServlet 浣跨敤銆 - * 鐢ㄤ簬鎸囧畾HttpRequest.currentUser鐨勬暟鎹被鍨嬨
- * 娉ㄦ剰锛 鏁版嵁绫诲瀷鏄疛avaBean锛 涓嶈兘鏄熀鏈暟鎹被鍨嬨丼tring銆乥yte[]銆丗ile绛塉ava鍐呯疆鐨勬暟鎹被鍨 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@Inherited -@Documented -@Target({TYPE}) -@Retention(RUNTIME) -public @interface HttpUserType { - - Class value(); - -} +/* + * 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 static java.lang.annotation.ElementType.*; +import java.lang.annotation.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * 閰嶅悎 HttpServlet 浣跨敤銆 + * 鐢ㄤ簬鎸囧畾HttpRequest.currentUser鐨勬暟鎹被鍨嬨
+ * 娉ㄦ剰锛 鏁版嵁绫诲瀷鏄疛avaBean锛 涓嶈兘鏄熀鏈暟鎹被鍨嬨丼tring銆乥yte[]銆丗ile绛塉ava鍐呯疆鐨勬暟鎹被鍨 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@Inherited +@Documented +@Target({TYPE}) +@Retention(RUNTIME) +public @interface HttpUserType { + + Class value(); + +} diff --git a/src/main/java/org/redkale/net/http/MimeType.java b/src/main/java/org/redkale/net/http/MimeType.java index 073034c34..04140dd42 100644 --- a/src/main/java/org/redkale/net/http/MimeType.java +++ b/src/main/java/org/redkale/net/http/MimeType.java @@ -1,206 +1,206 @@ -/* - * 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 java.util.*; - -/** - * MimeType - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public class MimeType { - - private final static Map contentTypes = new HashMap<>(); - - static { - contentTypes.put("abs", "audio/x-mpeg"); - contentTypes.put("ai", "application/postscript"); - contentTypes.put("aif", "audio/x-aiff"); - contentTypes.put("aifc", "audio/x-aiff"); - contentTypes.put("aiff", "audio/x-aiff"); - contentTypes.put("aim", "application/x-aim"); - contentTypes.put("art", "image/x-jg"); - contentTypes.put("asf", "video/x-ms-asf"); - contentTypes.put("asx", "video/x-ms-asf"); - contentTypes.put("au", "audio/basic"); - contentTypes.put("avi", "video/x-msvideo"); - contentTypes.put("avx", "video/x-rad-screenplay"); - contentTypes.put("bcpio", "application/x-bcpio"); - contentTypes.put("bin", "application/octet-stream"); - contentTypes.put("bmp", "image/bmp"); - contentTypes.put("body", "text/html"); - contentTypes.put("cdf", "application/x-cdf"); - contentTypes.put("cer", "application/x-x509-ca-cert"); - contentTypes.put("class", "application/java"); - contentTypes.put("cpio", "application/x-cpio"); - contentTypes.put("csh", "application/x-csh"); - contentTypes.put("css", "text/css"); - contentTypes.put("dib", "image/bmp"); - contentTypes.put("doc", "application/msword"); - contentTypes.put("dtd", "application/xml-dtd"); - contentTypes.put("dv", "video/x-dv"); - contentTypes.put("dvi", "application/x-dvi"); - contentTypes.put("eps", "application/postscript"); - contentTypes.put("etx", "text/x-setext"); - contentTypes.put("exe", "application/octet-stream"); - contentTypes.put("gif", "image/gif"); - contentTypes.put("gk", "application/octet-stream"); - contentTypes.put("gtar", "application/x-gtar"); - contentTypes.put("gz", "application/x-gzip"); - contentTypes.put("hdf", "application/x-hdf"); - contentTypes.put("hqx", "application/mac-binhex40"); - contentTypes.put("htc", "text/x-component"); - contentTypes.put("htm", "text/html"); - contentTypes.put("html", "text/html"); - contentTypes.put("hqx", "application/mac-binhex40"); - contentTypes.put("ico", "image/x-icon"); - contentTypes.put("ief", "image/ief"); - contentTypes.put("jad", "text/vnd.sun.j2me.app-descriptor"); - contentTypes.put("jar", "application/java-archive"); - contentTypes.put("java", "text/plain"); - contentTypes.put("jnlp", "application/x-java-jnlp-file"); - contentTypes.put("jpe", "image/jpeg"); - contentTypes.put("jpeg", "image/jpeg"); - contentTypes.put("jpg", "image/jpeg"); - contentTypes.put("js", "text/javascript"); - contentTypes.put("json", "application/json"); - contentTypes.put("kar", "audio/x-midi"); - contentTypes.put("latex", "application/x-latex"); - contentTypes.put("log", "text/plain"); - contentTypes.put("m3u", "audio/x-mpegurl"); - contentTypes.put("mac", "image/x-macpaint"); - contentTypes.put("man", "application/x-troff-man"); - contentTypes.put("manifest", "text/cache-manifest"); - contentTypes.put("mathml", "application/mathml+xml"); - contentTypes.put("me", "application/x-troff-me"); - contentTypes.put("mid", "audio/x-midi"); - contentTypes.put("midi", "audio/x-midi"); - contentTypes.put("mif", "application/x-mif"); - contentTypes.put("mov", "video/quicktime"); - contentTypes.put("movie", "video/x-sgi-movie"); - contentTypes.put("mp1", "audio/x-mpeg"); - contentTypes.put("mp2", "audio/x-mpeg"); - contentTypes.put("mp3", "audio/x-mpeg"); - contentTypes.put("mpa", "audio/x-mpeg"); - contentTypes.put("mp4", "video/mp4"); - contentTypes.put("ogv", "video/ogv"); - contentTypes.put("webm", "video/webm"); - contentTypes.put("flv", "video/x-flv"); - contentTypes.put("mpe", "video/mpeg"); - contentTypes.put("mpeg", "video/mpeg"); - contentTypes.put("mpega", "audio/x-mpeg"); - contentTypes.put("mpg", "video/mpeg"); - contentTypes.put("mpv2", "video/mpeg2"); - contentTypes.put("ms", "application/x-wais-source"); - contentTypes.put("nc", "application/x-netcdf"); - contentTypes.put("oda", "application/oda"); - contentTypes.put("ogg", "application/ogg"); - contentTypes.put("out", "text/plain"); - contentTypes.put("pac", "application/x-javascript-config"); - contentTypes.put("pbm", "image/x-portable-bitmap"); - contentTypes.put("pct", "image/pict"); - contentTypes.put("pdf", "application/pdf"); - contentTypes.put("pgm", "image/x-portable-graymap"); - contentTypes.put("pic", "image/pict"); - contentTypes.put("pict", "image/pict"); - contentTypes.put("pls", "audio/x-scpls"); - contentTypes.put("png", "image/png"); - contentTypes.put("pnm", "image/x-portable-anymap"); - contentTypes.put("pnt", "image/x-macpaint"); - contentTypes.put("ppm", "image/x-portable-pixmap"); - contentTypes.put("ppt", "application/powerpoint"); - contentTypes.put("ps", "application/postscript"); - contentTypes.put("psd", "image/x-photoshop"); - contentTypes.put("qt", "video/quicktime"); - contentTypes.put("qti", "image/x-quicktime"); - contentTypes.put("qtif", "image/x-quicktime"); - contentTypes.put("ras", "image/x-cmu-raster"); - contentTypes.put("rdf", "application/rdf+xml"); - contentTypes.put("rgb", "image/x-rgb"); - contentTypes.put("rm", "application/vnd.rn-realmedia"); - contentTypes.put("roff", "application/x-troff"); - contentTypes.put("rtf", "application/rtf"); - contentTypes.put("rtx", "text/richtext"); - contentTypes.put("sh", "application/x-sh"); - contentTypes.put("shar", "application/x-shar"); - contentTypes.put("shtml", "text/x-server-parsed-html"); - contentTypes.put("sit", "application/x-stuffit"); - contentTypes.put("smf", "audio/x-midi"); - contentTypes.put("snd", "audio/basic"); - contentTypes.put("src", "application/x-wais-source"); - contentTypes.put("sv4cpio", "application/x-sv4cpio"); - contentTypes.put("sv4crc", "application/x-sv4crc"); - contentTypes.put("svg", "image/svg+xml"); - contentTypes.put("svgz", "image/svg+xml"); - contentTypes.put("swf", "application/x-shockwave-flash"); - contentTypes.put("t", "application/x-troff"); - contentTypes.put("tar", "application/x-tar"); - contentTypes.put("tcl", "application/x-tcl"); - contentTypes.put("tex", "application/x-tex"); - contentTypes.put("texi", "application/x-texinfo"); - contentTypes.put("texinfo", "application/x-texinfo"); - contentTypes.put("tif", "image/tiff"); - contentTypes.put("tiff", "image/tiff"); - contentTypes.put("tr", "application/x-troff"); - contentTypes.put("tsv", "text/tab-separated-values"); - contentTypes.put("txt", "text/plain"); - contentTypes.put("ulw", "audio/basic"); - contentTypes.put("ustar", "application/x-ustar"); - contentTypes.put("xbm", "image/x-xbitmap"); - contentTypes.put("xml", "application/xml"); - contentTypes.put("xpm", "image/x-xpixmap"); - contentTypes.put("xsl", "application/xml"); - contentTypes.put("xslt", "application/xslt+xml"); - contentTypes.put("xwd", "image/x-xwindowdump"); - contentTypes.put("vsd", "application/x-visio"); - contentTypes.put("vxml", "application/voicexml+xml"); - contentTypes.put("wav", "audio/x-wav"); - contentTypes.put("wbmp", "image/vnd.wap.wbmp"); - contentTypes.put("wml", "text/vnd.wap.wml"); - contentTypes.put("wmlc", "application/vnd.wap.wmlc"); - contentTypes.put("wmls", "text/vnd.wap.wmls"); - contentTypes.put("wmlscriptc", "application/vnd.wap.wmlscriptc"); - contentTypes.put("wrl", "x-world/x-vrml"); - contentTypes.put("xht", "application/xhtml+xml"); - contentTypes.put("xhtml", "application/xhtml+xml"); - contentTypes.put("xls", "application/vnd.ms-excel"); - contentTypes.put("xul", "application/vnd.mozilla.xul+xml"); - contentTypes.put("Z", "application/x-compress"); - contentTypes.put("z", "application/x-compress"); - contentTypes.put("zip", "application/zip"); - } - - public static String get(String extension) { - return contentTypes.getOrDefault(extension.toLowerCase(), "text/plain"); - } - - public static String get(String extension, String defaultCt) { - return contentTypes.getOrDefault(extension.toLowerCase(), defaultCt); - } - - public static boolean contains(String extension) { - return contentTypes.containsKey(extension.toLowerCase()); - } - - public static void add(String extension, String contentType) { - if (extension != null && extension.length() != 0 && contentType != null && contentType.length() != 0) { - contentTypes.put(extension.toLowerCase(), contentType); - } - } - - public static String getByFilename(String fileName) { - int length = fileName.length(); - int newEnd = fileName.lastIndexOf('#'); - if (newEnd == -1) newEnd = length; - int i = fileName.lastIndexOf('.', newEnd); - return (i < 0) ? null : get(fileName.substring(i + 1, newEnd).toLowerCase()); - } - -} +/* + * 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 java.util.*; + +/** + * MimeType + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public class MimeType { + + private final static Map contentTypes = new HashMap<>(); + + static { + contentTypes.put("abs", "audio/x-mpeg"); + contentTypes.put("ai", "application/postscript"); + contentTypes.put("aif", "audio/x-aiff"); + contentTypes.put("aifc", "audio/x-aiff"); + contentTypes.put("aiff", "audio/x-aiff"); + contentTypes.put("aim", "application/x-aim"); + contentTypes.put("art", "image/x-jg"); + contentTypes.put("asf", "video/x-ms-asf"); + contentTypes.put("asx", "video/x-ms-asf"); + contentTypes.put("au", "audio/basic"); + contentTypes.put("avi", "video/x-msvideo"); + contentTypes.put("avx", "video/x-rad-screenplay"); + contentTypes.put("bcpio", "application/x-bcpio"); + contentTypes.put("bin", "application/octet-stream"); + contentTypes.put("bmp", "image/bmp"); + contentTypes.put("body", "text/html"); + contentTypes.put("cdf", "application/x-cdf"); + contentTypes.put("cer", "application/x-x509-ca-cert"); + contentTypes.put("class", "application/java"); + contentTypes.put("cpio", "application/x-cpio"); + contentTypes.put("csh", "application/x-csh"); + contentTypes.put("css", "text/css"); + contentTypes.put("dib", "image/bmp"); + contentTypes.put("doc", "application/msword"); + contentTypes.put("dtd", "application/xml-dtd"); + contentTypes.put("dv", "video/x-dv"); + contentTypes.put("dvi", "application/x-dvi"); + contentTypes.put("eps", "application/postscript"); + contentTypes.put("etx", "text/x-setext"); + contentTypes.put("exe", "application/octet-stream"); + contentTypes.put("gif", "image/gif"); + contentTypes.put("gk", "application/octet-stream"); + contentTypes.put("gtar", "application/x-gtar"); + contentTypes.put("gz", "application/x-gzip"); + contentTypes.put("hdf", "application/x-hdf"); + contentTypes.put("hqx", "application/mac-binhex40"); + contentTypes.put("htc", "text/x-component"); + contentTypes.put("htm", "text/html"); + contentTypes.put("html", "text/html"); + contentTypes.put("hqx", "application/mac-binhex40"); + contentTypes.put("ico", "image/x-icon"); + contentTypes.put("ief", "image/ief"); + contentTypes.put("jad", "text/vnd.sun.j2me.app-descriptor"); + contentTypes.put("jar", "application/java-archive"); + contentTypes.put("java", "text/plain"); + contentTypes.put("jnlp", "application/x-java-jnlp-file"); + contentTypes.put("jpe", "image/jpeg"); + contentTypes.put("jpeg", "image/jpeg"); + contentTypes.put("jpg", "image/jpeg"); + contentTypes.put("js", "text/javascript"); + contentTypes.put("json", "application/json"); + contentTypes.put("kar", "audio/x-midi"); + contentTypes.put("latex", "application/x-latex"); + contentTypes.put("log", "text/plain"); + contentTypes.put("m3u", "audio/x-mpegurl"); + contentTypes.put("mac", "image/x-macpaint"); + contentTypes.put("man", "application/x-troff-man"); + contentTypes.put("manifest", "text/cache-manifest"); + contentTypes.put("mathml", "application/mathml+xml"); + contentTypes.put("me", "application/x-troff-me"); + contentTypes.put("mid", "audio/x-midi"); + contentTypes.put("midi", "audio/x-midi"); + contentTypes.put("mif", "application/x-mif"); + contentTypes.put("mov", "video/quicktime"); + contentTypes.put("movie", "video/x-sgi-movie"); + contentTypes.put("mp1", "audio/x-mpeg"); + contentTypes.put("mp2", "audio/x-mpeg"); + contentTypes.put("mp3", "audio/x-mpeg"); + contentTypes.put("mpa", "audio/x-mpeg"); + contentTypes.put("mp4", "video/mp4"); + contentTypes.put("ogv", "video/ogv"); + contentTypes.put("webm", "video/webm"); + contentTypes.put("flv", "video/x-flv"); + contentTypes.put("mpe", "video/mpeg"); + contentTypes.put("mpeg", "video/mpeg"); + contentTypes.put("mpega", "audio/x-mpeg"); + contentTypes.put("mpg", "video/mpeg"); + contentTypes.put("mpv2", "video/mpeg2"); + contentTypes.put("ms", "application/x-wais-source"); + contentTypes.put("nc", "application/x-netcdf"); + contentTypes.put("oda", "application/oda"); + contentTypes.put("ogg", "application/ogg"); + contentTypes.put("out", "text/plain"); + contentTypes.put("pac", "application/x-javascript-config"); + contentTypes.put("pbm", "image/x-portable-bitmap"); + contentTypes.put("pct", "image/pict"); + contentTypes.put("pdf", "application/pdf"); + contentTypes.put("pgm", "image/x-portable-graymap"); + contentTypes.put("pic", "image/pict"); + contentTypes.put("pict", "image/pict"); + contentTypes.put("pls", "audio/x-scpls"); + contentTypes.put("png", "image/png"); + contentTypes.put("pnm", "image/x-portable-anymap"); + contentTypes.put("pnt", "image/x-macpaint"); + contentTypes.put("ppm", "image/x-portable-pixmap"); + contentTypes.put("ppt", "application/powerpoint"); + contentTypes.put("ps", "application/postscript"); + contentTypes.put("psd", "image/x-photoshop"); + contentTypes.put("qt", "video/quicktime"); + contentTypes.put("qti", "image/x-quicktime"); + contentTypes.put("qtif", "image/x-quicktime"); + contentTypes.put("ras", "image/x-cmu-raster"); + contentTypes.put("rdf", "application/rdf+xml"); + contentTypes.put("rgb", "image/x-rgb"); + contentTypes.put("rm", "application/vnd.rn-realmedia"); + contentTypes.put("roff", "application/x-troff"); + contentTypes.put("rtf", "application/rtf"); + contentTypes.put("rtx", "text/richtext"); + contentTypes.put("sh", "application/x-sh"); + contentTypes.put("shar", "application/x-shar"); + contentTypes.put("shtml", "text/x-server-parsed-html"); + contentTypes.put("sit", "application/x-stuffit"); + contentTypes.put("smf", "audio/x-midi"); + contentTypes.put("snd", "audio/basic"); + contentTypes.put("src", "application/x-wais-source"); + contentTypes.put("sv4cpio", "application/x-sv4cpio"); + contentTypes.put("sv4crc", "application/x-sv4crc"); + contentTypes.put("svg", "image/svg+xml"); + contentTypes.put("svgz", "image/svg+xml"); + contentTypes.put("swf", "application/x-shockwave-flash"); + contentTypes.put("t", "application/x-troff"); + contentTypes.put("tar", "application/x-tar"); + contentTypes.put("tcl", "application/x-tcl"); + contentTypes.put("tex", "application/x-tex"); + contentTypes.put("texi", "application/x-texinfo"); + contentTypes.put("texinfo", "application/x-texinfo"); + contentTypes.put("tif", "image/tiff"); + contentTypes.put("tiff", "image/tiff"); + contentTypes.put("tr", "application/x-troff"); + contentTypes.put("tsv", "text/tab-separated-values"); + contentTypes.put("txt", "text/plain"); + contentTypes.put("ulw", "audio/basic"); + contentTypes.put("ustar", "application/x-ustar"); + contentTypes.put("xbm", "image/x-xbitmap"); + contentTypes.put("xml", "application/xml"); + contentTypes.put("xpm", "image/x-xpixmap"); + contentTypes.put("xsl", "application/xml"); + contentTypes.put("xslt", "application/xslt+xml"); + contentTypes.put("xwd", "image/x-xwindowdump"); + contentTypes.put("vsd", "application/x-visio"); + contentTypes.put("vxml", "application/voicexml+xml"); + contentTypes.put("wav", "audio/x-wav"); + contentTypes.put("wbmp", "image/vnd.wap.wbmp"); + contentTypes.put("wml", "text/vnd.wap.wml"); + contentTypes.put("wmlc", "application/vnd.wap.wmlc"); + contentTypes.put("wmls", "text/vnd.wap.wmls"); + contentTypes.put("wmlscriptc", "application/vnd.wap.wmlscriptc"); + contentTypes.put("wrl", "x-world/x-vrml"); + contentTypes.put("xht", "application/xhtml+xml"); + contentTypes.put("xhtml", "application/xhtml+xml"); + contentTypes.put("xls", "application/vnd.ms-excel"); + contentTypes.put("xul", "application/vnd.mozilla.xul+xml"); + contentTypes.put("Z", "application/x-compress"); + contentTypes.put("z", "application/x-compress"); + contentTypes.put("zip", "application/zip"); + } + + public static String get(String extension) { + return contentTypes.getOrDefault(extension.toLowerCase(), "text/plain"); + } + + public static String get(String extension, String defaultCt) { + return contentTypes.getOrDefault(extension.toLowerCase(), defaultCt); + } + + public static boolean contains(String extension) { + return contentTypes.containsKey(extension.toLowerCase()); + } + + public static void add(String extension, String contentType) { + if (extension != null && extension.length() != 0 && contentType != null && contentType.length() != 0) { + contentTypes.put(extension.toLowerCase(), contentType); + } + } + + public static String getByFilename(String fileName) { + int length = fileName.length(); + int newEnd = fileName.lastIndexOf('#'); + if (newEnd == -1) newEnd = length; + int i = fileName.lastIndexOf('.', newEnd); + return (i < 0) ? null : get(fileName.substring(i + 1, newEnd).toLowerCase()); + } + +} diff --git a/src/main/java/org/redkale/net/http/MultiContext.java b/src/main/java/org/redkale/net/http/MultiContext.java index 9e625f06c..fe3b5bd41 100644 --- a/src/main/java/org/redkale/net/http/MultiContext.java +++ b/src/main/java/org/redkale/net/http/MultiContext.java @@ -1,368 +1,368 @@ -/* - * To change this license header, choose License Headers input Project Properties. - * To change this template file, choose Tools | Templates - * and open the template input the editor. - */ -package org.redkale.net.http; - -import org.redkale.util.ByteArray; -import java.io.*; -import java.nio.charset.*; -import java.util.*; -import java.util.concurrent.atomic.*; -import java.util.logging.*; -import java.util.regex.*; - -/** - * HTTP鐨勬枃浠朵笂浼犺姹傜殑涓婁笅鏂囧璞 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public final class MultiContext { - - private static final Logger logger = Logger.getLogger(MultiContext.class.getSimpleName()); - - private final String contentType; - - private final InputStream in; - - private final Charset charset; - - private final String boundary; - - private final byte[] endboundarray; - - private final ByteArray buf = new ByteArray(64); - - private final Map parameters; - - private final Pattern fielnamePattern; - - private static final Iterable emptyIterable = () -> new Iterator() { - - @Override - public boolean hasNext() { - return false; - } - - @Override - public MultiPart next() { - return null; - } - }; - - public MultiContext(final Charset charsetName, final String contentType, final Map params, final InputStream in, String fielnameRegex) { - this.charset = charsetName == null ? StandardCharsets.UTF_8 : charsetName; - this.contentType = contentType == null ? "" : contentType.trim(); - this.parameters = params; - this.boundary = parseBoundary(this.contentType); - this.endboundarray = ("--" + this.boundary + "--").getBytes(); - this.in = in instanceof BufferedInputStream ? in : new BufferedInputStream(in); - this.fielnamePattern = fielnameRegex == null || fielnameRegex.isEmpty() ? null : Pattern.compile(fielnameRegex); - } - - private String parseBoundary(String contentType) { - if (!contentType.startsWith("multipart/")) { - return null; - } - for (String str : contentType.split(";")) { - int pos = str.indexOf("boundary="); - if (pos >= 0) return str.substring(pos + "boundary=".length()).trim(); - } - return null; - } - - /** - * 鍒ゆ柇璇锋眰鏄惁鍖呭惈涓婁紶鏂囦欢 - * - * @return boolean - */ - public boolean isMultipart() { - return this.boundary != null; - } - - //鎴栬 REST 鐢ㄥ埌 - /** - * 鑾峰彇绗竴涓枃浠剁殑浜岃繘鍒 - * - * @param max 鍙帴鏀剁殑鏂囦欢澶у皬鏈澶у - * @param filenameReg 鍙帴鏀剁殑鏂囦欢鍚嶆鍒欒〃杈惧紡 - * @param contentTypeReg 鍙帴鏀剁殑ContentType姝e垯琛ㄨ揪寮 - * - * @return 浜岃繘鍒舵枃浠 - * @throws IOException IOException - */ - public byte[] partsFirstBytes(final long max, final String filenameReg, final String contentTypeReg) throws IOException { - if (!isMultipart()) return null; - byte[] tmpfile = null; - boolean has = false; - for (MultiPart part : parts()) { - if (has) continue;//涓嶉亶鍘嗗畬鍚庨潰getParameter鍙兘鑾峰彇涓嶅埌鍊 - has = true; - if (filenameReg != null && !filenameReg.isEmpty() && !part.getFilename().matches(filenameReg)) continue; - if (contentTypeReg != null && !contentTypeReg.isEmpty() && !part.getContentType().matches(contentTypeReg)) continue; - tmpfile = part.getContentBytes(max < 1 ? Long.MAX_VALUE : max); - } - return tmpfile; - } - - /** - * 鏍规嵁涓存椂鏂囦欢鑾峰彇涓婁紶鏃剁殑鏂囦欢鍚 - * - * @param file 涓存椂鏂囦欢 - * - * @return 涓婁紶鐨勬枃浠跺悕 - */ - public static String getFileName(File file) { - if (file == null) return null; - String name = file.getName(); - return name.startsWith("redkale-") ? name.substring(name.indexOf('_') + 1) : name; - } - - //鎴栬 REST 鐢ㄥ埌 - /** - * 鑾峰彇绗竴涓枃浠 - * - * @param home 杩涚▼鐩綍 - * @param max 鍙帴鏀剁殑鏂囦欢澶у皬鏈澶у - * @param filenameReg 鍙帴鏀剁殑鏂囦欢鍚嶆鍒欒〃杈惧紡 - * @param contentTypeReg 鍙帴鏀剁殑ContentType姝e垯琛ㄨ揪寮 - * - * @return 鏂囦欢 - * @throws IOException IOException - */ - public File partsFirstFile(final File home, final long max, final String filenameReg, final String contentTypeReg) throws IOException { - if (!isMultipart()) return null; - File tmpfile = null; - boolean has = false; - for (MultiPart part : parts()) { - if (has) continue; //涓嶉亶鍘嗗畬鍚庨潰getParameter鍙兘鑾峰彇涓嶅埌鍊 - has = true; - if (filenameReg != null && !filenameReg.isEmpty() && !part.getFilename().matches(filenameReg)) continue; - if (contentTypeReg != null && !contentTypeReg.isEmpty() && !part.getContentType().matches(contentTypeReg)) continue; - File file = new File(home, "tmp/redkale-" + System.nanoTime() + "_" + part.getFilename()); - File parent = file.getParentFile(); - if (!parent.isDirectory()) parent.mkdirs(); - boolean rs = part.save(max < 1 ? Long.MAX_VALUE : max, file); - if (!rs) { - file.delete(); - parent.delete(); - } else { - tmpfile = file; - } - } - return tmpfile; - } - - //鎴栬 REST 鐢ㄥ埌 - /** - * 鑾峰彇鎵鏈夋枃浠 - * - * @param home 杩涚▼鐩綍 - * @param max 鍙帴鏀剁殑鏂囦欢澶у皬鏈澶у - * @param filenameReg 鍙帴鏀剁殑鏂囦欢鍚嶆鍒欒〃杈惧紡 - * @param contentTypeReg 鍙帴鏀剁殑ContentType姝e垯琛ㄨ揪寮 - * - * @return 鏂囦欢鍒楄〃 - * @throws IOException IOException - */ - public File[] partsFiles(final File home, final long max, final String filenameReg, final String contentTypeReg) throws IOException { - if (!isMultipart()) return null; - List files = null; - for (MultiPart part : parts()) { - if (filenameReg != null && !filenameReg.isEmpty() && !part.getFilename().matches(filenameReg)) continue; - if (contentTypeReg != null && !contentTypeReg.isEmpty() && !part.getContentType().matches(contentTypeReg)) continue; - File file = new File(home, "tmp/redkale-" + System.nanoTime() + "_" + part.getFilename()); - File parent = file.getParentFile(); - if (!parent.isDirectory()) parent.mkdirs(); - boolean rs = part.save(max < 1 ? Long.MAX_VALUE : max, file); - if (!rs) { - file.delete(); - parent.delete(); - continue; - } - if (files == null) files = new ArrayList<>(); - files.add(file); - } - return files == null ? null : files.toArray(new File[files.size()]); - } - - /** - * 鑾峰彇涓婁紶鏂囦欢淇℃伅鍒楄〃 - * - * @return Iterable - * @throws IOException IOException - */ - public Iterable parts() throws IOException { - if (!isMultipart()) return emptyIterable; - final String boundarystr = "--" + this.boundary; - final Pattern fielnameReg = this.fielnamePattern; - final String endboundary = boundarystr + "--"; - final byte[] boundarray = ("\n" + boundarystr).getBytes(); - final byte[] buffer = new byte[boundarray.length]; - final InputStream input = this.in; - final Map params = this.parameters; - final AtomicBoolean finaled = new AtomicBoolean(false); - return () -> new Iterator() { - - private String boundaryline; - - private MultiPart lastentry; - - @Override - public boolean hasNext() { - try { - if (lastentry != null) { - lastentry.skip(); - if (finaled.get()) return false; - } - if (boundaryline == null) boundaryline = readBoundary(); - //if (debug) System.out.print("boundaryline=" + boundaryline + " "); - if (endboundary.equals(boundaryline) || !boundarystr.equals(boundaryline)) { //缁撳熬鎴栧紓甯 - lastentry = null; - return false; - } - final String disposition = readLine(); - //if (debug) System.out.println("disposition=" + disposition); - if (disposition.contains("; filename=\"")) { //鏄笂浼犳枃浠 - String contentType = ""; - //璇绘帀HTTP Header鍜岀┖鐧借 閫氬父鎯呭喌涓婥ontent-Type鍚庨潰灏辨槸鍐呭锛屼絾鏄湁浜涚壒娈婃儏鍐典笅鍚庨潰浼氳窡鍏朵粬濡侰ontent-Length: xxx绛塇TTP header锛屾墍浠ラ渶瑕佸惊鐜鍙 - String rl; - while (!(rl = readLine()).isEmpty()) { - if (rl.startsWith("Content-Type:") || rl.startsWith("content-type:")) contentType = rl.substring(rl.indexOf(':') + 1).trim(); - } - //if (debug) System.out.println("file.contentType=" + contentType); - - String name = parseValue(disposition, "name"); - String filename = parseValue(disposition, "filename"); - if (filename == null || filename.isEmpty()) { //娌℃湁涓婁紶 - readLine(); //璇绘帀绌虹櫧琛 - this.boundaryline = null; - this.lastentry = null; - return this.hasNext(); - } else { - int p1 = filename.lastIndexOf('/'); - if (p1 < 0) p1 = filename.lastIndexOf('\\'); - if (p1 >= 0) filename = filename.substring(p1 + 1); - } - final LongAdder counter = new LongAdder(); - InputStream source = new InputStream() { - - private int bufposition = buffer.length; - - private boolean end; - - @Override - public int read() throws IOException { - if (end) return -1; - final byte[] buf = buffer; - int ch = (this.bufposition < buf.length) ? (buf[this.bufposition++] & 0xff) : input.read(); - if ((ch == '\r' && readBuffer())) return -1; - counter.increment(); - return ch; - } - - private boolean readBuffer() throws IOException { - final byte[] buf = buffer; - final int pos = this.bufposition; - int s = 0; - for (int i = pos; i < buf.length; i++) { - buf[s++] = buf[i]; - } - int readed = 0; - int t = 0; - while ((t = input.read(buf, s + readed, pos - readed)) > 0) { - readed += t; - if (readed == pos) break; - } - this.bufposition = 0; - if (Arrays.equals(boundarray, buf)) { - this.end = true; - int c1 = input.read(); - int c2 = input.read(); - finaled.set(c1 == '-' && c2 == '-'); - return true; - } - return false; - } - - @Override - public long skip(long count) throws IOException { - if (end) return -1; - if (count <= 0) return 0; - long s = 0; - while (read() != -1) { - s++; - if (--count <= 0) break; - } - return s; - } - }; - this.lastentry = new MultiPart(filename, name, contentType, counter, source); - if (fielnameReg != null && !fielnameReg.matcher(filename).matches()) { - return this.hasNext(); - } - return true; - } else { //涓嶆槸鏂囦欢 - readLine(); //璇绘帀绌虹櫧 - params.put(parseValue(disposition, "name"), readLine()); - this.boundaryline = null; - this.lastentry = null; - return this.hasNext(); - } - } catch (IOException ex) { - logger.log(Level.FINER, "list multiparts abort", ex); - return false; - } - } - - @Override - public MultiPart next() { - return lastentry; - } - - }; - } - - private String readLine() throws IOException { - return readLine(false); - } - - private String readBoundary() throws IOException { - return readLine(true); - } - - private String readLine(boolean bd) throws IOException { // bd : 鏄惁鏄鍙朾oundary - byte lasted = '\r'; - buf.clear(); - final int bc = this.endboundarray.length; - int c = 0; - for (;;) { - int b = in.read(); - c++; - if (b == -1 || (lasted == '\r' && b == '\n')) break; - if (lasted != '\r') buf.put(lasted); - lasted = (byte) b; - if (bd && bc == c) { - buf.put(lasted); - if (buf.equal(this.endboundarray)) break; - buf.removeLastByte(); - } - } - if (buf.length() == 0) return ""; - return buf.toString(this.charset).trim(); - } - - private static String parseValue(final String str, String name) { - if (str == null) return null; - final String key = "; " + name + "=\""; - int pos = str.indexOf(key); - if (pos < 0) return null; - String sub = str.substring(pos + key.length()); - return sub.substring(0, sub.indexOf('"')); - } - -} +/* + * To change this license header, choose License Headers input Project Properties. + * To change this template file, choose Tools | Templates + * and open the template input the editor. + */ +package org.redkale.net.http; + +import org.redkale.util.ByteArray; +import java.io.*; +import java.nio.charset.*; +import java.util.*; +import java.util.concurrent.atomic.*; +import java.util.logging.*; +import java.util.regex.*; + +/** + * HTTP鐨勬枃浠朵笂浼犺姹傜殑涓婁笅鏂囧璞 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public final class MultiContext { + + private static final Logger logger = Logger.getLogger(MultiContext.class.getSimpleName()); + + private final String contentType; + + private final InputStream in; + + private final Charset charset; + + private final String boundary; + + private final byte[] endboundarray; + + private final ByteArray buf = new ByteArray(64); + + private final Map parameters; + + private final Pattern fielnamePattern; + + private static final Iterable emptyIterable = () -> new Iterator() { + + @Override + public boolean hasNext() { + return false; + } + + @Override + public MultiPart next() { + return null; + } + }; + + public MultiContext(final Charset charsetName, final String contentType, final Map params, final InputStream in, String fielnameRegex) { + this.charset = charsetName == null ? StandardCharsets.UTF_8 : charsetName; + this.contentType = contentType == null ? "" : contentType.trim(); + this.parameters = params; + this.boundary = parseBoundary(this.contentType); + this.endboundarray = ("--" + this.boundary + "--").getBytes(); + this.in = in instanceof BufferedInputStream ? in : new BufferedInputStream(in); + this.fielnamePattern = fielnameRegex == null || fielnameRegex.isEmpty() ? null : Pattern.compile(fielnameRegex); + } + + private String parseBoundary(String contentType) { + if (!contentType.startsWith("multipart/")) { + return null; + } + for (String str : contentType.split(";")) { + int pos = str.indexOf("boundary="); + if (pos >= 0) return str.substring(pos + "boundary=".length()).trim(); + } + return null; + } + + /** + * 鍒ゆ柇璇锋眰鏄惁鍖呭惈涓婁紶鏂囦欢 + * + * @return boolean + */ + public boolean isMultipart() { + return this.boundary != null; + } + + //鎴栬 REST 鐢ㄥ埌 + /** + * 鑾峰彇绗竴涓枃浠剁殑浜岃繘鍒 + * + * @param max 鍙帴鏀剁殑鏂囦欢澶у皬鏈澶у + * @param filenameReg 鍙帴鏀剁殑鏂囦欢鍚嶆鍒欒〃杈惧紡 + * @param contentTypeReg 鍙帴鏀剁殑ContentType姝e垯琛ㄨ揪寮 + * + * @return 浜岃繘鍒舵枃浠 + * @throws IOException IOException + */ + public byte[] partsFirstBytes(final long max, final String filenameReg, final String contentTypeReg) throws IOException { + if (!isMultipart()) return null; + byte[] tmpfile = null; + boolean has = false; + for (MultiPart part : parts()) { + if (has) continue;//涓嶉亶鍘嗗畬鍚庨潰getParameter鍙兘鑾峰彇涓嶅埌鍊 + has = true; + if (filenameReg != null && !filenameReg.isEmpty() && !part.getFilename().matches(filenameReg)) continue; + if (contentTypeReg != null && !contentTypeReg.isEmpty() && !part.getContentType().matches(contentTypeReg)) continue; + tmpfile = part.getContentBytes(max < 1 ? Long.MAX_VALUE : max); + } + return tmpfile; + } + + /** + * 鏍规嵁涓存椂鏂囦欢鑾峰彇涓婁紶鏃剁殑鏂囦欢鍚 + * + * @param file 涓存椂鏂囦欢 + * + * @return 涓婁紶鐨勬枃浠跺悕 + */ + public static String getFileName(File file) { + if (file == null) return null; + String name = file.getName(); + return name.startsWith("redkale-") ? name.substring(name.indexOf('_') + 1) : name; + } + + //鎴栬 REST 鐢ㄥ埌 + /** + * 鑾峰彇绗竴涓枃浠 + * + * @param home 杩涚▼鐩綍 + * @param max 鍙帴鏀剁殑鏂囦欢澶у皬鏈澶у + * @param filenameReg 鍙帴鏀剁殑鏂囦欢鍚嶆鍒欒〃杈惧紡 + * @param contentTypeReg 鍙帴鏀剁殑ContentType姝e垯琛ㄨ揪寮 + * + * @return 鏂囦欢 + * @throws IOException IOException + */ + public File partsFirstFile(final File home, final long max, final String filenameReg, final String contentTypeReg) throws IOException { + if (!isMultipart()) return null; + File tmpfile = null; + boolean has = false; + for (MultiPart part : parts()) { + if (has) continue; //涓嶉亶鍘嗗畬鍚庨潰getParameter鍙兘鑾峰彇涓嶅埌鍊 + has = true; + if (filenameReg != null && !filenameReg.isEmpty() && !part.getFilename().matches(filenameReg)) continue; + if (contentTypeReg != null && !contentTypeReg.isEmpty() && !part.getContentType().matches(contentTypeReg)) continue; + File file = new File(home, "tmp/redkale-" + System.nanoTime() + "_" + part.getFilename()); + File parent = file.getParentFile(); + if (!parent.isDirectory()) parent.mkdirs(); + boolean rs = part.save(max < 1 ? Long.MAX_VALUE : max, file); + if (!rs) { + file.delete(); + parent.delete(); + } else { + tmpfile = file; + } + } + return tmpfile; + } + + //鎴栬 REST 鐢ㄥ埌 + /** + * 鑾峰彇鎵鏈夋枃浠 + * + * @param home 杩涚▼鐩綍 + * @param max 鍙帴鏀剁殑鏂囦欢澶у皬鏈澶у + * @param filenameReg 鍙帴鏀剁殑鏂囦欢鍚嶆鍒欒〃杈惧紡 + * @param contentTypeReg 鍙帴鏀剁殑ContentType姝e垯琛ㄨ揪寮 + * + * @return 鏂囦欢鍒楄〃 + * @throws IOException IOException + */ + public File[] partsFiles(final File home, final long max, final String filenameReg, final String contentTypeReg) throws IOException { + if (!isMultipart()) return null; + List files = null; + for (MultiPart part : parts()) { + if (filenameReg != null && !filenameReg.isEmpty() && !part.getFilename().matches(filenameReg)) continue; + if (contentTypeReg != null && !contentTypeReg.isEmpty() && !part.getContentType().matches(contentTypeReg)) continue; + File file = new File(home, "tmp/redkale-" + System.nanoTime() + "_" + part.getFilename()); + File parent = file.getParentFile(); + if (!parent.isDirectory()) parent.mkdirs(); + boolean rs = part.save(max < 1 ? Long.MAX_VALUE : max, file); + if (!rs) { + file.delete(); + parent.delete(); + continue; + } + if (files == null) files = new ArrayList<>(); + files.add(file); + } + return files == null ? null : files.toArray(new File[files.size()]); + } + + /** + * 鑾峰彇涓婁紶鏂囦欢淇℃伅鍒楄〃 + * + * @return Iterable + * @throws IOException IOException + */ + public Iterable parts() throws IOException { + if (!isMultipart()) return emptyIterable; + final String boundarystr = "--" + this.boundary; + final Pattern fielnameReg = this.fielnamePattern; + final String endboundary = boundarystr + "--"; + final byte[] boundarray = ("\n" + boundarystr).getBytes(); + final byte[] buffer = new byte[boundarray.length]; + final InputStream input = this.in; + final Map params = this.parameters; + final AtomicBoolean finaled = new AtomicBoolean(false); + return () -> new Iterator() { + + private String boundaryline; + + private MultiPart lastentry; + + @Override + public boolean hasNext() { + try { + if (lastentry != null) { + lastentry.skip(); + if (finaled.get()) return false; + } + if (boundaryline == null) boundaryline = readBoundary(); + //if (debug) System.out.print("boundaryline=" + boundaryline + " "); + if (endboundary.equals(boundaryline) || !boundarystr.equals(boundaryline)) { //缁撳熬鎴栧紓甯 + lastentry = null; + return false; + } + final String disposition = readLine(); + //if (debug) System.out.println("disposition=" + disposition); + if (disposition.contains("; filename=\"")) { //鏄笂浼犳枃浠 + String contentType = ""; + //璇绘帀HTTP Header鍜岀┖鐧借 閫氬父鎯呭喌涓婥ontent-Type鍚庨潰灏辨槸鍐呭锛屼絾鏄湁浜涚壒娈婃儏鍐典笅鍚庨潰浼氳窡鍏朵粬濡侰ontent-Length: xxx绛塇TTP header锛屾墍浠ラ渶瑕佸惊鐜鍙 + String rl; + while (!(rl = readLine()).isEmpty()) { + if (rl.startsWith("Content-Type:") || rl.startsWith("content-type:")) contentType = rl.substring(rl.indexOf(':') + 1).trim(); + } + //if (debug) System.out.println("file.contentType=" + contentType); + + String name = parseValue(disposition, "name"); + String filename = parseValue(disposition, "filename"); + if (filename == null || filename.isEmpty()) { //娌℃湁涓婁紶 + readLine(); //璇绘帀绌虹櫧琛 + this.boundaryline = null; + this.lastentry = null; + return this.hasNext(); + } else { + int p1 = filename.lastIndexOf('/'); + if (p1 < 0) p1 = filename.lastIndexOf('\\'); + if (p1 >= 0) filename = filename.substring(p1 + 1); + } + final LongAdder counter = new LongAdder(); + InputStream source = new InputStream() { + + private int bufposition = buffer.length; + + private boolean end; + + @Override + public int read() throws IOException { + if (end) return -1; + final byte[] buf = buffer; + int ch = (this.bufposition < buf.length) ? (buf[this.bufposition++] & 0xff) : input.read(); + if ((ch == '\r' && readBuffer())) return -1; + counter.increment(); + return ch; + } + + private boolean readBuffer() throws IOException { + final byte[] buf = buffer; + final int pos = this.bufposition; + int s = 0; + for (int i = pos; i < buf.length; i++) { + buf[s++] = buf[i]; + } + int readed = 0; + int t = 0; + while ((t = input.read(buf, s + readed, pos - readed)) > 0) { + readed += t; + if (readed == pos) break; + } + this.bufposition = 0; + if (Arrays.equals(boundarray, buf)) { + this.end = true; + int c1 = input.read(); + int c2 = input.read(); + finaled.set(c1 == '-' && c2 == '-'); + return true; + } + return false; + } + + @Override + public long skip(long count) throws IOException { + if (end) return -1; + if (count <= 0) return 0; + long s = 0; + while (read() != -1) { + s++; + if (--count <= 0) break; + } + return s; + } + }; + this.lastentry = new MultiPart(filename, name, contentType, counter, source); + if (fielnameReg != null && !fielnameReg.matcher(filename).matches()) { + return this.hasNext(); + } + return true; + } else { //涓嶆槸鏂囦欢 + readLine(); //璇绘帀绌虹櫧 + params.put(parseValue(disposition, "name"), readLine()); + this.boundaryline = null; + this.lastentry = null; + return this.hasNext(); + } + } catch (IOException ex) { + logger.log(Level.FINER, "list multiparts abort", ex); + return false; + } + } + + @Override + public MultiPart next() { + return lastentry; + } + + }; + } + + private String readLine() throws IOException { + return readLine(false); + } + + private String readBoundary() throws IOException { + return readLine(true); + } + + private String readLine(boolean bd) throws IOException { // bd : 鏄惁鏄鍙朾oundary + byte lasted = '\r'; + buf.clear(); + final int bc = this.endboundarray.length; + int c = 0; + for (;;) { + int b = in.read(); + c++; + if (b == -1 || (lasted == '\r' && b == '\n')) break; + if (lasted != '\r') buf.put(lasted); + lasted = (byte) b; + if (bd && bc == c) { + buf.put(lasted); + if (buf.equal(this.endboundarray)) break; + buf.removeLastByte(); + } + } + if (buf.length() == 0) return ""; + return buf.toString(this.charset).trim(); + } + + private static String parseValue(final String str, String name) { + if (str == null) return null; + final String key = "; " + name + "=\""; + int pos = str.indexOf(key); + if (pos < 0) return null; + String sub = str.substring(pos + key.length()); + return sub.substring(0, sub.indexOf('"')); + } + +} diff --git a/src/main/java/org/redkale/net/http/MultiPart.java b/src/main/java/org/redkale/net/http/MultiPart.java index 818db3299..534b1b769 100644 --- a/src/main/java/org/redkale/net/http/MultiPart.java +++ b/src/main/java/org/redkale/net/http/MultiPart.java @@ -1,116 +1,116 @@ -/* - * 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 java.io.*; -import java.util.concurrent.atomic.LongAdder; - -/** - * - *

璇︽儏瑙: https://redkale.org - * @author zhangjx - */ -public final class MultiPart { - - private final String filename; - - private final String name; - - private final String contentType; - - private final InputStream in; - - private final LongAdder received; - - MultiPart(String filename, String name, String contentType, LongAdder received, InputStream in) { - this.filename = filename; - this.name = name; - this.in = in; - this.contentType = contentType; - this.received = received; - } - - @Override - public String toString() { - return this.getClass().getSimpleName() + "{" + "name=" + name + ", filename=" + filename + ", contentType=" + contentType + ", received=" + received + '}'; - } - - public boolean save(File file) throws IOException { - return save(Long.MAX_VALUE, file); - } - - public boolean save(long max, File file) throws IOException { - OutputStream out = new FileOutputStream(file); - boolean rs = save(max, out); - out.close(); - return rs; - } - - public byte[] getContentBytes() throws IOException { - return getContentBytes(Long.MAX_VALUE); - } - - /** - * 灏嗘枃浠舵祦璇昏繘bytes锛 濡傛灉瓒呭嚭max鎸囧畾鐨勫煎垯杩斿洖null - * - * @param max 鏈澶ч暱搴﹂檺鍒 - * @return 鍐呭 - * @throws IOException 寮傚父 - */ - public byte[] getContentBytes(long max) throws IOException { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - return save(max, out) ? out.toByteArray() : null; - } - - public boolean save(OutputStream out) throws IOException { - return save(Long.MAX_VALUE, out); - } - - /** - * 灏嗘枃浠舵祦鍐欒繘out锛 濡傛灉瓒呭嚭max鎸囧畾鐨勫煎垯涓柇骞惰繑鍥瀎alse - * - * @param max 鏈澶ч暱搴﹂檺鍒 - * @param out 杈撳嚭娴 - * @return 鏄惁鎴愬姛 - * @throws IOException 寮傚父 - */ - public boolean save(long max, OutputStream out) throws IOException { - byte[] bytes = new byte[4096]; - int pos; - InputStream in0 = this.getInputStream(); - while ((pos = in0.read(bytes)) != -1) { - if (max < 0) return false; - out.write(bytes, 0, pos); - max -= pos; - } - return true; - } - - public String getContentType() { - return contentType; - } - - public String getFilename() { - return filename; - } - - public String getName() { - return name; - } - - public InputStream getInputStream() { - return in; - } - - public long getReceived() { - return received.longValue(); - } - - public void skip() throws IOException { - in.skip(Long.MAX_VALUE); - } - -} +/* + * 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 java.io.*; +import java.util.concurrent.atomic.LongAdder; + +/** + * + *

璇︽儏瑙: https://redkale.org + * @author zhangjx + */ +public final class MultiPart { + + private final String filename; + + private final String name; + + private final String contentType; + + private final InputStream in; + + private final LongAdder received; + + MultiPart(String filename, String name, String contentType, LongAdder received, InputStream in) { + this.filename = filename; + this.name = name; + this.in = in; + this.contentType = contentType; + this.received = received; + } + + @Override + public String toString() { + return this.getClass().getSimpleName() + "{" + "name=" + name + ", filename=" + filename + ", contentType=" + contentType + ", received=" + received + '}'; + } + + public boolean save(File file) throws IOException { + return save(Long.MAX_VALUE, file); + } + + public boolean save(long max, File file) throws IOException { + OutputStream out = new FileOutputStream(file); + boolean rs = save(max, out); + out.close(); + return rs; + } + + public byte[] getContentBytes() throws IOException { + return getContentBytes(Long.MAX_VALUE); + } + + /** + * 灏嗘枃浠舵祦璇昏繘bytes锛 濡傛灉瓒呭嚭max鎸囧畾鐨勫煎垯杩斿洖null + * + * @param max 鏈澶ч暱搴﹂檺鍒 + * @return 鍐呭 + * @throws IOException 寮傚父 + */ + public byte[] getContentBytes(long max) throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + return save(max, out) ? out.toByteArray() : null; + } + + public boolean save(OutputStream out) throws IOException { + return save(Long.MAX_VALUE, out); + } + + /** + * 灏嗘枃浠舵祦鍐欒繘out锛 濡傛灉瓒呭嚭max鎸囧畾鐨勫煎垯涓柇骞惰繑鍥瀎alse + * + * @param max 鏈澶ч暱搴﹂檺鍒 + * @param out 杈撳嚭娴 + * @return 鏄惁鎴愬姛 + * @throws IOException 寮傚父 + */ + public boolean save(long max, OutputStream out) throws IOException { + byte[] bytes = new byte[4096]; + int pos; + InputStream in0 = this.getInputStream(); + while ((pos = in0.read(bytes)) != -1) { + if (max < 0) return false; + out.write(bytes, 0, pos); + max -= pos; + } + return true; + } + + public String getContentType() { + return contentType; + } + + public String getFilename() { + return filename; + } + + public String getName() { + return name; + } + + public InputStream getInputStream() { + return in; + } + + public long getReceived() { + return received.longValue(); + } + + public void skip() throws IOException { + in.skip(Long.MAX_VALUE); + } + +} diff --git a/src/main/java/org/redkale/net/http/RestAddress.java b/src/main/java/org/redkale/net/http/RestAddress.java index 09127daf9..4530d4570 100644 --- a/src/main/java/org/redkale/net/http/RestAddress.java +++ b/src/main/java/org/redkale/net/http/RestAddress.java @@ -1,34 +1,34 @@ -/* - * 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 java.lang.annotation.*; -import static java.lang.annotation.ElementType.*; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * 鍙兘娉ㄨВ浜嶴ervice绫荤殑鏂规硶鐨凷tring鍙傛暟鎴栧弬鏁板唴鐨凷tring瀛楁 - *

- * 鐢ㄤ簬鑾峰彇HTTP璇锋眰绔殑IP鍦板潃 HttpRequest.getRemoteAddr - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@Inherited -@Documented -@Target({PARAMETER, FIELD}) -@Retention(RUNTIME) -public @interface RestAddress { - - /** - * 澶囨敞鎻忚堪, 瀵瑰簲@HttpParam.comment - * - * @return String - */ - String comment() default ""; -} +/* + * 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 java.lang.annotation.*; +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * 鍙兘娉ㄨВ浜嶴ervice绫荤殑鏂规硶鐨凷tring鍙傛暟鎴栧弬鏁板唴鐨凷tring瀛楁 + *

+ * 鐢ㄤ簬鑾峰彇HTTP璇锋眰绔殑IP鍦板潃 HttpRequest.getRemoteAddr + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@Inherited +@Documented +@Target({PARAMETER, FIELD}) +@Retention(RUNTIME) +public @interface RestAddress { + + /** + * 澶囨敞鎻忚堪, 瀵瑰簲@HttpParam.comment + * + * @return String + */ + String comment() default ""; +} diff --git a/src/main/java/org/redkale/net/http/RestBody.java b/src/main/java/org/redkale/net/http/RestBody.java index 8ab3e1bc4..0dbc85cfb 100644 --- a/src/main/java/org/redkale/net/http/RestBody.java +++ b/src/main/java/org/redkale/net/http/RestBody.java @@ -1,48 +1,48 @@ -/* - * 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 java.lang.annotation.*; -import static java.lang.annotation.ElementType.*; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * 鍙兘娉ㄨВ浜嶳estService绫荤殑鏂规硶鐨凷tring/byte[]/JavaBean鍙傛暟鎴栧弬鏁板唴鐨凷tring/byte[]/JavaBean瀛楁 - *

- * 鐢ㄤ簬鑾峰彇HTTP璇锋眰绔殑璇锋眰鍐呭UTF-8缂栫爜瀛楃涓层乥yte[]銆丣avaBean - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@Inherited -@Documented -@Target({PARAMETER, FIELD}) -@Retention(RUNTIME) -public @interface RestBody { - - /** - * 鍙傛暟鏄惁蹇呬紶, 妗嗘灦杩愯涓笉浣滈獙璇, only for OpenAPI Specification 3 - * - * @return boolean - */ - boolean required() default true; - - /** - * for OpenAPI Specification 3.1.0 - * - * @return String - */ - String example() default ""; - - /** - * 澶囨敞鎻忚堪, 瀵瑰簲@HttpParam.comment - * - * @return String - */ - String comment() default ""; -} +/* + * 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 java.lang.annotation.*; +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * 鍙兘娉ㄨВ浜嶳estService绫荤殑鏂规硶鐨凷tring/byte[]/JavaBean鍙傛暟鎴栧弬鏁板唴鐨凷tring/byte[]/JavaBean瀛楁 + *

+ * 鐢ㄤ簬鑾峰彇HTTP璇锋眰绔殑璇锋眰鍐呭UTF-8缂栫爜瀛楃涓层乥yte[]銆丣avaBean + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@Inherited +@Documented +@Target({PARAMETER, FIELD}) +@Retention(RUNTIME) +public @interface RestBody { + + /** + * 鍙傛暟鏄惁蹇呬紶, 妗嗘灦杩愯涓笉浣滈獙璇, only for OpenAPI Specification 3 + * + * @return boolean + */ + boolean required() default true; + + /** + * for OpenAPI Specification 3.1.0 + * + * @return String + */ + String example() default ""; + + /** + * 澶囨敞鎻忚堪, 瀵瑰簲@HttpParam.comment + * + * @return String + */ + String comment() default ""; +} diff --git a/src/main/java/org/redkale/net/http/RestConvert.java b/src/main/java/org/redkale/net/http/RestConvert.java index 1f4f6d49e..9ed108616 100644 --- a/src/main/java/org/redkale/net/http/RestConvert.java +++ b/src/main/java/org/redkale/net/http/RestConvert.java @@ -1,46 +1,46 @@ -/* - * 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 java.lang.annotation.*; -import static java.lang.annotation.ElementType.*; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * 鍙兘渚濋檮鍦⊿ervice瀹炵幇绫荤殑public鏂规硶涓, 褰撴柟娉曠殑杩斿洖鍊间互JSON杈撳嚭鏃跺鎸囧畾绫诲瀷鐨勮浆鎹㈣瀹氥
- * 娉ㄦ剰: 濡傛灉 type() == void.class 鍒欐棤瑙嗗叾浠栧弬鏁板浐瀹氳繑鍥 JsonFactory.create().skipAllIgnore(true).getConvert(); - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@Inherited -@Documented -@Target({METHOD}) -@Retention(RUNTIME) -@Repeatable(RestConvert.RestConverts.class) -public @interface RestConvert { - - boolean tiny() default true; - - boolean skipIgnore() default false; - - Class type(); - - String[] ignoreColumns() default {}; - - String[] convertColumns() default {}; - - @Inherited - @Documented - @Target({METHOD}) - @Retention(RUNTIME) - @interface RestConverts { - - RestConvert[] value(); - } -} +/* + * 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 java.lang.annotation.*; +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * 鍙兘渚濋檮鍦⊿ervice瀹炵幇绫荤殑public鏂规硶涓, 褰撴柟娉曠殑杩斿洖鍊间互JSON杈撳嚭鏃跺鎸囧畾绫诲瀷鐨勮浆鎹㈣瀹氥
+ * 娉ㄦ剰: 濡傛灉 type() == void.class 鍒欐棤瑙嗗叾浠栧弬鏁板浐瀹氳繑鍥 JsonFactory.create().skipAllIgnore(true).getConvert(); + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@Inherited +@Documented +@Target({METHOD}) +@Retention(RUNTIME) +@Repeatable(RestConvert.RestConverts.class) +public @interface RestConvert { + + boolean tiny() default true; + + boolean skipIgnore() default false; + + Class type(); + + String[] ignoreColumns() default {}; + + String[] convertColumns() default {}; + + @Inherited + @Documented + @Target({METHOD}) + @Retention(RUNTIME) + @interface RestConverts { + + RestConvert[] value(); + } +} diff --git a/src/main/java/org/redkale/net/http/RestConvertCoder.java b/src/main/java/org/redkale/net/http/RestConvertCoder.java index a57e36b6a..87005ae1e 100644 --- a/src/main/java/org/redkale/net/http/RestConvertCoder.java +++ b/src/main/java/org/redkale/net/http/RestConvertCoder.java @@ -1,43 +1,43 @@ -/* - * 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 java.lang.annotation.*; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.RetentionPolicy.RUNTIME; -import org.redkale.convert.*; - -/** - * 鎸囧畾class鏌愪釜瀛楁鐨勮嚜瀹氫箟搴忓垪鍖栧拰鍙嶅簭鍒楀寲绛栫暐銆
- * 鍙兘渚濋檮鍦⊿ervice瀹炵幇绫荤殑public鏂规硶涓, 褰撴柟娉曠殑杩斿洖鍊间互JSON杈撳嚭鏃跺鎸囧畾绫诲瀷鐨勮浆鎹㈣瀹氥
- * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@Inherited -@Documented -@Target({METHOD}) -@Retention(RUNTIME) -@Repeatable(RestConvertCoder.RestConvertCoders.class) -public @interface RestConvertCoder { - - Class type(); - - String field(); - - Class coder(); - - @Inherited - @Documented - @Target({METHOD}) - @Retention(RUNTIME) - @interface RestConvertCoders { - - RestConvertCoder[] value(); - } -} +/* + * 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 java.lang.annotation.*; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import org.redkale.convert.*; + +/** + * 鎸囧畾class鏌愪釜瀛楁鐨勮嚜瀹氫箟搴忓垪鍖栧拰鍙嶅簭鍒楀寲绛栫暐銆
+ * 鍙兘渚濋檮鍦⊿ervice瀹炵幇绫荤殑public鏂规硶涓, 褰撴柟娉曠殑杩斿洖鍊间互JSON杈撳嚭鏃跺鎸囧畾绫诲瀷鐨勮浆鎹㈣瀹氥
+ * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@Inherited +@Documented +@Target({METHOD}) +@Retention(RUNTIME) +@Repeatable(RestConvertCoder.RestConvertCoders.class) +public @interface RestConvertCoder { + + Class type(); + + String field(); + + Class coder(); + + @Inherited + @Documented + @Target({METHOD}) + @Retention(RUNTIME) + @interface RestConvertCoders { + + RestConvertCoder[] value(); + } +} diff --git a/src/main/java/org/redkale/net/http/RestCookie.java b/src/main/java/org/redkale/net/http/RestCookie.java index 9c75b1ab1..b02fe5204 100644 --- a/src/main/java/org/redkale/net/http/RestCookie.java +++ b/src/main/java/org/redkale/net/http/RestCookie.java @@ -1,52 +1,52 @@ -/* - * 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 java.lang.annotation.*; -import static java.lang.annotation.ElementType.*; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * 鍙兘娉ㄨВ浜嶳estService绫荤殑鏂规硶鐨凷tring鍙傛暟鎴栧弬鏁板唴鐨凷tring瀛楁 - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@Inherited -@Documented -@Target({PARAMETER, FIELD}) -@Retention(RUNTIME) -public @interface RestCookie { - - /** - * cookie鍚 - * - * @return String - */ - String name(); - - /** - * 杞崲鏁板瓧byte/short/int/long鏃舵墍鐢ㄧ殑杩涘埗鏁帮紝 榛樿10杩涘埗 - * - * @return int - */ - int radix() default 10; - - /** - * for OpenAPI Specification 3.1.0 - * - * @return String - */ - String example() default ""; - - /** - * 澶囨敞鎻忚堪 - * - * @return String - */ - String comment() default ""; -} +/* + * 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 java.lang.annotation.*; +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * 鍙兘娉ㄨВ浜嶳estService绫荤殑鏂规硶鐨凷tring鍙傛暟鎴栧弬鏁板唴鐨凷tring瀛楁 + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@Inherited +@Documented +@Target({PARAMETER, FIELD}) +@Retention(RUNTIME) +public @interface RestCookie { + + /** + * cookie鍚 + * + * @return String + */ + String name(); + + /** + * 杞崲鏁板瓧byte/short/int/long鏃舵墍鐢ㄧ殑杩涘埗鏁帮紝 榛樿10杩涘埗 + * + * @return int + */ + int radix() default 10; + + /** + * for OpenAPI Specification 3.1.0 + * + * @return String + */ + String example() default ""; + + /** + * 澶囨敞鎻忚堪 + * + * @return String + */ + String comment() default ""; +} diff --git a/src/main/java/org/redkale/net/http/RestHeader.java b/src/main/java/org/redkale/net/http/RestHeader.java index c8f98aeb4..8e0e28a19 100644 --- a/src/main/java/org/redkale/net/http/RestHeader.java +++ b/src/main/java/org/redkale/net/http/RestHeader.java @@ -1,59 +1,59 @@ -/* - * 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 java.lang.annotation.*; -import static java.lang.annotation.ElementType.*; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * 鍙兘娉ㄨВ浜嶳estService绫荤殑鏂规硶鐨勫弬鏁版垨鍙傛暟鍐呯殑String銆乯ava.net.InetSocketAddress瀛楁 - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@Inherited -@Documented -@Target({PARAMETER, FIELD}) -@Retention(RUNTIME) -public @interface RestHeader { - - /** - * Header鍙傛暟鍚 - * - * @return String - */ - String name(); - - /** - * 杞崲鏁板瓧byte/short/int/long鏃舵墍鐢ㄧ殑杩涘埗鏁帮紝 榛樿10杩涘埗 - * - * @return int - */ - int radix() default 10; - - /** - * 鍙傛暟鏄惁蹇呬紶, 妗嗘灦杩愯涓笉浣滈獙璇, only for OpenAPI Specification 3 - * - * @return boolean - */ - boolean required() default true; - - /** - * for OpenAPI Specification 3.1.0 - * - * @return String - */ - String example() default ""; - - /** - * 澶囨敞鎻忚堪 - * - * @return String - */ - String comment() default ""; -} +/* + * 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 java.lang.annotation.*; +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * 鍙兘娉ㄨВ浜嶳estService绫荤殑鏂规硶鐨勫弬鏁版垨鍙傛暟鍐呯殑String銆乯ava.net.InetSocketAddress瀛楁 + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@Inherited +@Documented +@Target({PARAMETER, FIELD}) +@Retention(RUNTIME) +public @interface RestHeader { + + /** + * Header鍙傛暟鍚 + * + * @return String + */ + String name(); + + /** + * 杞崲鏁板瓧byte/short/int/long鏃舵墍鐢ㄧ殑杩涘埗鏁帮紝 榛樿10杩涘埗 + * + * @return int + */ + int radix() default 10; + + /** + * 鍙傛暟鏄惁蹇呬紶, 妗嗘灦杩愯涓笉浣滈獙璇, only for OpenAPI Specification 3 + * + * @return boolean + */ + boolean required() default true; + + /** + * for OpenAPI Specification 3.1.0 + * + * @return String + */ + String example() default ""; + + /** + * 澶囨敞鎻忚堪 + * + * @return String + */ + String comment() default ""; +} diff --git a/src/main/java/org/redkale/net/http/RestHeaders.java b/src/main/java/org/redkale/net/http/RestHeaders.java index fd5b074fc..285e04d8d 100644 --- a/src/main/java/org/redkale/net/http/RestHeaders.java +++ b/src/main/java/org/redkale/net/http/RestHeaders.java @@ -1,28 +1,28 @@ -/* - * 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 java.lang.annotation.*; -import static java.lang.annotation.ElementType.*; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * 鍙兘娉ㄨВ浜嶳estService绫荤殑鏂规硶鐨勫弬鏁版垨鍙傛暟鍐呯殑Map<String, String>瀛楁 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * - * @since 2.1.0 - */ -@Inherited -@Documented -@Target({PARAMETER, FIELD}) -@Retention(RUNTIME) -public @interface RestHeaders { - -} +/* + * 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 java.lang.annotation.*; +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * 鍙兘娉ㄨВ浜嶳estService绫荤殑鏂规硶鐨勫弬鏁版垨鍙傛暟鍐呯殑Map<String, String>瀛楁 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.1.0 + */ +@Inherited +@Documented +@Target({PARAMETER, FIELD}) +@Retention(RUNTIME) +public @interface RestHeaders { + +} diff --git a/src/main/java/org/redkale/net/http/RestMapping.java b/src/main/java/org/redkale/net/http/RestMapping.java index 1480f4efd..4d470c138 100644 --- a/src/main/java/org/redkale/net/http/RestMapping.java +++ b/src/main/java/org/redkale/net/http/RestMapping.java @@ -1,99 +1,99 @@ -/* - * 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 java.lang.annotation.*; -import static java.lang.annotation.ElementType.*; -import static java.lang.annotation.RetentionPolicy.*; - -/** - * 鍙兘渚濋檮鍦⊿ervice瀹炵幇绫荤殑public鏂规硶涓婏紝涓旀柟娉曞鏋渢hrows鍙兘鏄疘OException
- * value榛樿涓"/" + Service鐨勭被鍚嶅幓鎺塖ervice瀛楁牱鐨勫皬鍐欏瓧绗︿覆 (濡侶elloService锛岀殑榛樿璺緞涓/hello)銆
- *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@Inherited -@Documented -@Target({METHOD}) -@Retention(RUNTIME) -@Repeatable(RestMapping.RestMappings.class) -public @interface RestMapping { - - /** - * 鏄惁灞忚斀璇ユ柟娉曡繘琛孒ttpMapping杞崲 - * - * @return boolean - */ - boolean ignore() default false; - - /** - * 璇锋眰鐨勬柟娉曞悕, 涓嶈兘鍚壒娈婂瓧绗 - * - * @return String - */ - String name() default ""; - - /** - * 澶囨敞鎻忚堪, 瀵瑰簲@HttpMapping.comment - * - * @return String - */ - String comment() default ""; - - /** - * 鏄惁鍙帴鏀禦PC璇锋眰, 瀵瑰簲@HttpMapping.rpconly - * - * @return boolean - */ - boolean rpconly() default false; - - /** - * 鏄惁閴存潈锛岄粯璁ら渶瑕侀壌鏉, 瀵瑰簲@HttpMapping.auth - * - * @return boolean - */ - boolean auth() default true; - - /** - * 鎿嶄綔ID鍊硷紝閴存潈鏃剁敤鍒, 瀵瑰簲@HttpMapping.actionid - * - * @return int - */ - int actionid() default 0; - - /** - * 缁撴灉缂撳瓨鐨勭鏁, 涓0琛ㄧず涓嶇紦瀛, 瀵瑰簲@HttpMapping.cacheseconds - * - * @return int - */ - int cacheseconds() default 0; - - /** - * 鍏佽鏂规硶(涓嶅尯鍒嗗ぇ灏忓啓),濡:GET/POST/PUT,涓虹┖琛ㄧず鍏佽鎵鏈夋柟娉, 瀵瑰簲@HttpMapping.methods - * - * @return String[] - */ - String[] methods() default {}; - - /** - * 杩斿洖缁撴灉鐨勬牱渚 - * for OpenAPI Specification 3.1.0 - * - * @return String - */ - String example() default ""; - - @Inherited - @Documented - @Target({METHOD}) - @Retention(RUNTIME) - @interface RestMappings { - - RestMapping[] value(); - } -} +/* + * 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 java.lang.annotation.*; +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +/** + * 鍙兘渚濋檮鍦⊿ervice瀹炵幇绫荤殑public鏂规硶涓婏紝涓旀柟娉曞鏋渢hrows鍙兘鏄疘OException
+ * value榛樿涓"/" + Service鐨勭被鍚嶅幓鎺塖ervice瀛楁牱鐨勫皬鍐欏瓧绗︿覆 (濡侶elloService锛岀殑榛樿璺緞涓/hello)銆
+ *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@Inherited +@Documented +@Target({METHOD}) +@Retention(RUNTIME) +@Repeatable(RestMapping.RestMappings.class) +public @interface RestMapping { + + /** + * 鏄惁灞忚斀璇ユ柟娉曡繘琛孒ttpMapping杞崲 + * + * @return boolean + */ + boolean ignore() default false; + + /** + * 璇锋眰鐨勬柟娉曞悕, 涓嶈兘鍚壒娈婂瓧绗 + * + * @return String + */ + String name() default ""; + + /** + * 澶囨敞鎻忚堪, 瀵瑰簲@HttpMapping.comment + * + * @return String + */ + String comment() default ""; + + /** + * 鏄惁鍙帴鏀禦PC璇锋眰, 瀵瑰簲@HttpMapping.rpconly + * + * @return boolean + */ + boolean rpconly() default false; + + /** + * 鏄惁閴存潈锛岄粯璁ら渶瑕侀壌鏉, 瀵瑰簲@HttpMapping.auth + * + * @return boolean + */ + boolean auth() default true; + + /** + * 鎿嶄綔ID鍊硷紝閴存潈鏃剁敤鍒, 瀵瑰簲@HttpMapping.actionid + * + * @return int + */ + int actionid() default 0; + + /** + * 缁撴灉缂撳瓨鐨勭鏁, 涓0琛ㄧず涓嶇紦瀛, 瀵瑰簲@HttpMapping.cacheseconds + * + * @return int + */ + int cacheseconds() default 0; + + /** + * 鍏佽鏂规硶(涓嶅尯鍒嗗ぇ灏忓啓),濡:GET/POST/PUT,涓虹┖琛ㄧず鍏佽鎵鏈夋柟娉, 瀵瑰簲@HttpMapping.methods + * + * @return String[] + */ + String[] methods() default {}; + + /** + * 杩斿洖缁撴灉鐨勬牱渚 + * for OpenAPI Specification 3.1.0 + * + * @return String + */ + String example() default ""; + + @Inherited + @Documented + @Target({METHOD}) + @Retention(RUNTIME) + @interface RestMappings { + + RestMapping[] value(); + } +} diff --git a/src/main/java/org/redkale/net/http/RestOnMessage.java b/src/main/java/org/redkale/net/http/RestOnMessage.java index 2fa48dac9..b93cd1f01 100644 --- a/src/main/java/org/redkale/net/http/RestOnMessage.java +++ b/src/main/java/org/redkale/net/http/RestOnMessage.java @@ -1,44 +1,44 @@ -/* - * 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 java.lang.annotation.*; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * 鏍囪鍦≧estWebSocket鐨勬帴鏀舵秷鎭柟娉曚笂;
- * 娉ㄦ剰锛氳鏍囪鐨勬柟娉曞繀椤诲悓鏃剁鍚堜互涓嬫潯浠:
- * 1銆佸繀椤讳慨楗颁负public - * 2銆佷笉鑳戒慨楗颁负final鍜宻tatic - * 3銆佽繑鍥炲煎繀椤绘槸void - * 4銆佷笉鑳絫hrows妫鏌ュ瀷寮傚父 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@Inherited -@Documented -@Target({METHOD}) -@Retention(RUNTIME) -public @interface RestOnMessage { - - /** - * 璇锋眰鐨勬柟娉曞悕, 涓嶈兘鍚壒娈婂瓧绗,涓嶈兘浠ユ暟瀛楀紑澶(鑳戒綔涓哄彉閲忓悕) - * - * @return String - */ - String name(); - - /** - * 澶囨敞鎻忚堪 - * - * @return String - */ - String comment() default ""; -} +/* + * 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 java.lang.annotation.*; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * 鏍囪鍦≧estWebSocket鐨勬帴鏀舵秷鎭柟娉曚笂;
+ * 娉ㄦ剰锛氳鏍囪鐨勬柟娉曞繀椤诲悓鏃剁鍚堜互涓嬫潯浠:
+ * 1銆佸繀椤讳慨楗颁负public + * 2銆佷笉鑳戒慨楗颁负final鍜宻tatic + * 3銆佽繑鍥炲煎繀椤绘槸void + * 4銆佷笉鑳絫hrows妫鏌ュ瀷寮傚父 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@Inherited +@Documented +@Target({METHOD}) +@Retention(RUNTIME) +public @interface RestOnMessage { + + /** + * 璇锋眰鐨勬柟娉曞悕, 涓嶈兘鍚壒娈婂瓧绗,涓嶈兘浠ユ暟瀛楀紑澶(鑳戒綔涓哄彉閲忓悕) + * + * @return String + */ + String name(); + + /** + * 澶囨敞鎻忚堪 + * + * @return String + */ + String comment() default ""; +} diff --git a/src/main/java/org/redkale/net/http/RestParam.java b/src/main/java/org/redkale/net/http/RestParam.java index 61c93692c..1ce85e505 100644 --- a/src/main/java/org/redkale/net/http/RestParam.java +++ b/src/main/java/org/redkale/net/http/RestParam.java @@ -1,67 +1,67 @@ -/* - * 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 java.lang.annotation.*; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * - * 渚濋檮鍦≧estService绫荤殑鏂规硶鐨勫弬鏁颁笂
- * name='&' 琛ㄧず褰撳墠鐢ㄦ埛
- * name='#'琛ㄧず鎴彇uri鏈鍚庝竴娈
- * name='#xxx:'琛ㄧず浠巙ri涓/pipes/xxx:v/鎴彇xxx:鐨勫
- *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@Inherited -@Documented -@Target({PARAMETER}) -@Retention(RUNTIME) -public @interface RestParam { - - //name='&'琛ㄧず褰撳墠鐢ㄦ埛; - /** - * 鍙傛暟鍚
- * name='&'琛ㄧず褰撳墠鐢ㄦ埛;
- * name='#'琛ㄧず鎴彇uri鏈鍚庝竴娈;
- * name='#xxx:'琛ㄧず浠巙ri涓/pipes/xxx:v/鎴彇xxx:鐨勫
- * - * @return String - */ - String name() default ""; - - /** - * 杞崲鏁板瓧byte/short/int/long鏃舵墍鐢ㄧ殑杩涘埗鏁帮紝 榛樿10杩涘埗 - * - * @return int - */ - int radix() default 10; - - /** - * 鍙傛暟鏄惁蹇呬紶, 妗嗘灦杩愯涓笉浣滈獙璇, only for OpenAPI Specification 3 - * - * @return boolean - */ - boolean required() default true; - - /** - * for OpenAPI Specification 3.1.0 - * - * @return String - */ - String example() default ""; - - /** - * 澶囨敞鎻忚堪 - * - * @return String - */ - String comment() default ""; -} +/* + * 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 java.lang.annotation.*; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * + * 渚濋檮鍦≧estService绫荤殑鏂规硶鐨勫弬鏁颁笂
+ * name='&' 琛ㄧず褰撳墠鐢ㄦ埛
+ * name='#'琛ㄧず鎴彇uri鏈鍚庝竴娈
+ * name='#xxx:'琛ㄧず浠巙ri涓/pipes/xxx:v/鎴彇xxx:鐨勫
+ *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@Inherited +@Documented +@Target({PARAMETER}) +@Retention(RUNTIME) +public @interface RestParam { + + //name='&'琛ㄧず褰撳墠鐢ㄦ埛; + /** + * 鍙傛暟鍚
+ * name='&'琛ㄧず褰撳墠鐢ㄦ埛;
+ * name='#'琛ㄧず鎴彇uri鏈鍚庝竴娈;
+ * name='#xxx:'琛ㄧず浠巙ri涓/pipes/xxx:v/鎴彇xxx:鐨勫
+ * + * @return String + */ + String name() default ""; + + /** + * 杞崲鏁板瓧byte/short/int/long鏃舵墍鐢ㄧ殑杩涘埗鏁帮紝 榛樿10杩涘埗 + * + * @return int + */ + int radix() default 10; + + /** + * 鍙傛暟鏄惁蹇呬紶, 妗嗘灦杩愯涓笉浣滈獙璇, only for OpenAPI Specification 3 + * + * @return boolean + */ + boolean required() default true; + + /** + * for OpenAPI Specification 3.1.0 + * + * @return String + */ + String example() default ""; + + /** + * 澶囨敞鎻忚堪 + * + * @return String + */ + String comment() default ""; +} diff --git a/src/main/java/org/redkale/net/http/RestParams.java b/src/main/java/org/redkale/net/http/RestParams.java index b89b01228..8d1b15c6e 100644 --- a/src/main/java/org/redkale/net/http/RestParams.java +++ b/src/main/java/org/redkale/net/http/RestParams.java @@ -1,28 +1,28 @@ -/* - * 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 java.lang.annotation.*; -import static java.lang.annotation.ElementType.*; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * 鍙兘娉ㄨВ浜嶳estService绫荤殑鏂规硶鐨勫弬鏁版垨鍙傛暟鍐呯殑Map<String, String>瀛楁 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * - * @since 2.4.0 - */ -@Inherited -@Documented -@Target({PARAMETER, FIELD}) -@Retention(RUNTIME) -public @interface RestParams { - -} +/* + * 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 java.lang.annotation.*; +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * 鍙兘娉ㄨВ浜嶳estService绫荤殑鏂规硶鐨勫弬鏁版垨鍙傛暟鍐呯殑Map<String, String>瀛楁 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.4.0 + */ +@Inherited +@Documented +@Target({PARAMETER, FIELD}) +@Retention(RUNTIME) +public @interface RestParams { + +} diff --git a/src/main/java/org/redkale/net/http/RestService.java b/src/main/java/org/redkale/net/http/RestService.java index 24e8bcd5a..20c7bdafc 100644 --- a/src/main/java/org/redkale/net/http/RestService.java +++ b/src/main/java/org/redkale/net/http/RestService.java @@ -1,80 +1,80 @@ -/* - * 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 java.lang.annotation.*; -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * 鍙兘渚濋檮鍦⊿ervice绫讳笂锛宯ame榛樿涓篠ervice鐨勭被鍚嶅皬鍐欏苟鍘绘帀Service瀛楁牱鍙婂悗闈㈢殑瀛楃涓 (濡侶elloService/HelloServiceImpl锛岀殑榛樿璺緞涓 hello)銆 - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@Inherited -@Documented -@Target({TYPE}) -@Retention(RUNTIME) -public @interface RestService { - - /** - * 妯″潡鍚, 鍙兘鏄ā鍧楀悕,涓嶈兘鍚壒娈婂瓧绗︼紝 鍙兘灏忓啓瀛楁瘝+鏁板瓧锛屼笖涓嶈兘浠ユ暟瀛楀紑澶达紝 鍗曠嫭涓涓┖鏍煎间负鐗规畩鍊 - * - * @return 妯″潡鍚 - */ - String name() default ""; - - /** - * 鐩綍鍚, 涓嶈兘鍚壒娈婂瓧绗︼紝 鍙兘灏忓啓瀛楁瘝+鏁板瓧锛屼笖涓嶈兘浠ユ暟瀛楀紑澶 - * - * @return 鐩綍鍚 - */ - String catalog() default ""; - - /** - * 妯″潡ID鍊硷紝閴存潈鏃剁敤鍒, 瀵瑰簲@WebServlet.moduleid - * - * @return 妯″潡ID鍊 - */ - int moduleid() default 0; - - /** - * 鏄惁鍙帴鍙桼PC璇锋眰锛 榛樿涓篺alse, 涓簍rue鍒欒鐩栨墍鏈@RestMapping鐨勬柟娉曠殑rpconly鍊硷紝閮借浆涓簍rue - * - * @return 榛樿false - */ - boolean rpconly() default false; - - /** - * 娌℃湁鏍囪@RestMapping鐨勬柟娉曟槸鍚﹁浆鎹紝 榛樿涓篺alse - * - * @return 榛樿false - */ - boolean automapping() default false; - - /** - * 鏄惁灞忚斀璇ョ被鐨勮浆鎹 - * - * @return 榛樿false - */ - boolean ignore() default false; - - /** - * 鍚@WebServlet鐨剅epair灞炴 - * - * @return 榛樿true - */ - boolean repair() default true; - - /** - * 澶囨敞鎻忚堪 - * - * @return 澶囨敞鎻忚堪 - */ - String comment() default ""; -} +/* + * 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 java.lang.annotation.*; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * 鍙兘渚濋檮鍦⊿ervice绫讳笂锛宯ame榛樿涓篠ervice鐨勭被鍚嶅皬鍐欏苟鍘绘帀Service瀛楁牱鍙婂悗闈㈢殑瀛楃涓 (濡侶elloService/HelloServiceImpl锛岀殑榛樿璺緞涓 hello)銆 + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@Inherited +@Documented +@Target({TYPE}) +@Retention(RUNTIME) +public @interface RestService { + + /** + * 妯″潡鍚, 鍙兘鏄ā鍧楀悕,涓嶈兘鍚壒娈婂瓧绗︼紝 鍙兘灏忓啓瀛楁瘝+鏁板瓧锛屼笖涓嶈兘浠ユ暟瀛楀紑澶达紝 鍗曠嫭涓涓┖鏍煎间负鐗规畩鍊 + * + * @return 妯″潡鍚 + */ + String name() default ""; + + /** + * 鐩綍鍚, 涓嶈兘鍚壒娈婂瓧绗︼紝 鍙兘灏忓啓瀛楁瘝+鏁板瓧锛屼笖涓嶈兘浠ユ暟瀛楀紑澶 + * + * @return 鐩綍鍚 + */ + String catalog() default ""; + + /** + * 妯″潡ID鍊硷紝閴存潈鏃剁敤鍒, 瀵瑰簲@WebServlet.moduleid + * + * @return 妯″潡ID鍊 + */ + int moduleid() default 0; + + /** + * 鏄惁鍙帴鍙桼PC璇锋眰锛 榛樿涓篺alse, 涓簍rue鍒欒鐩栨墍鏈@RestMapping鐨勬柟娉曠殑rpconly鍊硷紝閮借浆涓簍rue + * + * @return 榛樿false + */ + boolean rpconly() default false; + + /** + * 娌℃湁鏍囪@RestMapping鐨勬柟娉曟槸鍚﹁浆鎹紝 榛樿涓篺alse + * + * @return 榛樿false + */ + boolean automapping() default false; + + /** + * 鏄惁灞忚斀璇ョ被鐨勮浆鎹 + * + * @return 榛樿false + */ + boolean ignore() default false; + + /** + * 鍚@WebServlet鐨剅epair灞炴 + * + * @return 榛樿true + */ + boolean repair() default true; + + /** + * 澶囨敞鎻忚堪 + * + * @return 澶囨敞鎻忚堪 + */ + String comment() default ""; +} diff --git a/src/main/java/org/redkale/net/http/RestSessionid.java b/src/main/java/org/redkale/net/http/RestSessionid.java index c743131dc..a156a8d2f 100644 --- a/src/main/java/org/redkale/net/http/RestSessionid.java +++ b/src/main/java/org/redkale/net/http/RestSessionid.java @@ -1,26 +1,26 @@ -/* - * 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 java.lang.annotation.*; -import static java.lang.annotation.ElementType.*; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * 鍙兘娉ㄨВ浜嶴ervice绫荤殑鏂规硶鐨勫弬鏁版垨鍙傛暟鍐呯殑String瀛楁 - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@Inherited -@Documented -@Target({PARAMETER, FIELD}) -@Retention(RUNTIME) -public @interface RestSessionid { - - boolean create() default false; -} +/* + * 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 java.lang.annotation.*; +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * 鍙兘娉ㄨВ浜嶴ervice绫荤殑鏂规硶鐨勫弬鏁版垨鍙傛暟鍐呯殑String瀛楁 + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@Inherited +@Documented +@Target({PARAMETER, FIELD}) +@Retention(RUNTIME) +public @interface RestSessionid { + + boolean create() default false; +} diff --git a/src/main/java/org/redkale/net/http/RestURI.java b/src/main/java/org/redkale/net/http/RestURI.java index aed6ec68c..fb7fb6a01 100644 --- a/src/main/java/org/redkale/net/http/RestURI.java +++ b/src/main/java/org/redkale/net/http/RestURI.java @@ -1,33 +1,33 @@ -/* - * 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 java.lang.annotation.*; -import static java.lang.annotation.ElementType.*; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * 鍙兘娉ㄨВ浜嶴ervice绫荤殑鏂规硶鐨凷tring鍙傛暟鎴栧弬鏁板唴鐨凷tring瀛楁 - *

- * 鐢ㄤ簬鑾峰彇HTTP璇锋眰URL HttpRequest.getRequestURI - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@Inherited -@Documented -@Target({PARAMETER, FIELD}) -@Retention(RUNTIME) -public @interface RestURI { - - /** - * 澶囨敞鎻忚堪, 瀵瑰簲@HttpParam.comment - * - * @return String - */ - String comment() default ""; -} +/* + * 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 java.lang.annotation.*; +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * 鍙兘娉ㄨВ浜嶴ervice绫荤殑鏂规硶鐨凷tring鍙傛暟鎴栧弬鏁板唴鐨凷tring瀛楁 + *

+ * 鐢ㄤ簬鑾峰彇HTTP璇锋眰URL HttpRequest.getRequestURI + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@Inherited +@Documented +@Target({PARAMETER, FIELD}) +@Retention(RUNTIME) +public @interface RestURI { + + /** + * 澶囨敞鎻忚堪, 瀵瑰簲@HttpParam.comment + * + * @return String + */ + String comment() default ""; +} diff --git a/src/main/java/org/redkale/net/http/RestUploadFile.java b/src/main/java/org/redkale/net/http/RestUploadFile.java index 16bab2e98..6d1b11566 100644 --- a/src/main/java/org/redkale/net/http/RestUploadFile.java +++ b/src/main/java/org/redkale/net/http/RestUploadFile.java @@ -1,55 +1,55 @@ -/* - * 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 java.lang.annotation.*; -import static java.lang.annotation.ElementType.*; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * - * 渚濋檮鍦≧estService绫荤殑鏂规硶鐨勫弬鏁颁笂, 鐢ㄤ簬鎺ユ敹涓婁紶鏂囦欢
- * 鍙兘鏍囪鍦╞yte[]/File/File[] 绫诲瀷鐨勫弬鏁颁笂
- * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@Inherited -@Documented -@Target({PARAMETER, FIELD}) -@Retention(RUNTIME) -public @interface RestUploadFile { - - /** - * 鍙帴鏀剁殑鏂囦欢澶у皬鏈澶у硷紝 灏忎簬1琛ㄧず鏃犲ぇ灏忛檺鍒 - * - * @return int - */ - long maxLength() default 0; - - /** - * 鍙帴鏀剁殑鏂囦欢鍚嶆鍒欒〃杈惧紡, 涓虹┖琛ㄧず鎺ユ敹浠讳綍鏂囦欢
- * - * @return String - */ - String fileNameReg() default ""; - - /** - * 鍙帴鏀剁殑ContentType姝e垯琛ㄨ揪寮, 涓虹┖琛ㄧず鎺ユ敹浠讳綍鏂囦欢绫诲瀷
- * - * @return String - */ - String contentTypeReg() default ""; - - /** - * 澶囨敞鎻忚堪, 瀵瑰簲@HttpParam.comment - * - * @return String - */ - String comment() default ""; -} +/* + * 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 java.lang.annotation.*; +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * + * 渚濋檮鍦≧estService绫荤殑鏂规硶鐨勫弬鏁颁笂, 鐢ㄤ簬鎺ユ敹涓婁紶鏂囦欢
+ * 鍙兘鏍囪鍦╞yte[]/File/File[] 绫诲瀷鐨勫弬鏁颁笂
+ * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@Inherited +@Documented +@Target({PARAMETER, FIELD}) +@Retention(RUNTIME) +public @interface RestUploadFile { + + /** + * 鍙帴鏀剁殑鏂囦欢澶у皬鏈澶у硷紝 灏忎簬1琛ㄧず鏃犲ぇ灏忛檺鍒 + * + * @return int + */ + long maxLength() default 0; + + /** + * 鍙帴鏀剁殑鏂囦欢鍚嶆鍒欒〃杈惧紡, 涓虹┖琛ㄧず鎺ユ敹浠讳綍鏂囦欢
+ * + * @return String + */ + String fileNameReg() default ""; + + /** + * 鍙帴鏀剁殑ContentType姝e垯琛ㄨ揪寮, 涓虹┖琛ㄧず鎺ユ敹浠讳綍鏂囦欢绫诲瀷
+ * + * @return String + */ + String contentTypeReg() default ""; + + /** + * 澶囨敞鎻忚堪, 瀵瑰簲@HttpParam.comment + * + * @return String + */ + String comment() default ""; +} diff --git a/src/main/java/org/redkale/net/http/RestUserid.java b/src/main/java/org/redkale/net/http/RestUserid.java index 86ba3b398..61a58dd54 100644 --- a/src/main/java/org/redkale/net/http/RestUserid.java +++ b/src/main/java/org/redkale/net/http/RestUserid.java @@ -1,29 +1,29 @@ -/* - * 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 java.lang.annotation.*; -import static java.lang.annotation.ElementType.*; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * 鍙兘娉ㄨВ浜嶴ervice绫荤殑鏂规硶鐨勫弬鏁版垨鍙傛暟鍐呯殑Serializable瀛楁 - *

- * 鐢ㄤ簬鑾峰彇HTTP璇锋眰绔殑鐢ㄦ埛ID HttpRequest.currentUserid - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * - * @since 2.1.0 - */ -@Inherited -@Documented -@Target({PARAMETER, FIELD}) -@Retention(RUNTIME) -public @interface RestUserid { - -} +/* + * 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 java.lang.annotation.*; +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * 鍙兘娉ㄨВ浜嶴ervice绫荤殑鏂规硶鐨勫弬鏁版垨鍙傛暟鍐呯殑Serializable瀛楁 + *

+ * 鐢ㄤ簬鑾峰彇HTTP璇锋眰绔殑鐢ㄦ埛ID HttpRequest.currentUserid + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.1.0 + */ +@Inherited +@Documented +@Target({PARAMETER, FIELD}) +@Retention(RUNTIME) +public @interface RestUserid { + +} diff --git a/src/main/java/org/redkale/net/http/RestWebSocket.java b/src/main/java/org/redkale/net/http/RestWebSocket.java index 2ea2cdd1e..0cdc18b44 100644 --- a/src/main/java/org/redkale/net/http/RestWebSocket.java +++ b/src/main/java/org/redkale/net/http/RestWebSocket.java @@ -1,125 +1,125 @@ -/* - * 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 java.lang.annotation.*; -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; -import org.redkale.net.Cryptor; - -/** - * 鍙兘渚濋檮鍦╓ebSocket绫讳笂锛宯ame榛樿涓篠ervice鐨勭被鍚嶅皬鍐欏苟鍘绘帀Service瀛楁牱鍙婂悗闈㈢殑瀛楃涓 (濡侶elloWebSocket/HelloWebSocketImpl锛岀殑榛樿璺緞涓 hello)銆
- * 娉ㄦ剰: 琚爣璁@RestWebSocket鐨刉ebSocket涓嶈兘琚慨楗颁负abstract鎴杅inal锛屼笖鍏跺唴閮ㄦ爣璁颁负@Resource鐨勫瓧娈靛彧鑳芥槸protected鎴杙ublic锛屼笖蹇呴』瑕佹湁涓涓猵rotected鎴杙ublic鐨勭┖鍙傛暟鏋勯犲嚱鏁般
- * name鍊兼敮鎸佸惈{system.property.xxx}妯″紡 - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@Inherited -@Documented -@Target({TYPE}) -@Retention(RUNTIME) -public @interface RestWebSocket { - - /** - * 妯″潡鍚, 鍙兘鏄ā鍧楀悕,涓嶈兘鍚壒娈婂瓧绗︼紝 鍙兘灏忓啓瀛楁瘝+鏁板瓧锛屼笖涓嶈兘浠ユ暟瀛楀紑澶 - * - * @return 妯″潡鍚 - */ - String name() default ""; - - /** - * 鐩綍鍚, 涓嶈兘鍚壒娈婂瓧绗︼紝 鍙兘灏忓啓瀛楁瘝+鏁板瓧锛屼笖涓嶈兘浠ユ暟瀛楀紑澶 - * - * @return 鐩綍鍚 - */ - String catalog() default ""; - - /** - * 鏄惁涓轰簩杩涘埗娑堟伅, 榛樿涓烘枃鏈秷鎭 - * - * @return boolean - */ - boolean binary() default false; - - /** - * 鏄惁鍗曠敤鎴峰崟杩炴帴, 榛樿鍗曠敤鎴峰崟杩炴帴 - * - * @return 鏄惁鍗曠敤鎴峰崟杩炴帴 - */ - boolean single() default true; - - /** - * WebSocket.createUserid杩斿洖鐨勫兼槸鍚︿笉鑳借〃绀虹敤鎴风櫥褰曟侊紝 姣斿createUserid杩斿洖闅忔満鐨刄UID閭d箞anyuser搴旇涓簍rue - * - * @return 榛樿false - */ - boolean anyuser() default false; - - /** - * 鎺ユ敹瀹㈡埛绔殑鍒嗗寘(last=false)娑堟伅鏃舵槸鍚﹁嚜鍔ㄥ悎骞跺寘 - * - * @return 榛樿true - */ - boolean mergemsg() default true; - - /** - * WebScoket鏈嶅姟鍣ㄧ粰瀹㈡埛绔繘琛宲ing鎿嶄綔鐨勯棿闅旀椂闂, 鍗曚綅: 绉掞紝 榛樿鍊硷細15绉 - * - * @return int - */ - int liveinterval() default WebSocketServlet.DEFAILT_LIVEINTERVAL; - - /** - * 鍔犲瘑瑙e瘑鍣 - * - * @return Cryptor - */ - Class cryptor() default Cryptor.class; - - /** - * 鏈澶ц繛鎺ユ暟, 灏忎簬1琛ㄧず鏃犻檺鍒 - * - * @return 鏈澶ц繛鎺ユ暟 - */ - int wsmaxconns() default 0; - - /** - * 鎿嶄綔WebSocketNode瀵瑰簲CacheSource骞跺彂鏁, 涓-1琛ㄧず鏃犻檺鍒讹紝涓0琛ㄧず绯荤粺榛樿鍊(CPU*8) - * - * @return 鏈澶ц繛鎺ユ暟 - */ - int wsthreads() default 0; - - /** - * 鏈澶ф秷鎭綋闀垮害, 灏忎簬1琛ㄧず鏃犻檺鍒 - * - * @return 鏈澶ф秷鎭綋闀垮害 - */ - int wsmaxbody() default 32 * 1024; - - /** - * 鏄惁灞忚斀璇ョ被鐨勮浆鎹 - * - * @return 榛樿false - */ - boolean ignore() default false; - - /** - * 鍚@WebServlet鐨剅epair灞炴 - * - * @return 榛樿true - */ - boolean repair() default true; - - /** - * 澶囨敞鎻忚堪 - * - * @return 澶囨敞鎻忚堪 - */ - String comment() default ""; -} +/* + * 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 java.lang.annotation.*; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import org.redkale.net.Cryptor; + +/** + * 鍙兘渚濋檮鍦╓ebSocket绫讳笂锛宯ame榛樿涓篠ervice鐨勭被鍚嶅皬鍐欏苟鍘绘帀Service瀛楁牱鍙婂悗闈㈢殑瀛楃涓 (濡侶elloWebSocket/HelloWebSocketImpl锛岀殑榛樿璺緞涓 hello)銆
+ * 娉ㄦ剰: 琚爣璁@RestWebSocket鐨刉ebSocket涓嶈兘琚慨楗颁负abstract鎴杅inal锛屼笖鍏跺唴閮ㄦ爣璁颁负@Resource鐨勫瓧娈靛彧鑳芥槸protected鎴杙ublic锛屼笖蹇呴』瑕佹湁涓涓猵rotected鎴杙ublic鐨勭┖鍙傛暟鏋勯犲嚱鏁般
+ * name鍊兼敮鎸佸惈{system.property.xxx}妯″紡 + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@Inherited +@Documented +@Target({TYPE}) +@Retention(RUNTIME) +public @interface RestWebSocket { + + /** + * 妯″潡鍚, 鍙兘鏄ā鍧楀悕,涓嶈兘鍚壒娈婂瓧绗︼紝 鍙兘灏忓啓瀛楁瘝+鏁板瓧锛屼笖涓嶈兘浠ユ暟瀛楀紑澶 + * + * @return 妯″潡鍚 + */ + String name() default ""; + + /** + * 鐩綍鍚, 涓嶈兘鍚壒娈婂瓧绗︼紝 鍙兘灏忓啓瀛楁瘝+鏁板瓧锛屼笖涓嶈兘浠ユ暟瀛楀紑澶 + * + * @return 鐩綍鍚 + */ + String catalog() default ""; + + /** + * 鏄惁涓轰簩杩涘埗娑堟伅, 榛樿涓烘枃鏈秷鎭 + * + * @return boolean + */ + boolean binary() default false; + + /** + * 鏄惁鍗曠敤鎴峰崟杩炴帴, 榛樿鍗曠敤鎴峰崟杩炴帴 + * + * @return 鏄惁鍗曠敤鎴峰崟杩炴帴 + */ + boolean single() default true; + + /** + * WebSocket.createUserid杩斿洖鐨勫兼槸鍚︿笉鑳借〃绀虹敤鎴风櫥褰曟侊紝 姣斿createUserid杩斿洖闅忔満鐨刄UID閭d箞anyuser搴旇涓簍rue + * + * @return 榛樿false + */ + boolean anyuser() default false; + + /** + * 鎺ユ敹瀹㈡埛绔殑鍒嗗寘(last=false)娑堟伅鏃舵槸鍚﹁嚜鍔ㄥ悎骞跺寘 + * + * @return 榛樿true + */ + boolean mergemsg() default true; + + /** + * WebScoket鏈嶅姟鍣ㄧ粰瀹㈡埛绔繘琛宲ing鎿嶄綔鐨勯棿闅旀椂闂, 鍗曚綅: 绉掞紝 榛樿鍊硷細15绉 + * + * @return int + */ + int liveinterval() default WebSocketServlet.DEFAILT_LIVEINTERVAL; + + /** + * 鍔犲瘑瑙e瘑鍣 + * + * @return Cryptor + */ + Class cryptor() default Cryptor.class; + + /** + * 鏈澶ц繛鎺ユ暟, 灏忎簬1琛ㄧず鏃犻檺鍒 + * + * @return 鏈澶ц繛鎺ユ暟 + */ + int wsmaxconns() default 0; + + /** + * 鎿嶄綔WebSocketNode瀵瑰簲CacheSource骞跺彂鏁, 涓-1琛ㄧず鏃犻檺鍒讹紝涓0琛ㄧず绯荤粺榛樿鍊(CPU*8) + * + * @return 鏈澶ц繛鎺ユ暟 + */ + int wsthreads() default 0; + + /** + * 鏈澶ф秷鎭綋闀垮害, 灏忎簬1琛ㄧず鏃犻檺鍒 + * + * @return 鏈澶ф秷鎭綋闀垮害 + */ + int wsmaxbody() default 32 * 1024; + + /** + * 鏄惁灞忚斀璇ョ被鐨勮浆鎹 + * + * @return 榛樿false + */ + boolean ignore() default false; + + /** + * 鍚@WebServlet鐨剅epair灞炴 + * + * @return 榛樿true + */ + boolean repair() default true; + + /** + * 澶囨敞鎻忚堪 + * + * @return 澶囨敞鎻忚堪 + */ + String comment() default ""; +} diff --git a/src/main/java/org/redkale/net/http/WebServlet.java b/src/main/java/org/redkale/net/http/WebServlet.java index 578ce6527..98f3d5070 100644 --- a/src/main/java/org/redkale/net/http/WebServlet.java +++ b/src/main/java/org/redkale/net/http/WebServlet.java @@ -1,58 +1,58 @@ -/* - * 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 java.lang.annotation.*; - -/** - * 鍔熻兘鍚孞SR 315 (java-servlet 3.0) 瑙勮寖涓殑 @WebServlet - * - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@Documented -@Target({ElementType.TYPE}) -@Retention(RetentionPolicy.RUNTIME) -public @interface WebServlet { - - /** - * HttpServlet璧勬簮鍚 - * - * @return String - */ - String name() default ""; - - /** - * 鏄惁鑷姩娣诲姞url鍓嶇紑, 瀵瑰簲application.xml涓璼ervlets鑺傜偣鐨刾ath灞炴 - * - * @return boolean - */ - boolean repair() default true; - - /** - * url鍖归厤瑙勫垯 - * - * @return String[] - */ - String[] value() default {}; - - /** - * 妯″潡ID锛屼竴涓狧ttpServlet灏介噺鍙湁鎻愪緵涓涓ā鍧楃殑鏈嶅姟 - * - * @return int - */ - int moduleid() default 0; - - /** - * 澶囨敞鎻忚堪 - * - * @return String - */ - String comment() default ""; -} +/* + * 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 java.lang.annotation.*; + +/** + * 鍔熻兘鍚孞SR 315 (java-servlet 3.0) 瑙勮寖涓殑 @WebServlet + * + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@Documented +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +public @interface WebServlet { + + /** + * HttpServlet璧勬簮鍚 + * + * @return String + */ + String name() default ""; + + /** + * 鏄惁鑷姩娣诲姞url鍓嶇紑, 瀵瑰簲application.xml涓璼ervlets鑺傜偣鐨刾ath灞炴 + * + * @return boolean + */ + boolean repair() default true; + + /** + * url鍖归厤瑙勫垯 + * + * @return String[] + */ + String[] value() default {}; + + /** + * 妯″潡ID锛屼竴涓狧ttpServlet灏介噺鍙湁鎻愪緵涓涓ā鍧楃殑鏈嶅姟 + * + * @return int + */ + int moduleid() default 0; + + /** + * 澶囨敞鎻忚堪 + * + * @return String + */ + String comment() default ""; +} diff --git a/src/main/java/org/redkale/net/http/WebSocket.java b/src/main/java/org/redkale/net/http/WebSocket.java index d8f98bfd7..f459aacbc 100644 --- a/src/main/java/org/redkale/net/http/WebSocket.java +++ b/src/main/java/org/redkale/net/http/WebSocket.java @@ -1,921 +1,921 @@ -/* - * 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.http.WebSocketPacket.FrameType; -import java.io.*; -import java.net.*; -import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; -import java.util.*; -import java.util.concurrent.*; -import java.util.function.*; -import java.util.logging.*; -import java.util.stream.Stream; -import java.util.zip.*; -import org.redkale.convert.Convert; -import org.redkale.net.AsyncConnection; -import org.redkale.util.Comment; - -/** - *

- * 涓涓猈ebSocket杩炴帴瀵瑰簲涓涓猈ebSocket瀹炰綋锛屽嵆涓涓猈ebSocket浼氱粦瀹氫竴涓猅CP杩炴帴銆
- * 鍗忚涓婄鍚圚TML5瑙勮寖, 鍏舵祦绋嬮『搴忓涓:
- *      1.1 onOpen 鑻ヨ繑鍥瀗ull锛岃涓篧ebSocket鐨勮繛鎺ヤ笉鍚堟硶锛屽己鍒跺叧闂璚ebSocket杩炴帴锛涢氬父鐢ㄤ簬鍒ゆ柇鐧诲綍鎬併
- *      1.2 createUserid 鑻ヨ繑鍥瀗ull锛岃涓篧ebSocket鐨勮繛鎺ヤ笉鍚堟硶锛屽己鍒跺叧闂璚ebSocket杩炴帴锛涢氬父鐢ㄤ簬鍒ゆ柇鐢ㄦ埛鏉冮檺鏄惁绗﹀悎銆
- *      1.3 onConnected WebSocket鎴愬姛杩炴帴鍚庡湪鍑嗗鎺ユ敹鏁版嵁鍓嶅洖璋冩鏂规硶銆
- *      1.4 onMessage/onFragment+ WebSocket鎺ユ敹鍒版秷鎭悗鍥炶皟姝ゆ秷鎭被鏂规硶銆
- *      1.5 onClose WebSocket琚叧闂悗鍥炶皟姝ゆ柟娉曘
- *  鏅氭ā寮忎笅 浠ヤ笂鏂规硶閮藉簲璇ヨ閲嶈浇銆
- * 
- *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Groupid鐨勬硾鍨 - * @param Message鐨勬硾鍨 - */ -public abstract class WebSocket { - - //--------------------------- CLOSECODE ------------------------------- - @Comment("鏈嶅姟鍣ㄤ富鍔ㄥ叧闂") - public static final int CLOSECODE_SERVERCLOSE = 3001; - - @Comment("瀹㈡埛绔富鍔ㄥ叧闂") - public static final int CLOSECODE_CLIENTCLOSE = 3002; - - @Comment("寮傚父鍏抽棴") - public static final int CLOSECODE_WSEXCEPTION = 3003; - - @Comment("寮傚父鏁版嵁寮哄埗鍏抽棴") - public static final int CLOSECODE_ILLPACKET = 3004; - - //---------------------------- RETCODE -------------------------------- - @Comment("娑堟伅涓嶅悎娉") - public static final int RETCODE_SEND_ILLPACKET = 1 << 1; //2 - - @Comment("WebSocket宸茬粡鍏抽棴") - public static final int RETCODE_WSOCKET_CLOSED = 1 << 2; //4 - - @Comment("Socket鐨刡uffer涓嶅悎娉") - public static final int RETCODE_ILLEGALBUFFER = 1 << 3; //8 - - @Comment("WebSocket鍙戦佹秷鎭紓甯") - public static final int RETCODE_SENDEXCEPTION = 1 << 4; //16 - - @Comment("WebSocketEngine瀹炰緥涓嶅瓨鍦") - public static final int RETCODE_ENGINE_NULL = 1 << 5; //32 - - @Comment("WebSocketNode瀹炰緥涓嶅瓨鍦") - public static final int RETCODE_NODESERVICE_NULL = 1 << 6; //64 - - @Comment("WebSocket缁勪负绌, 琛ㄧず鏃燱ebSocket杩炴帴") - public static final int RETCODE_GROUP_EMPTY = 1 << 7; //128 - - @Comment("WebSocket宸茬绾") - public static final int RETCODE_WSOFFLINE = 1 << 8; //256 - - @Comment("WebSocket灏嗗欢杩熷彂閫") - public static final int RETCODE_DEAYSEND = 1 << 9; //512 - - WebSocketEngine _engine; //涓嶅彲鑳戒负绌 - - //WebSocketRunner _runner; //涓嶅彲鑳戒负绌 - WebSocketReadHandler _readHandler; - - WebSocketWriteHandler _writeHandler; - - InetSocketAddress _sncpAddress; //鍒嗗竷寮忎笅涓嶅彲涓虹┖ - - AsyncConnection _channel;//涓嶅彲鑳戒负绌 - - String _sessionid; //涓嶅彲鑳戒负绌 - - G _userid; //涓嶅彲鑳戒负绌 - - SocketAddress _remoteAddress;//涓嶅彲鑳戒负绌 - - String _remoteAddr;//涓嶅彲鑳戒负绌 - - Convert _textConvert; //涓嶅彲鑳戒负绌 - - Convert _binaryConvert; //鍙兘涓虹┖ - - Convert _sendConvert; //涓嶅彲鑳戒负绌 - - java.lang.reflect.Type _messageTextType; //涓嶅彲鑳戒负绌 - - Deflater deflater; //鍘嬬缉 - - Inflater inflater; //瑙e帇 - - long createtime = System.currentTimeMillis(); - - List delayPackets; - - private Map attributes = new HashMap<>(); //闈炵嚎绋嬪畨鍏 - - private long lastPingTime; - - long lastReadTime; - - long lastSendTime; - - boolean initiateClosed; //鏀跺埌瀹㈡埛绔彂閫佺殑CLOSE娑堟伅 - - private boolean closed = false; - - protected WebSocket() { - } - - //---------------------------------------------------------------- - public final CompletableFuture sendPing() { - this.lastPingTime = System.currentTimeMillis(); - //if (_engine.finest) _engine.logger.finest(this + " on "+_engine.getEngineid()+" ping..."); - return sendPacket(WebSocketPacket.DEFAULT_PING_PACKET); - } - - public final CompletableFuture sendPing(byte[] data) { - if (data == null) return sendPing(); - this.lastPingTime = System.currentTimeMillis(); - return sendPacket(new WebSocketPacket(FrameType.PING, data)); - } - - public final CompletableFuture sendPong(byte[] data) { - return sendPacket(new WebSocketPacket(FrameType.PONG, data)); - } - - public final long getCreatetime() { - return createtime; - } - - /** - * 缁欒嚜韬彂閫佹秷鎭, 娑堟伅绫诲瀷鏄疭tring鎴朾yte[]鎴栧彲JavaBean瀵硅薄 - * - * @param message 涓嶅彲涓虹┖, 鍙兘鏄疭tring鎴朾yte[]鎴栧彲JavaBean瀵硅薄 - * - * @return 0琛ㄧず鎴愬姛锛 闈0琛ㄧず閿欒鐮 - */ - public final CompletableFuture send(Object message) { - return send(message, true); - } - - /** - * 缁欒嚜韬彂閫佹秷鎭, 娑堟伅绫诲瀷鏄疭tring鎴朾yte[]鎴栧彲JavaBean瀵硅薄 - * - * @param message 涓嶅彲涓虹┖, 鍙兘鏄疭tring鎴朾yte[]鎴栧彲JavaBean瀵硅薄 - * @param last 鏄惁鏈鍚庝竴鏉 - * - * @return 0琛ㄧず鎴愬姛锛 闈0琛ㄧず閿欒鐮 - */ - public final CompletableFuture send(Object message, boolean last) { - if (message instanceof CompletableFuture) { - return ((CompletableFuture) message).thenCompose((json) -> { - if (json instanceof CharSequence) { - return sendPacket(new WebSocketPacket(json.toString(), last)); - } else if (json == null || json instanceof byte[]) { - return sendPacket(new WebSocketPacket((byte[]) json, last)); - } else if (message instanceof WebSocketPacket) { - return sendPacket((WebSocketPacket) message); - } else { - Convert convert = getSendConvert(); - return sendPacket(new WebSocketPacket(convert.isBinary() ? FrameType.BINARY : FrameType.TEXT, convert.convertToBytes(json), last)); - } - }); - } - Object json = message; - if (json instanceof CharSequence) { - return sendPacket(new WebSocketPacket(FrameType.TEXT, json.toString().getBytes(StandardCharsets.UTF_8), last)); - } else if (json == null || json instanceof byte[]) { - return sendPacket(new WebSocketPacket(FrameType.BINARY, (byte[]) json, last)); - } else if (message instanceof WebSocketPacket) { - return sendPacket((WebSocketPacket) message); - } else { - Convert convert = getSendConvert(); - return sendPacket(new WebSocketPacket(convert.isBinary() ? FrameType.BINARY : FrameType.TEXT, convert.convertToBytes(json), last)); - } - } - - /** - * 缁欒嚜韬彂閫佹秷鎭, 娑堟伅绫诲瀷鏄疛avaBean瀵硅薄 - * - * @param convert Convert - * @param message 涓嶅彲涓虹┖, 鍙兘鏄疛SON瀵硅薄 - * - * @return 0琛ㄧず鎴愬姛锛 闈0琛ㄧず閿欒鐮 - */ - public final CompletableFuture send(Convert convert, Object message) { - return send(convert, message, true); - } - - /** - * 缁欒嚜韬彂閫佹秷鎭, 娑堟伅绫诲瀷鏄疛avaBean瀵硅薄 - * - * @param convert Convert - * @param message 涓嶅彲涓虹┖, 鍙兘鏄疛avaBean瀵硅薄 - * @param last 鏄惁鏈鍚庝竴鏉 - * - * @return 0琛ㄧず鎴愬姛锛 闈0琛ㄧず閿欒鐮 - */ - public final CompletableFuture send(Convert convert, Object message, boolean last) { - final Convert c = convert == null ? getSendConvert() : convert; - if (message instanceof CompletableFuture) { - return ((CompletableFuture) message).thenCompose((json) -> sendPacket(new WebSocketPacket(c.isBinary() ? FrameType.BINARY : FrameType.TEXT, c.convertToBytes(json), last))); - } - return sendPacket(new WebSocketPacket(c.isBinary() ? FrameType.BINARY : FrameType.TEXT, c.convertToBytes(message), last)); - } - - /** - * 缁欒嚜韬彂閫佹秷鎭綋, 鍖呭惈浜岃繘鍒/鏂囨湰 - * - * @param packet WebSocketPacket - * - * @return 0琛ㄧず鎴愬姛锛 闈0琛ㄧず閿欒鐮 - */ - CompletableFuture sendPacket(WebSocketPacket packet) { - if (this._writeHandler == null) { - if (delayPackets == null) delayPackets = new ArrayList<>(); - delayPackets.add(packet); - return CompletableFuture.completedFuture(RETCODE_DEAYSEND); - } - CompletableFuture rs = this._writeHandler.send(packet); - if (_engine.logger.isLoggable(Level.FINER) && packet != WebSocketPacket.DEFAULT_PING_PACKET) { - _engine.logger.finer("userid:" + getUserid() + " send websocket message(" + packet + ")" + " on " + this); - } - return rs == null ? CompletableFuture.completedFuture(RETCODE_WSOCKET_CLOSED) : rs; - } - - //---------------------------------------------------------------- - /** - * 缁欐寚瀹歶serid鐨刉ebSocket鑺傜偣鍙戦 浜岃繘鍒舵秷鎭/鏂囨湰娑堟伅/JavaBean瀵硅薄娑堟伅 - * - * @param message 涓嶅彲涓虹┖ - * @param userids Stream - * - * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀哄紓甯 - */ - public final CompletableFuture sendMessage(Object message, Stream userids) { - return sendMessage(message, true, userids); - } - - /** - * 缁欐寚瀹歶serid鐨刉ebSocket鑺傜偣鍙戦 浜岃繘鍒舵秷鎭/鏂囨湰娑堟伅/JavaBean瀵硅薄娑堟伅 - * - * @param message 涓嶅彲涓虹┖ - * @param userids Serializable[] - * - * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀哄紓甯 - */ - public final CompletableFuture sendMessage(Object message, G... userids) { - return sendMessage(message, true, userids); - } - - /** - * 缁欐寚瀹歶serid鐨刉ebSocket鑺傜偣鍙戦 浜岃繘鍒舵秷鎭/鏂囨湰娑堟伅/JavaBean瀵硅薄娑堟伅 - * - * @param convert Convert - * @param message 涓嶅彲涓虹┖ - * @param userids Stream - * - * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀哄紓甯 - */ - public final CompletableFuture sendMessage(final Convert convert, Object message, Stream userids) { - return sendMessage(convert, message, true, userids); - } - - /** - * 缁欐寚瀹歶serid鐨刉ebSocket鑺傜偣鍙戦 浜岃繘鍒舵秷鎭/鏂囨湰娑堟伅/JavaBean瀵硅薄娑堟伅 - * - * @param convert Convert - * @param message 涓嶅彲涓虹┖ - * @param userids Serializable[] - * - * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀哄紓甯 - */ - public final CompletableFuture sendMessage(final Convert convert, Object message, G... userids) { - return sendMessage(convert, message, true, userids); - } - - /** - * 缁欐寚瀹歶serid鐨刉ebSocket鑺傜偣鍙戦 浜岃繘鍒舵秷鎭/鏂囨湰娑堟伅/JavaBean瀵硅薄娑堟伅 - * - * @param message 涓嶅彲涓虹┖ - * @param last 鏄惁鏈鍚庝竴鏉 - * @param userids Serializable[] - * - * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀哄紓甯 - */ - public final CompletableFuture sendMessage(Object message, boolean last, Stream userids) { - return sendMessage((Convert) null, message, last, userids); - } - - /** - * 缁欐寚瀹歶serid鐨刉ebSocket鑺傜偣鍙戦 浜岃繘鍒舵秷鎭/鏂囨湰娑堟伅/JavaBean瀵硅薄娑堟伅 - * - * @param message 涓嶅彲涓虹┖ - * @param last 鏄惁鏈鍚庝竴鏉 - * @param userids Serializable[] - * - * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀哄紓甯 - */ - public final CompletableFuture sendMessage(Object message, boolean last, G... userids) { - return sendMessage((Convert) null, message, last, userids); - } - - /** - * 缁欐寚瀹歶serid鐨刉ebSocket鑺傜偣鍙戦 浜岃繘鍒舵秷鎭/鏂囨湰娑堟伅/JavaBean瀵硅薄娑堟伅 - * - * @param convert Convert - * @param message 涓嶅彲涓虹┖ - * @param last 鏄惁鏈鍚庝竴鏉 - * @param userids Stream - * - * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀哄紓甯 - */ - public final CompletableFuture sendMessage(final Convert convert, Object message, boolean last, final Stream userids) { - Object[] array = userids.toArray(); - Serializable[] ss = new Serializable[array.length]; - for (int i = 0; i < array.length; i++) { - ss[i] = (Serializable) array[i]; - } - return sendMessage(convert, message, last, ss); - } - - /** - * 缁欐寚瀹歶serid鐨刉ebSocket鑺傜偣鍙戦 浜岃繘鍒舵秷鎭/鏂囨湰娑堟伅/JavaBean瀵硅薄娑堟伅 - * - * @param convert Convert - * @param message 涓嶅彲涓虹┖ - * @param last 鏄惁鏈鍚庝竴鏉 - * @param userids Serializable[] - * - * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀哄紓甯 - */ - public final CompletableFuture sendMessage(final Convert convert, Object message, boolean last, Serializable... userids) { - if (_engine.node == null) return CompletableFuture.completedFuture(RETCODE_NODESERVICE_NULL); - if (message instanceof CompletableFuture) { - return ((CompletableFuture) message).thenCompose((json) -> _engine.node.sendMessage(convert, json, last, userids)); - } - CompletableFuture rs = _engine.node.sendMessage(convert, message, last, userids); - if (_engine.logger.isLoggable(Level.FINER)) _engine.logger.finer("userids:" + Arrays.toString(userids) + " send websocket message(" + message + ")"); - return rs; - } - - /** - * 骞挎挱娑堟伅锛 缁欐墍鏈変汉鍙戞秷鎭 - * - * @param message 娑堟伅鍐呭 - * - * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 - */ - public final CompletableFuture broadcastMessage(final Object message) { - return broadcastMessage((Convert) null, message, true); - } - - /** - * 骞挎挱娑堟伅锛 缁欐墍鏈変汉鍙戞秷鎭 - * - * @param wsrange 杩囨护鏉′欢 - * @param message 娑堟伅鍐呭 - * - * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 - */ - public final CompletableFuture broadcastMessage(final WebSocketRange wsrange, final Object message) { - return broadcastMessage((WebSocketRange) null, (Convert) null, message, true); - } - - /** - * 骞挎挱娑堟伅锛 缁欐墍鏈変汉鍙戞秷鎭 - * - * @param convert Convert - * @param message 娑堟伅鍐呭 - * - * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 - */ - public final CompletableFuture broadcastMessage(final Convert convert, final Object message) { - return broadcastMessage(convert, message, true); - } - - /** - * 骞挎挱娑堟伅锛 缁欐墍鏈変汉鍙戞秷鎭 - * - * @param wsrange 杩囨护鏉′欢 - * @param convert Convert - * @param message 娑堟伅鍐呭 - * - * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 - */ - public final CompletableFuture broadcastMessage(final WebSocketRange wsrange, final Convert convert, final Object message) { - return broadcastMessage((WebSocketRange) null, convert, message, true); - } - - /** - * 骞挎挱娑堟伅锛 缁欐墍鏈変汉鍙戞秷鎭 - * - * @param message 娑堟伅鍐呭 - * @param last 鏄惁鏈鍚庝竴鏉 - * - * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 - */ - public final CompletableFuture broadcastMessage(final Object message, final boolean last) { - return broadcastMessage((Convert) null, message, last); - } - - /** - * 骞挎挱娑堟伅锛 缁欐墍鏈変汉鍙戞秷鎭 - * - * @param wsrange 杩囨护鏉′欢 - * @param message 娑堟伅鍐呭 - * @param last 鏄惁鏈鍚庝竴鏉 - * - * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 - */ - public final CompletableFuture broadcastMessage(final WebSocketRange wsrange, final Object message, final boolean last) { - return broadcastMessage(wsrange, (Convert) null, message, last); - } - - /** - * 骞挎挱娑堟伅锛 缁欐墍鏈変汉鍙戞秷鎭 - * - * @param convert Convert - * @param message 娑堟伅鍐呭 - * @param last 鏄惁鏈鍚庝竴鏉 - * - * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 - */ - public final CompletableFuture broadcastMessage(final Convert convert, final Object message, final boolean last) { - return broadcastMessage((WebSocketRange) null, convert, message, last); - } - - /** - * 骞挎挱娑堟伅锛 缁欐墍鏈変汉鍙戞秷鎭 - * - * @param wsrange 杩囨护鏉′欢 - * @param convert Convert - * @param message 娑堟伅鍐呭 - * @param last 鏄惁鏈鍚庝竴鏉 - * - * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 - */ - public final CompletableFuture broadcastMessage(final WebSocketRange wsrange, final Convert convert, final Object message, final boolean last) { - if (_engine.node == null) return CompletableFuture.completedFuture(RETCODE_NODESERVICE_NULL); - if (message instanceof CompletableFuture) { - return ((CompletableFuture) message).thenCompose((json) -> _engine.node.broadcastMessage(wsrange, convert, json, last)); - } - CompletableFuture rs = _engine.node.broadcastMessage(wsrange, convert, message, last); - if (_engine.logger.isLoggable(Level.FINER)) _engine.logger.finer("broadcast send websocket message(" + message + ")"); - return rs; - } - - /** - * 缁欐寚瀹歶serid鐨刉ebSocket鑺傜偣鍙戦佹搷浣 - * - * @param action 鎿嶄綔鍙傛暟 - * @param userids Serializable[] - * - * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀哄紓甯 - */ - public final CompletableFuture sendAction(final WebSocketAction action, Serializable... userids) { - if (_engine.node == null) return CompletableFuture.completedFuture(RETCODE_NODESERVICE_NULL); - CompletableFuture rs = _engine.node.sendAction(action, userids); - if (_engine.logger.isLoggable(Level.FINER)) _engine.logger.finer("userids:" + Arrays.toString(userids) + " send websocket action(" + action + ")"); - return rs; - } - - /** - * 骞挎挱鎿嶄綔锛 缁欐墍鏈変汉鍙戞搷浣滄寚浠 - * - * @param action 鎿嶄綔鍙傛暟 - * - * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 - */ - public final CompletableFuture broadcastAction(final WebSocketAction action) { - if (_engine.node == null) return CompletableFuture.completedFuture(RETCODE_NODESERVICE_NULL); - CompletableFuture rs = _engine.node.broadcastAction(action); - if (_engine.logger.isLoggable(Level.FINER)) _engine.logger.finer("broadcast send websocket action(" + action + ")"); - return rs; - } - - /** - * 鑾峰彇鐢ㄦ埛鍦ㄧ嚎鐨凷NCP鑺傜偣鍦板潃鍒楄〃锛屼笉鏄垎甯冨紡鍒欒繑鍥炲厓绱犳暟閲忎负1锛屼笖鍏冪礌鍊间负null鐨勫垪琛
- * InetSocketAddress 涓 SNCP鑺傜偣鍦板潃 - * - * @param userid Serializable - * - * @return 鍦板潃鍒楄〃 - */ - public CompletableFuture> getRpcNodeAddresses(final Serializable userid) { - if (_engine.node == null) return CompletableFuture.completedFuture(null); - return _engine.node.getRpcNodeAddresses(userid); - } - - /** - * 鑾峰彇鍦ㄧ嚎鐢ㄦ埛鐨勮缁嗚繛鎺ヤ俊鎭
- * Map.key 涓 SNCP鑺傜偣鍦板潃, 鍚间负null鐨刱ey琛ㄧず娌℃湁鍒嗗竷寮 - * Map.value 涓 鐢ㄦ埛瀹㈡埛绔殑IP - * - * @param userid Serializable - * - * @return 鍦板潃闆嗗悎 - */ - public CompletableFuture>> getRpcNodeWebSocketAddresses(final Serializable userid) { - if (_engine.node == null) return CompletableFuture.completedFuture(null); - return _engine.node.getRpcNodeWebSocketAddresses(userid); - } - - /** - * 鏇存敼鏈琖ebSocket鐨剈serid - * - * @param newuserid 鏂扮敤鎴稩D锛屼笉鑳戒负null - * - * @return CompletableFuture - */ - public CompletableFuture changeUserid(final G newuserid) { - if (newuserid == null) throw new NullPointerException("newuserid is null"); - return _engine.changeLocalUserid(this, newuserid); - } - - /** - * 寮哄埗鍏抽棴鐢ㄦ埛鐨勬墍鏈塛ebSocket - * - * @param userid Serializable - * - * @return int - */ - @Comment("寮哄埗鍏抽棴鐢ㄦ埛鐨勬墍鏈塛ebSocket") - public CompletableFuture forceCloseWebSocket(Serializable userid) { - return _engine.node.forceCloseWebSocket(userid); - } - - /** - * 鑾峰彇WebSocketNode - * - * - * @return WebSocketNode - */ - @Comment("鑾峰彇WebSocketNode") - public final WebSocketNode webSocketNode() { - return _engine.node; - } - - /** - * 鑾峰彇褰撳墠WebSocket涓嬬殑灞炴э紝闈炵嚎绋嬪畨鍏 - * - * @param 灞炴у肩殑绫诲瀷 - * @param name 灞炴у悕 - * - * @return 灞炴у - */ - @SuppressWarnings("unchecked") - public final V getAttribute(String name) { - return attributes == null ? null : (V) attributes.get(name); - } - - /** - * 绉诲嚭褰撳墠WebSocket涓嬬殑灞炴э紝闈炵嚎绋嬪畨鍏 - * - * @param 灞炴у肩殑绫诲瀷 - * @param name 灞炴у悕 - * - * @return 灞炴у - */ - public final V removeAttribute(String name) { - return attributes == null ? null : (V) attributes.remove(name); - } - - /** - * 缁欏綋鍓峎ebSocket涓嬬殑澧炲姞灞炴э紝闈炵嚎绋嬪畨鍏 - * - * @param name 灞炴у - * @param value 灞炴у - */ - public final void setAttribute(String name, Object value) { - if (attributes == null) attributes = new HashMap<>(); - attributes.put(name, value); - } - - /** - * 鑾峰彇褰撳墠WebSocket鎵灞炵殑userid - * - * @return userid - */ - public final G getUserid() { - return _userid; - } - - /** - * 鑾峰彇褰撳墠WebSocket鐨勪細璇滻D锛 涓嶄細涓簄ull - * - * @return sessionid - */ - public final String getSessionid() { - return _sessionid; - } - - /** - * 鑾峰彇瀹㈡埛绔洿鎺ュ湴鍧, 褰揥ebSocket杩炴帴鏄敱浠g悊鏈嶅姟鍣ㄨ浆鍙戠殑锛屽垯璇ュ煎浐瀹氫负浠g悊鏈嶅姟鍣ㄧ殑IP鍦板潃 - * - * @return SocketAddress - */ - public final SocketAddress getRemoteAddress() { - return _remoteAddress; - } - - /** - * 鑾峰彇瀹㈡埛绔湡瀹炲湴鍧 鍚 HttpRequest.getRemoteAddr() - * - * @return String - */ - public final String getRemoteAddr() { - return _remoteAddr; - } - - protected Convert getTextConvert() { - return _textConvert; - } - - protected Convert getBinaryConvert() { - return _binaryConvert; - } - - protected Convert getSendConvert() { - return _sendConvert; - } - - //------------------------------------------------------------------- - /** - * 鑾峰彇鎸囧畾userid鐨刉ebSocket鏁扮粍, 娌℃湁杩斿洖null
- * 姝ゆ柟娉曠敤浜庡崟鐢ㄦ埛澶氳繛鎺ユā寮 - * - * @param userid Serializable - * - * @return WebSocket闆嗗悎 - */ - protected final Stream getLocalWebSockets(G userid) { - return _engine.getLocalWebSockets(userid); - } - - /** - * 鑾峰彇鎸囧畾userid鐨刉ebSocket鏁扮粍, 娌℃湁杩斿洖null
- * 姝ゆ柟娉曠敤浜庡崟鐢ㄦ埛鍗曡繛鎺ユā寮 - * - * @param userid Serializable - * - * @return WebSocket - */ - protected final WebSocket findLocalWebSocket(G userid) { - return _engine.findLocalWebSocket(userid); - } - - /** - * 鑾峰彇褰撳墠杩涚▼鑺傜偣鎵鏈夊湪绾跨殑WebSocket - * - * @return WebSocketGroup鍒楄〃 - */ - protected final Collection getLocalWebSockets() { - return _engine.getLocalWebSockets(); - } - - /** - * 鑾峰彇ByteBuffer鐢熸垚鍣 - * - * @return Supplier - */ - protected Supplier getBufferSupplier() { - return this._channel.getBufferSupplier(); - } - - /** - * 鑾峰彇ByteBuffer鍥炴敹鍣 - * - * @return Consumer - */ - protected Consumer getBufferConsumer() { - return this._channel.getBufferConsumer(); - } - - //------------------------------------------------------------------- - /** - * 杩斿洖sessionid, null琛ㄧず杩炴帴涓嶅悎娉曟垨寮傚父,榛樿瀹炵幇鏄痳equest.sessionid(true)锛岄氬父闇瑕侀噸鍐欒鏂规硶 - * - * @param request HttpRequest - * - * @return sessionid - */ - protected CompletableFuture onOpen(final HttpRequest request) { - return CompletableFuture.completedFuture(request.getSessionid(true)); - } - - /** - * 鍒涘缓userid锛 null琛ㄧず寮傚父锛 蹇呴』瀹炵幇璇ユ柟娉 - * - * @return userid - */ - protected abstract CompletableFuture createUserid(); - - /** - * WebSocket.broadcastMessage鏃剁殑杩囨护鏉′欢 - * - * @param wsrange 杩囨护鏉′欢 - * - * @return boolean - */ - protected boolean predicate(WebSocketRange wsrange) { - return true; - } - - /** - * WebSocket.broadcastAction鏃剁殑鎿嶄綔 - * - * @param action 鎿嶄綔鍙傛暟 - * - * @return CompletableFuture - * - */ - protected CompletableFuture action(WebSocketAction action) { - return CompletableFuture.completedFuture(0); - } - - /** - * WebSokcet杩炴帴鎴愬姛鍚庣殑鍥炶皟鏂规硶 - * - * @return Future 鍙互涓簄ull - */ - public CompletableFuture onConnected() { - return null; - } - - /** - * ping鍚庣殑鍥炶皟鏂规硶 - * - * @param bytes 鏁版嵁 - */ - public void onPing(byte[] bytes) { - } - - /** - * pong鍚庣殑鍥炶皟鏂规硶 - * - * @param bytes 鏁版嵁 - */ - public void onPong(byte[] bytes) { - } - - /** - * - * 鎺ユ敹鍒版秷鎭墠鐨勬嫤鎴柟娉曪紝 ping/pong涓嶅湪鍏跺唴
- * 娉ㄦ剰锛氬鐞嗗畬鍚庨渶瑕佽皟鐢 messageEvent.run() 鎵嶈兘鍝嶅簲onMessage - * - * @param restmapping Rest鐨勬柟娉曞悕锛屾病鏈夊垯涓虹┖瀛楃涓 - * @param param onMessage鏂规硶鐨勫弬鏁 - * @param messageEvent onMessage浜嬩欢 - */ - public void preOnMessage(String restmapping, WebSocketParam param, Runnable messageEvent) { - messageEvent.run(); - } - - /** - * 鎺ユ敹鍒版秷鎭殑鍥炶皟鏂规硶 - * - * @param message 娑堟伅 - * @param last 鏄惁鏈鍚庝竴鏉 - */ - public void onMessage(T message, boolean last) { - } - - /** - * 鎺ユ敹鍒版枃鏈秷鎭殑鍥炶皟鏂规硶 - * - * @param text 娑堟伅 - * @param last 鏄惁鏈鍚庝竴鏉 - */ - public void onMessage(String text, boolean last) { - } - - /** - * 鎺ユ敹鍒颁簩杩涘埗娑堟伅鐨勫洖璋冩柟娉 - * - * @param bytes 娑堟伅 - * @param last 鏄惁鏈鍚庝竴鏉 - */ - public void onMessage(byte[] bytes, boolean last) { - } - - /** - * 鍏抽棴鐨勫洖璋冩柟娉曪紝璋冪敤姝ゆ柟娉曟椂WebSocket宸茬粡琚叧闂 - * - * @param code 缁撴灉鐮侊紝闈0琛ㄧず闈炴甯稿叧闂 - * @param reason 鍏抽棴鍘熷洜 - * - * @return Future 鍙互涓簄ull - */ - public CompletableFuture onClose(int code, String reason) { - return null; - } - - /** - * 鍙戠敓寮傚父鏃惰皟鐢 - * - * @param t 寮傚父 - * @param buffers ByteBuffer[] - */ - public void onOccurException(Throwable t, ByteBuffer[] buffers) { - this.getLogger().log(Level.SEVERE, "WebSocket receive or send Message error", t); - } - - /** - * 褰揝ingle妯″紡涓嬬敤鎴烽噸澶嶇櫥褰曟椂鍥炶皟鍑芥暟锛岄粯璁ゅ鐞嗘柟寮: 鍏抽棴鏃ц繛鎺 - * - * @return Future 鍙互涓簄ull, 涓簄ull鎴栬匜uture鍊间负false琛ㄧず鍏抽棴鏂拌繛鎺ワ紝 Future鍊间负true琛ㄧず鍏抽棴鏃ц繛鎺 - */ - public CompletableFuture onSingleRepeatConnect() { - return forceCloseWebSocket(getUserid()).thenApply((r) -> true); - } - - /** - * 鑾峰彇鍒嗗竷寮忔儏鍐典笅鐨凷NCP鍦板潃, 闈炲垎甯冨紡涓嬩负null - * - * @return InetSocketAddress sncpAddress - */ - public InetSocketAddress getSncpAddress() { - return _sncpAddress; - } - - /** - * 鑾峰彇Logger - * - * @return Logger Logger - */ - public Logger getLogger() { - return this._engine.logger; - } - - /** - * 鑾峰彇鏈鍚庝竴娆″彂閫佹秷鎭殑鏃堕棿 - * - * @return long - */ - public long getLastSendTime() { - return this.lastSendTime; - } - - /** - * 鑾峰彇鏈鍚庝竴娆¤鍙栨秷鎭殑鏃堕棿 - * - * @return long - */ - public long getLastReadTime() { - return this.lastReadTime; - } - - /** - * 鑾峰彇鏈鍚庝竴娆″彂閫丳ING娑堟伅鐨勬椂闂 - * - * @return long - */ - public long getLastPingTime() { - return this.lastPingTime; - } - - /** - * 鏄惧紡鍦板叧闂璚ebSocket - */ - public final void close() { - if (this.deflater != null) this.deflater.end(); - if (this.inflater != null) this.inflater.end(); - CompletableFuture future = kill(CLOSECODE_SERVERCLOSE, "user close"); - if (future != null) future.join(); - } - - //closeRunner - CompletableFuture kill(int code, String reason) { - if (closed) return null; - synchronized (this) { - if (closed) return null; - closed = true; - if (_channel == null) return null; - CompletableFuture future = _engine.removeLocalThenDisconnect(this); - _channel.dispose(); - CompletableFuture closeFuture = onClose(code, reason); - if (closeFuture == null) return future; - return CompletableFuture.allOf(future, closeFuture); - } - } - - /** - * 鏄惁鍏抽棴 - * - * @return boolean - */ - public final boolean isClosed() { - return this.closed; - } - - @Override - public String toString() { - return this.getUserid() + "@" + _remoteAddr + "@" + Objects.hashCode(this); - } -} +/* + * 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.http.WebSocketPacket.FrameType; +import java.io.*; +import java.net.*; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.concurrent.*; +import java.util.function.*; +import java.util.logging.*; +import java.util.stream.Stream; +import java.util.zip.*; +import org.redkale.convert.Convert; +import org.redkale.net.AsyncConnection; +import org.redkale.util.Comment; + +/** + *

+ * 涓涓猈ebSocket杩炴帴瀵瑰簲涓涓猈ebSocket瀹炰綋锛屽嵆涓涓猈ebSocket浼氱粦瀹氫竴涓猅CP杩炴帴銆
+ * 鍗忚涓婄鍚圚TML5瑙勮寖, 鍏舵祦绋嬮『搴忓涓:
+ *      1.1 onOpen 鑻ヨ繑鍥瀗ull锛岃涓篧ebSocket鐨勮繛鎺ヤ笉鍚堟硶锛屽己鍒跺叧闂璚ebSocket杩炴帴锛涢氬父鐢ㄤ簬鍒ゆ柇鐧诲綍鎬併
+ *      1.2 createUserid 鑻ヨ繑鍥瀗ull锛岃涓篧ebSocket鐨勮繛鎺ヤ笉鍚堟硶锛屽己鍒跺叧闂璚ebSocket杩炴帴锛涢氬父鐢ㄤ簬鍒ゆ柇鐢ㄦ埛鏉冮檺鏄惁绗﹀悎銆
+ *      1.3 onConnected WebSocket鎴愬姛杩炴帴鍚庡湪鍑嗗鎺ユ敹鏁版嵁鍓嶅洖璋冩鏂规硶銆
+ *      1.4 onMessage/onFragment+ WebSocket鎺ユ敹鍒版秷鎭悗鍥炶皟姝ゆ秷鎭被鏂规硶銆
+ *      1.5 onClose WebSocket琚叧闂悗鍥炶皟姝ゆ柟娉曘
+ *  鏅氭ā寮忎笅 浠ヤ笂鏂规硶閮藉簲璇ヨ閲嶈浇銆
+ * 
+ *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Groupid鐨勬硾鍨 + * @param Message鐨勬硾鍨 + */ +public abstract class WebSocket { + + //--------------------------- CLOSECODE ------------------------------- + @Comment("鏈嶅姟鍣ㄤ富鍔ㄥ叧闂") + public static final int CLOSECODE_SERVERCLOSE = 3001; + + @Comment("瀹㈡埛绔富鍔ㄥ叧闂") + public static final int CLOSECODE_CLIENTCLOSE = 3002; + + @Comment("寮傚父鍏抽棴") + public static final int CLOSECODE_WSEXCEPTION = 3003; + + @Comment("寮傚父鏁版嵁寮哄埗鍏抽棴") + public static final int CLOSECODE_ILLPACKET = 3004; + + //---------------------------- RETCODE -------------------------------- + @Comment("娑堟伅涓嶅悎娉") + public static final int RETCODE_SEND_ILLPACKET = 1 << 1; //2 + + @Comment("WebSocket宸茬粡鍏抽棴") + public static final int RETCODE_WSOCKET_CLOSED = 1 << 2; //4 + + @Comment("Socket鐨刡uffer涓嶅悎娉") + public static final int RETCODE_ILLEGALBUFFER = 1 << 3; //8 + + @Comment("WebSocket鍙戦佹秷鎭紓甯") + public static final int RETCODE_SENDEXCEPTION = 1 << 4; //16 + + @Comment("WebSocketEngine瀹炰緥涓嶅瓨鍦") + public static final int RETCODE_ENGINE_NULL = 1 << 5; //32 + + @Comment("WebSocketNode瀹炰緥涓嶅瓨鍦") + public static final int RETCODE_NODESERVICE_NULL = 1 << 6; //64 + + @Comment("WebSocket缁勪负绌, 琛ㄧず鏃燱ebSocket杩炴帴") + public static final int RETCODE_GROUP_EMPTY = 1 << 7; //128 + + @Comment("WebSocket宸茬绾") + public static final int RETCODE_WSOFFLINE = 1 << 8; //256 + + @Comment("WebSocket灏嗗欢杩熷彂閫") + public static final int RETCODE_DEAYSEND = 1 << 9; //512 + + WebSocketEngine _engine; //涓嶅彲鑳戒负绌 + + //WebSocketRunner _runner; //涓嶅彲鑳戒负绌 + WebSocketReadHandler _readHandler; + + WebSocketWriteHandler _writeHandler; + + InetSocketAddress _sncpAddress; //鍒嗗竷寮忎笅涓嶅彲涓虹┖ + + AsyncConnection _channel;//涓嶅彲鑳戒负绌 + + String _sessionid; //涓嶅彲鑳戒负绌 + + G _userid; //涓嶅彲鑳戒负绌 + + SocketAddress _remoteAddress;//涓嶅彲鑳戒负绌 + + String _remoteAddr;//涓嶅彲鑳戒负绌 + + Convert _textConvert; //涓嶅彲鑳戒负绌 + + Convert _binaryConvert; //鍙兘涓虹┖ + + Convert _sendConvert; //涓嶅彲鑳戒负绌 + + java.lang.reflect.Type _messageTextType; //涓嶅彲鑳戒负绌 + + Deflater deflater; //鍘嬬缉 + + Inflater inflater; //瑙e帇 + + long createtime = System.currentTimeMillis(); + + List delayPackets; + + private Map attributes = new HashMap<>(); //闈炵嚎绋嬪畨鍏 + + private long lastPingTime; + + long lastReadTime; + + long lastSendTime; + + boolean initiateClosed; //鏀跺埌瀹㈡埛绔彂閫佺殑CLOSE娑堟伅 + + private boolean closed = false; + + protected WebSocket() { + } + + //---------------------------------------------------------------- + public final CompletableFuture sendPing() { + this.lastPingTime = System.currentTimeMillis(); + //if (_engine.finest) _engine.logger.finest(this + " on "+_engine.getEngineid()+" ping..."); + return sendPacket(WebSocketPacket.DEFAULT_PING_PACKET); + } + + public final CompletableFuture sendPing(byte[] data) { + if (data == null) return sendPing(); + this.lastPingTime = System.currentTimeMillis(); + return sendPacket(new WebSocketPacket(FrameType.PING, data)); + } + + public final CompletableFuture sendPong(byte[] data) { + return sendPacket(new WebSocketPacket(FrameType.PONG, data)); + } + + public final long getCreatetime() { + return createtime; + } + + /** + * 缁欒嚜韬彂閫佹秷鎭, 娑堟伅绫诲瀷鏄疭tring鎴朾yte[]鎴栧彲JavaBean瀵硅薄 + * + * @param message 涓嶅彲涓虹┖, 鍙兘鏄疭tring鎴朾yte[]鎴栧彲JavaBean瀵硅薄 + * + * @return 0琛ㄧず鎴愬姛锛 闈0琛ㄧず閿欒鐮 + */ + public final CompletableFuture send(Object message) { + return send(message, true); + } + + /** + * 缁欒嚜韬彂閫佹秷鎭, 娑堟伅绫诲瀷鏄疭tring鎴朾yte[]鎴栧彲JavaBean瀵硅薄 + * + * @param message 涓嶅彲涓虹┖, 鍙兘鏄疭tring鎴朾yte[]鎴栧彲JavaBean瀵硅薄 + * @param last 鏄惁鏈鍚庝竴鏉 + * + * @return 0琛ㄧず鎴愬姛锛 闈0琛ㄧず閿欒鐮 + */ + public final CompletableFuture send(Object message, boolean last) { + if (message instanceof CompletableFuture) { + return ((CompletableFuture) message).thenCompose((json) -> { + if (json instanceof CharSequence) { + return sendPacket(new WebSocketPacket(json.toString(), last)); + } else if (json == null || json instanceof byte[]) { + return sendPacket(new WebSocketPacket((byte[]) json, last)); + } else if (message instanceof WebSocketPacket) { + return sendPacket((WebSocketPacket) message); + } else { + Convert convert = getSendConvert(); + return sendPacket(new WebSocketPacket(convert.isBinary() ? FrameType.BINARY : FrameType.TEXT, convert.convertToBytes(json), last)); + } + }); + } + Object json = message; + if (json instanceof CharSequence) { + return sendPacket(new WebSocketPacket(FrameType.TEXT, json.toString().getBytes(StandardCharsets.UTF_8), last)); + } else if (json == null || json instanceof byte[]) { + return sendPacket(new WebSocketPacket(FrameType.BINARY, (byte[]) json, last)); + } else if (message instanceof WebSocketPacket) { + return sendPacket((WebSocketPacket) message); + } else { + Convert convert = getSendConvert(); + return sendPacket(new WebSocketPacket(convert.isBinary() ? FrameType.BINARY : FrameType.TEXT, convert.convertToBytes(json), last)); + } + } + + /** + * 缁欒嚜韬彂閫佹秷鎭, 娑堟伅绫诲瀷鏄疛avaBean瀵硅薄 + * + * @param convert Convert + * @param message 涓嶅彲涓虹┖, 鍙兘鏄疛SON瀵硅薄 + * + * @return 0琛ㄧず鎴愬姛锛 闈0琛ㄧず閿欒鐮 + */ + public final CompletableFuture send(Convert convert, Object message) { + return send(convert, message, true); + } + + /** + * 缁欒嚜韬彂閫佹秷鎭, 娑堟伅绫诲瀷鏄疛avaBean瀵硅薄 + * + * @param convert Convert + * @param message 涓嶅彲涓虹┖, 鍙兘鏄疛avaBean瀵硅薄 + * @param last 鏄惁鏈鍚庝竴鏉 + * + * @return 0琛ㄧず鎴愬姛锛 闈0琛ㄧず閿欒鐮 + */ + public final CompletableFuture send(Convert convert, Object message, boolean last) { + final Convert c = convert == null ? getSendConvert() : convert; + if (message instanceof CompletableFuture) { + return ((CompletableFuture) message).thenCompose((json) -> sendPacket(new WebSocketPacket(c.isBinary() ? FrameType.BINARY : FrameType.TEXT, c.convertToBytes(json), last))); + } + return sendPacket(new WebSocketPacket(c.isBinary() ? FrameType.BINARY : FrameType.TEXT, c.convertToBytes(message), last)); + } + + /** + * 缁欒嚜韬彂閫佹秷鎭綋, 鍖呭惈浜岃繘鍒/鏂囨湰 + * + * @param packet WebSocketPacket + * + * @return 0琛ㄧず鎴愬姛锛 闈0琛ㄧず閿欒鐮 + */ + CompletableFuture sendPacket(WebSocketPacket packet) { + if (this._writeHandler == null) { + if (delayPackets == null) delayPackets = new ArrayList<>(); + delayPackets.add(packet); + return CompletableFuture.completedFuture(RETCODE_DEAYSEND); + } + CompletableFuture rs = this._writeHandler.send(packet); + if (_engine.logger.isLoggable(Level.FINER) && packet != WebSocketPacket.DEFAULT_PING_PACKET) { + _engine.logger.finer("userid:" + getUserid() + " send websocket message(" + packet + ")" + " on " + this); + } + return rs == null ? CompletableFuture.completedFuture(RETCODE_WSOCKET_CLOSED) : rs; + } + + //---------------------------------------------------------------- + /** + * 缁欐寚瀹歶serid鐨刉ebSocket鑺傜偣鍙戦 浜岃繘鍒舵秷鎭/鏂囨湰娑堟伅/JavaBean瀵硅薄娑堟伅 + * + * @param message 涓嶅彲涓虹┖ + * @param userids Stream + * + * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀哄紓甯 + */ + public final CompletableFuture sendMessage(Object message, Stream userids) { + return sendMessage(message, true, userids); + } + + /** + * 缁欐寚瀹歶serid鐨刉ebSocket鑺傜偣鍙戦 浜岃繘鍒舵秷鎭/鏂囨湰娑堟伅/JavaBean瀵硅薄娑堟伅 + * + * @param message 涓嶅彲涓虹┖ + * @param userids Serializable[] + * + * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀哄紓甯 + */ + public final CompletableFuture sendMessage(Object message, G... userids) { + return sendMessage(message, true, userids); + } + + /** + * 缁欐寚瀹歶serid鐨刉ebSocket鑺傜偣鍙戦 浜岃繘鍒舵秷鎭/鏂囨湰娑堟伅/JavaBean瀵硅薄娑堟伅 + * + * @param convert Convert + * @param message 涓嶅彲涓虹┖ + * @param userids Stream + * + * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀哄紓甯 + */ + public final CompletableFuture sendMessage(final Convert convert, Object message, Stream userids) { + return sendMessage(convert, message, true, userids); + } + + /** + * 缁欐寚瀹歶serid鐨刉ebSocket鑺傜偣鍙戦 浜岃繘鍒舵秷鎭/鏂囨湰娑堟伅/JavaBean瀵硅薄娑堟伅 + * + * @param convert Convert + * @param message 涓嶅彲涓虹┖ + * @param userids Serializable[] + * + * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀哄紓甯 + */ + public final CompletableFuture sendMessage(final Convert convert, Object message, G... userids) { + return sendMessage(convert, message, true, userids); + } + + /** + * 缁欐寚瀹歶serid鐨刉ebSocket鑺傜偣鍙戦 浜岃繘鍒舵秷鎭/鏂囨湰娑堟伅/JavaBean瀵硅薄娑堟伅 + * + * @param message 涓嶅彲涓虹┖ + * @param last 鏄惁鏈鍚庝竴鏉 + * @param userids Serializable[] + * + * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀哄紓甯 + */ + public final CompletableFuture sendMessage(Object message, boolean last, Stream userids) { + return sendMessage((Convert) null, message, last, userids); + } + + /** + * 缁欐寚瀹歶serid鐨刉ebSocket鑺傜偣鍙戦 浜岃繘鍒舵秷鎭/鏂囨湰娑堟伅/JavaBean瀵硅薄娑堟伅 + * + * @param message 涓嶅彲涓虹┖ + * @param last 鏄惁鏈鍚庝竴鏉 + * @param userids Serializable[] + * + * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀哄紓甯 + */ + public final CompletableFuture sendMessage(Object message, boolean last, G... userids) { + return sendMessage((Convert) null, message, last, userids); + } + + /** + * 缁欐寚瀹歶serid鐨刉ebSocket鑺傜偣鍙戦 浜岃繘鍒舵秷鎭/鏂囨湰娑堟伅/JavaBean瀵硅薄娑堟伅 + * + * @param convert Convert + * @param message 涓嶅彲涓虹┖ + * @param last 鏄惁鏈鍚庝竴鏉 + * @param userids Stream + * + * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀哄紓甯 + */ + public final CompletableFuture sendMessage(final Convert convert, Object message, boolean last, final Stream userids) { + Object[] array = userids.toArray(); + Serializable[] ss = new Serializable[array.length]; + for (int i = 0; i < array.length; i++) { + ss[i] = (Serializable) array[i]; + } + return sendMessage(convert, message, last, ss); + } + + /** + * 缁欐寚瀹歶serid鐨刉ebSocket鑺傜偣鍙戦 浜岃繘鍒舵秷鎭/鏂囨湰娑堟伅/JavaBean瀵硅薄娑堟伅 + * + * @param convert Convert + * @param message 涓嶅彲涓虹┖ + * @param last 鏄惁鏈鍚庝竴鏉 + * @param userids Serializable[] + * + * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀哄紓甯 + */ + public final CompletableFuture sendMessage(final Convert convert, Object message, boolean last, Serializable... userids) { + if (_engine.node == null) return CompletableFuture.completedFuture(RETCODE_NODESERVICE_NULL); + if (message instanceof CompletableFuture) { + return ((CompletableFuture) message).thenCompose((json) -> _engine.node.sendMessage(convert, json, last, userids)); + } + CompletableFuture rs = _engine.node.sendMessage(convert, message, last, userids); + if (_engine.logger.isLoggable(Level.FINER)) _engine.logger.finer("userids:" + Arrays.toString(userids) + " send websocket message(" + message + ")"); + return rs; + } + + /** + * 骞挎挱娑堟伅锛 缁欐墍鏈変汉鍙戞秷鎭 + * + * @param message 娑堟伅鍐呭 + * + * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 + */ + public final CompletableFuture broadcastMessage(final Object message) { + return broadcastMessage((Convert) null, message, true); + } + + /** + * 骞挎挱娑堟伅锛 缁欐墍鏈変汉鍙戞秷鎭 + * + * @param wsrange 杩囨护鏉′欢 + * @param message 娑堟伅鍐呭 + * + * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 + */ + public final CompletableFuture broadcastMessage(final WebSocketRange wsrange, final Object message) { + return broadcastMessage((WebSocketRange) null, (Convert) null, message, true); + } + + /** + * 骞挎挱娑堟伅锛 缁欐墍鏈変汉鍙戞秷鎭 + * + * @param convert Convert + * @param message 娑堟伅鍐呭 + * + * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 + */ + public final CompletableFuture broadcastMessage(final Convert convert, final Object message) { + return broadcastMessage(convert, message, true); + } + + /** + * 骞挎挱娑堟伅锛 缁欐墍鏈変汉鍙戞秷鎭 + * + * @param wsrange 杩囨护鏉′欢 + * @param convert Convert + * @param message 娑堟伅鍐呭 + * + * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 + */ + public final CompletableFuture broadcastMessage(final WebSocketRange wsrange, final Convert convert, final Object message) { + return broadcastMessage((WebSocketRange) null, convert, message, true); + } + + /** + * 骞挎挱娑堟伅锛 缁欐墍鏈変汉鍙戞秷鎭 + * + * @param message 娑堟伅鍐呭 + * @param last 鏄惁鏈鍚庝竴鏉 + * + * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 + */ + public final CompletableFuture broadcastMessage(final Object message, final boolean last) { + return broadcastMessage((Convert) null, message, last); + } + + /** + * 骞挎挱娑堟伅锛 缁欐墍鏈変汉鍙戞秷鎭 + * + * @param wsrange 杩囨护鏉′欢 + * @param message 娑堟伅鍐呭 + * @param last 鏄惁鏈鍚庝竴鏉 + * + * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 + */ + public final CompletableFuture broadcastMessage(final WebSocketRange wsrange, final Object message, final boolean last) { + return broadcastMessage(wsrange, (Convert) null, message, last); + } + + /** + * 骞挎挱娑堟伅锛 缁欐墍鏈変汉鍙戞秷鎭 + * + * @param convert Convert + * @param message 娑堟伅鍐呭 + * @param last 鏄惁鏈鍚庝竴鏉 + * + * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 + */ + public final CompletableFuture broadcastMessage(final Convert convert, final Object message, final boolean last) { + return broadcastMessage((WebSocketRange) null, convert, message, last); + } + + /** + * 骞挎挱娑堟伅锛 缁欐墍鏈変汉鍙戞秷鎭 + * + * @param wsrange 杩囨护鏉′欢 + * @param convert Convert + * @param message 娑堟伅鍐呭 + * @param last 鏄惁鏈鍚庝竴鏉 + * + * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 + */ + public final CompletableFuture broadcastMessage(final WebSocketRange wsrange, final Convert convert, final Object message, final boolean last) { + if (_engine.node == null) return CompletableFuture.completedFuture(RETCODE_NODESERVICE_NULL); + if (message instanceof CompletableFuture) { + return ((CompletableFuture) message).thenCompose((json) -> _engine.node.broadcastMessage(wsrange, convert, json, last)); + } + CompletableFuture rs = _engine.node.broadcastMessage(wsrange, convert, message, last); + if (_engine.logger.isLoggable(Level.FINER)) _engine.logger.finer("broadcast send websocket message(" + message + ")"); + return rs; + } + + /** + * 缁欐寚瀹歶serid鐨刉ebSocket鑺傜偣鍙戦佹搷浣 + * + * @param action 鎿嶄綔鍙傛暟 + * @param userids Serializable[] + * + * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀哄紓甯 + */ + public final CompletableFuture sendAction(final WebSocketAction action, Serializable... userids) { + if (_engine.node == null) return CompletableFuture.completedFuture(RETCODE_NODESERVICE_NULL); + CompletableFuture rs = _engine.node.sendAction(action, userids); + if (_engine.logger.isLoggable(Level.FINER)) _engine.logger.finer("userids:" + Arrays.toString(userids) + " send websocket action(" + action + ")"); + return rs; + } + + /** + * 骞挎挱鎿嶄綔锛 缁欐墍鏈変汉鍙戞搷浣滄寚浠 + * + * @param action 鎿嶄綔鍙傛暟 + * + * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 + */ + public final CompletableFuture broadcastAction(final WebSocketAction action) { + if (_engine.node == null) return CompletableFuture.completedFuture(RETCODE_NODESERVICE_NULL); + CompletableFuture rs = _engine.node.broadcastAction(action); + if (_engine.logger.isLoggable(Level.FINER)) _engine.logger.finer("broadcast send websocket action(" + action + ")"); + return rs; + } + + /** + * 鑾峰彇鐢ㄦ埛鍦ㄧ嚎鐨凷NCP鑺傜偣鍦板潃鍒楄〃锛屼笉鏄垎甯冨紡鍒欒繑鍥炲厓绱犳暟閲忎负1锛屼笖鍏冪礌鍊间负null鐨勫垪琛
+ * InetSocketAddress 涓 SNCP鑺傜偣鍦板潃 + * + * @param userid Serializable + * + * @return 鍦板潃鍒楄〃 + */ + public CompletableFuture> getRpcNodeAddresses(final Serializable userid) { + if (_engine.node == null) return CompletableFuture.completedFuture(null); + return _engine.node.getRpcNodeAddresses(userid); + } + + /** + * 鑾峰彇鍦ㄧ嚎鐢ㄦ埛鐨勮缁嗚繛鎺ヤ俊鎭
+ * Map.key 涓 SNCP鑺傜偣鍦板潃, 鍚间负null鐨刱ey琛ㄧず娌℃湁鍒嗗竷寮 + * Map.value 涓 鐢ㄦ埛瀹㈡埛绔殑IP + * + * @param userid Serializable + * + * @return 鍦板潃闆嗗悎 + */ + public CompletableFuture>> getRpcNodeWebSocketAddresses(final Serializable userid) { + if (_engine.node == null) return CompletableFuture.completedFuture(null); + return _engine.node.getRpcNodeWebSocketAddresses(userid); + } + + /** + * 鏇存敼鏈琖ebSocket鐨剈serid + * + * @param newuserid 鏂扮敤鎴稩D锛屼笉鑳戒负null + * + * @return CompletableFuture + */ + public CompletableFuture changeUserid(final G newuserid) { + if (newuserid == null) throw new NullPointerException("newuserid is null"); + return _engine.changeLocalUserid(this, newuserid); + } + + /** + * 寮哄埗鍏抽棴鐢ㄦ埛鐨勬墍鏈塛ebSocket + * + * @param userid Serializable + * + * @return int + */ + @Comment("寮哄埗鍏抽棴鐢ㄦ埛鐨勬墍鏈塛ebSocket") + public CompletableFuture forceCloseWebSocket(Serializable userid) { + return _engine.node.forceCloseWebSocket(userid); + } + + /** + * 鑾峰彇WebSocketNode + * + * + * @return WebSocketNode + */ + @Comment("鑾峰彇WebSocketNode") + public final WebSocketNode webSocketNode() { + return _engine.node; + } + + /** + * 鑾峰彇褰撳墠WebSocket涓嬬殑灞炴э紝闈炵嚎绋嬪畨鍏 + * + * @param 灞炴у肩殑绫诲瀷 + * @param name 灞炴у悕 + * + * @return 灞炴у + */ + @SuppressWarnings("unchecked") + public final V getAttribute(String name) { + return attributes == null ? null : (V) attributes.get(name); + } + + /** + * 绉诲嚭褰撳墠WebSocket涓嬬殑灞炴э紝闈炵嚎绋嬪畨鍏 + * + * @param 灞炴у肩殑绫诲瀷 + * @param name 灞炴у悕 + * + * @return 灞炴у + */ + public final V removeAttribute(String name) { + return attributes == null ? null : (V) attributes.remove(name); + } + + /** + * 缁欏綋鍓峎ebSocket涓嬬殑澧炲姞灞炴э紝闈炵嚎绋嬪畨鍏 + * + * @param name 灞炴у + * @param value 灞炴у + */ + public final void setAttribute(String name, Object value) { + if (attributes == null) attributes = new HashMap<>(); + attributes.put(name, value); + } + + /** + * 鑾峰彇褰撳墠WebSocket鎵灞炵殑userid + * + * @return userid + */ + public final G getUserid() { + return _userid; + } + + /** + * 鑾峰彇褰撳墠WebSocket鐨勪細璇滻D锛 涓嶄細涓簄ull + * + * @return sessionid + */ + public final String getSessionid() { + return _sessionid; + } + + /** + * 鑾峰彇瀹㈡埛绔洿鎺ュ湴鍧, 褰揥ebSocket杩炴帴鏄敱浠g悊鏈嶅姟鍣ㄨ浆鍙戠殑锛屽垯璇ュ煎浐瀹氫负浠g悊鏈嶅姟鍣ㄧ殑IP鍦板潃 + * + * @return SocketAddress + */ + public final SocketAddress getRemoteAddress() { + return _remoteAddress; + } + + /** + * 鑾峰彇瀹㈡埛绔湡瀹炲湴鍧 鍚 HttpRequest.getRemoteAddr() + * + * @return String + */ + public final String getRemoteAddr() { + return _remoteAddr; + } + + protected Convert getTextConvert() { + return _textConvert; + } + + protected Convert getBinaryConvert() { + return _binaryConvert; + } + + protected Convert getSendConvert() { + return _sendConvert; + } + + //------------------------------------------------------------------- + /** + * 鑾峰彇鎸囧畾userid鐨刉ebSocket鏁扮粍, 娌℃湁杩斿洖null
+ * 姝ゆ柟娉曠敤浜庡崟鐢ㄦ埛澶氳繛鎺ユā寮 + * + * @param userid Serializable + * + * @return WebSocket闆嗗悎 + */ + protected final Stream getLocalWebSockets(G userid) { + return _engine.getLocalWebSockets(userid); + } + + /** + * 鑾峰彇鎸囧畾userid鐨刉ebSocket鏁扮粍, 娌℃湁杩斿洖null
+ * 姝ゆ柟娉曠敤浜庡崟鐢ㄦ埛鍗曡繛鎺ユā寮 + * + * @param userid Serializable + * + * @return WebSocket + */ + protected final WebSocket findLocalWebSocket(G userid) { + return _engine.findLocalWebSocket(userid); + } + + /** + * 鑾峰彇褰撳墠杩涚▼鑺傜偣鎵鏈夊湪绾跨殑WebSocket + * + * @return WebSocketGroup鍒楄〃 + */ + protected final Collection getLocalWebSockets() { + return _engine.getLocalWebSockets(); + } + + /** + * 鑾峰彇ByteBuffer鐢熸垚鍣 + * + * @return Supplier + */ + protected Supplier getBufferSupplier() { + return this._channel.getBufferSupplier(); + } + + /** + * 鑾峰彇ByteBuffer鍥炴敹鍣 + * + * @return Consumer + */ + protected Consumer getBufferConsumer() { + return this._channel.getBufferConsumer(); + } + + //------------------------------------------------------------------- + /** + * 杩斿洖sessionid, null琛ㄧず杩炴帴涓嶅悎娉曟垨寮傚父,榛樿瀹炵幇鏄痳equest.sessionid(true)锛岄氬父闇瑕侀噸鍐欒鏂规硶 + * + * @param request HttpRequest + * + * @return sessionid + */ + protected CompletableFuture onOpen(final HttpRequest request) { + return CompletableFuture.completedFuture(request.getSessionid(true)); + } + + /** + * 鍒涘缓userid锛 null琛ㄧず寮傚父锛 蹇呴』瀹炵幇璇ユ柟娉 + * + * @return userid + */ + protected abstract CompletableFuture createUserid(); + + /** + * WebSocket.broadcastMessage鏃剁殑杩囨护鏉′欢 + * + * @param wsrange 杩囨护鏉′欢 + * + * @return boolean + */ + protected boolean predicate(WebSocketRange wsrange) { + return true; + } + + /** + * WebSocket.broadcastAction鏃剁殑鎿嶄綔 + * + * @param action 鎿嶄綔鍙傛暟 + * + * @return CompletableFuture + * + */ + protected CompletableFuture action(WebSocketAction action) { + return CompletableFuture.completedFuture(0); + } + + /** + * WebSokcet杩炴帴鎴愬姛鍚庣殑鍥炶皟鏂规硶 + * + * @return Future 鍙互涓簄ull + */ + public CompletableFuture onConnected() { + return null; + } + + /** + * ping鍚庣殑鍥炶皟鏂规硶 + * + * @param bytes 鏁版嵁 + */ + public void onPing(byte[] bytes) { + } + + /** + * pong鍚庣殑鍥炶皟鏂规硶 + * + * @param bytes 鏁版嵁 + */ + public void onPong(byte[] bytes) { + } + + /** + * + * 鎺ユ敹鍒版秷鎭墠鐨勬嫤鎴柟娉曪紝 ping/pong涓嶅湪鍏跺唴
+ * 娉ㄦ剰锛氬鐞嗗畬鍚庨渶瑕佽皟鐢 messageEvent.run() 鎵嶈兘鍝嶅簲onMessage + * + * @param restmapping Rest鐨勬柟娉曞悕锛屾病鏈夊垯涓虹┖瀛楃涓 + * @param param onMessage鏂规硶鐨勫弬鏁 + * @param messageEvent onMessage浜嬩欢 + */ + public void preOnMessage(String restmapping, WebSocketParam param, Runnable messageEvent) { + messageEvent.run(); + } + + /** + * 鎺ユ敹鍒版秷鎭殑鍥炶皟鏂规硶 + * + * @param message 娑堟伅 + * @param last 鏄惁鏈鍚庝竴鏉 + */ + public void onMessage(T message, boolean last) { + } + + /** + * 鎺ユ敹鍒版枃鏈秷鎭殑鍥炶皟鏂规硶 + * + * @param text 娑堟伅 + * @param last 鏄惁鏈鍚庝竴鏉 + */ + public void onMessage(String text, boolean last) { + } + + /** + * 鎺ユ敹鍒颁簩杩涘埗娑堟伅鐨勫洖璋冩柟娉 + * + * @param bytes 娑堟伅 + * @param last 鏄惁鏈鍚庝竴鏉 + */ + public void onMessage(byte[] bytes, boolean last) { + } + + /** + * 鍏抽棴鐨勫洖璋冩柟娉曪紝璋冪敤姝ゆ柟娉曟椂WebSocket宸茬粡琚叧闂 + * + * @param code 缁撴灉鐮侊紝闈0琛ㄧず闈炴甯稿叧闂 + * @param reason 鍏抽棴鍘熷洜 + * + * @return Future 鍙互涓簄ull + */ + public CompletableFuture onClose(int code, String reason) { + return null; + } + + /** + * 鍙戠敓寮傚父鏃惰皟鐢 + * + * @param t 寮傚父 + * @param buffers ByteBuffer[] + */ + public void onOccurException(Throwable t, ByteBuffer[] buffers) { + this.getLogger().log(Level.SEVERE, "WebSocket receive or send Message error", t); + } + + /** + * 褰揝ingle妯″紡涓嬬敤鎴烽噸澶嶇櫥褰曟椂鍥炶皟鍑芥暟锛岄粯璁ゅ鐞嗘柟寮: 鍏抽棴鏃ц繛鎺 + * + * @return Future 鍙互涓簄ull, 涓簄ull鎴栬匜uture鍊间负false琛ㄧず鍏抽棴鏂拌繛鎺ワ紝 Future鍊间负true琛ㄧず鍏抽棴鏃ц繛鎺 + */ + public CompletableFuture onSingleRepeatConnect() { + return forceCloseWebSocket(getUserid()).thenApply((r) -> true); + } + + /** + * 鑾峰彇鍒嗗竷寮忔儏鍐典笅鐨凷NCP鍦板潃, 闈炲垎甯冨紡涓嬩负null + * + * @return InetSocketAddress sncpAddress + */ + public InetSocketAddress getSncpAddress() { + return _sncpAddress; + } + + /** + * 鑾峰彇Logger + * + * @return Logger Logger + */ + public Logger getLogger() { + return this._engine.logger; + } + + /** + * 鑾峰彇鏈鍚庝竴娆″彂閫佹秷鎭殑鏃堕棿 + * + * @return long + */ + public long getLastSendTime() { + return this.lastSendTime; + } + + /** + * 鑾峰彇鏈鍚庝竴娆¤鍙栨秷鎭殑鏃堕棿 + * + * @return long + */ + public long getLastReadTime() { + return this.lastReadTime; + } + + /** + * 鑾峰彇鏈鍚庝竴娆″彂閫丳ING娑堟伅鐨勬椂闂 + * + * @return long + */ + public long getLastPingTime() { + return this.lastPingTime; + } + + /** + * 鏄惧紡鍦板叧闂璚ebSocket + */ + public final void close() { + if (this.deflater != null) this.deflater.end(); + if (this.inflater != null) this.inflater.end(); + CompletableFuture future = kill(CLOSECODE_SERVERCLOSE, "user close"); + if (future != null) future.join(); + } + + //closeRunner + CompletableFuture kill(int code, String reason) { + if (closed) return null; + synchronized (this) { + if (closed) return null; + closed = true; + if (_channel == null) return null; + CompletableFuture future = _engine.removeLocalThenDisconnect(this); + _channel.dispose(); + CompletableFuture closeFuture = onClose(code, reason); + if (closeFuture == null) return future; + return CompletableFuture.allOf(future, closeFuture); + } + } + + /** + * 鏄惁鍏抽棴 + * + * @return boolean + */ + public final boolean isClosed() { + return this.closed; + } + + @Override + public String toString() { + return this.getUserid() + "@" + _remoteAddr + "@" + Objects.hashCode(this); + } +} diff --git a/src/main/java/org/redkale/net/http/WebSocketAction.java b/src/main/java/org/redkale/net/http/WebSocketAction.java index db53325db..0324e5dc0 100644 --- a/src/main/java/org/redkale/net/http/WebSocketAction.java +++ b/src/main/java/org/redkale/net/http/WebSocketAction.java @@ -1,66 +1,66 @@ -/* - * 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 java.io.Serializable; -import java.util.Map; -import org.redkale.convert.json.JsonConvert; - -/** - * WebSocket.broadcastAction鏃剁殑鍙傛暟 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public class WebSocketAction implements Serializable { - - protected String action; - - protected Map attach; - - public WebSocketAction() { - } - - public WebSocketAction(String action) { - this.action = action; - } - - public WebSocketAction(String action, Map attach) { - this.action = action; - this.attach = attach; - } - - public String findAttach(String name) { - return attach == null ? null : attach.get(name); - } - - public String findAttach(String name, String defvalue) { - return attach == null ? defvalue : attach.getOrDefault(name, defvalue); - } - - public String getAction() { - return action; - } - - public void setAction(String action) { - this.action = action; - } - - public Map getAttach() { - return attach; - } - - public void setAttach(Map attach) { - this.attach = attach; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } -} +/* + * 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 java.io.Serializable; +import java.util.Map; +import org.redkale.convert.json.JsonConvert; + +/** + * WebSocket.broadcastAction鏃剁殑鍙傛暟 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public class WebSocketAction implements Serializable { + + protected String action; + + protected Map attach; + + public WebSocketAction() { + } + + public WebSocketAction(String action) { + this.action = action; + } + + public WebSocketAction(String action, Map attach) { + this.action = action; + this.attach = attach; + } + + public String findAttach(String name) { + return attach == null ? null : attach.get(name); + } + + public String findAttach(String name, String defvalue) { + return attach == null ? defvalue : attach.getOrDefault(name, defvalue); + } + + public String getAction() { + return action; + } + + public void setAction(String action) { + this.action = action; + } + + public Map getAttach() { + return attach; + } + + public void setAttach(Map attach) { + this.attach = attach; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } +} diff --git a/src/main/java/org/redkale/net/http/WebSocketAddress.java b/src/main/java/org/redkale/net/http/WebSocketAddress.java index 5e2a29d35..f04a1e130 100644 --- a/src/main/java/org/redkale/net/http/WebSocketAddress.java +++ b/src/main/java/org/redkale/net/http/WebSocketAddress.java @@ -1,74 +1,74 @@ -/* - * 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 java.io.Serializable; -import java.net.InetSocketAddress; -import java.util.Objects; -import org.redkale.convert.json.JsonConvert; - -/** - * 瀛樻斁鐢ㄦ埛WS杩炴帴鐨凷NCP鍦板潃鍜孧Q topic锛 褰撴秷鎭娇鐢∕Q浠g悊鏃讹紝topic鎵嶄細鏈夊 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * - * @since 2.1.0 - */ -public class WebSocketAddress implements Serializable { - - protected InetSocketAddress addr; - - protected String topic; - - public WebSocketAddress() { - } - - public WebSocketAddress(String topic, InetSocketAddress addr) { - this.topic = topic; - this.addr = addr; - } - - @Override - public int hashCode() { - int hash = 7; - hash = 37 * hash + Objects.hashCode(this.addr); - hash = 37 * hash + Objects.hashCode(this.topic); - return hash; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; - final WebSocketAddress other = (WebSocketAddress) obj; - return Objects.equals(this.topic, other.topic) && Objects.equals(this.addr, other.addr); - } - - public String getTopic() { - return topic; - } - - public void setTopic(String topic) { - this.topic = topic; - } - - public InetSocketAddress getAddr() { - return addr; - } - - public void setAddr(InetSocketAddress addr) { - this.addr = addr; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } -} +/* + * 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 java.io.Serializable; +import java.net.InetSocketAddress; +import java.util.Objects; +import org.redkale.convert.json.JsonConvert; + +/** + * 瀛樻斁鐢ㄦ埛WS杩炴帴鐨凷NCP鍦板潃鍜孧Q topic锛 褰撴秷鎭娇鐢∕Q浠g悊鏃讹紝topic鎵嶄細鏈夊 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.1.0 + */ +public class WebSocketAddress implements Serializable { + + protected InetSocketAddress addr; + + protected String topic; + + public WebSocketAddress() { + } + + public WebSocketAddress(String topic, InetSocketAddress addr) { + this.topic = topic; + this.addr = addr; + } + + @Override + public int hashCode() { + int hash = 7; + hash = 37 * hash + Objects.hashCode(this.addr); + hash = 37 * hash + Objects.hashCode(this.topic); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + final WebSocketAddress other = (WebSocketAddress) obj; + return Objects.equals(this.topic, other.topic) && Objects.equals(this.addr, other.addr); + } + + public String getTopic() { + return topic; + } + + public void setTopic(String topic) { + this.topic = topic; + } + + public InetSocketAddress getAddr() { + return addr; + } + + public void setAddr(InetSocketAddress addr) { + this.addr = addr; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } +} diff --git a/src/main/java/org/redkale/net/http/WebSocketEngine.java b/src/main/java/org/redkale/net/http/WebSocketEngine.java index f7b6f61f2..4d7ccfa56 100644 --- a/src/main/java/org/redkale/net/http/WebSocketEngine.java +++ b/src/main/java/org/redkale/net/http/WebSocketEngine.java @@ -1,495 +1,495 @@ -/* - * 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 static org.redkale.net.http.WebSocketServlet.DEFAILT_LIVEINTERVAL; -import java.io.*; -import java.util.*; -import java.util.concurrent.*; -import java.util.concurrent.atomic.*; -import java.util.function.*; -import java.util.logging.*; -import java.util.stream.*; -import org.redkale.convert.Convert; -import org.redkale.net.Cryptor; -import static org.redkale.net.http.WebSocket.RETCODE_GROUP_EMPTY; -import static org.redkale.net.http.WebSocketServlet.*; -import org.redkale.util.*; - -/** - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public class WebSocketEngine { - - @Comment("鍏ㄥ眬鑷闀縄D, 涓轰簡纭繚鍦ㄤ竴涓繘绋嬮噷澶氫釜WebSocketEngine瀹氭椂鍙戦乸ing鏃朵笉浼氬悓鏃惰繘琛") - private static final AtomicInteger sequence = new AtomicInteger(); - - @Comment("Engine鑷闀垮簭鍙稩D") - private final int index; - - @Comment("褰撳墠WebSocket瀵瑰簲鐨凟ngine") - private final String engineid; - - @Comment("褰撳墠WebSocket瀵瑰簲鐨凬ode") - protected final WebSocketNode node; - - //HttpContext - protected final HttpContext context; - - //Convert - protected final Convert sendConvert; - - @Comment("鏄惁鍗曠敤鎴峰崟杩炴帴") - protected final boolean single; - - @Comment("鍦ㄧ嚎鐢ㄦ埛ID瀵瑰簲鐨刉ebSocket缁勶紝鐢ㄤ簬鍗曠敤鎴峰崟杩炴帴妯″紡") - private final Map websockets = new ConcurrentHashMap<>(); - - @Comment("鍦ㄧ嚎鐢ㄦ埛ID瀵瑰簲鐨刉ebSocket缁勶紝鐢ㄤ簬鍗曠敤鎴峰杩炴帴妯″紡") - private final Map> websockets2 = new ConcurrentHashMap<>(); - - @Comment("褰撳墠杩炴帴鏁") - protected final AtomicInteger currconns = new AtomicInteger(); - - @Comment("鐢ㄤ簬PING鐨勫畾鏃跺櫒") - private ScheduledThreadPoolExecutor scheduler; - - @Comment("鏃ュ織") - protected final Logger logger; - - @Comment("PING鐨勯棿闅旂鏁") - protected int liveinterval; - - @Comment("鏈澶ц繛鎺ユ暟, 涓0琛ㄧず鏃犻檺鍒") - protected int wsmaxconns; - - @Comment("鎿嶄綔WebSocketNode瀵瑰簲CacheSource骞跺彂鏁, 涓-1琛ㄧず鏃犻檺鍒讹紝涓0琛ㄧず绯荤粺榛樿鍊(CPU*8)") - protected int wsthreads; - - @Comment("鏈澶ф秷鎭綋闀垮害, 灏忎簬1琛ㄧず鏃犻檺鍒") - protected int wsmaxbody; - - @Comment("鎺ユ敹瀹㈡埛绔殑鍒嗗寘(last=false)娑堟伅鏃舵槸鍚﹁嚜鍔ㄥ悎骞跺寘") - protected boolean mergemsg = true; - - @Comment("鍔犲瘑瑙e瘑鍣") - protected Cryptor cryptor; - - protected WebSocketEngine(String engineid, boolean single, HttpContext context, int liveinterval, int wsmaxconns, - int wsthreads, int wsmaxbody, boolean mergemsg, Cryptor cryptor, WebSocketNode node, Convert sendConvert, Logger logger) { - this.engineid = engineid; - this.single = single; - this.context = context; - this.sendConvert = sendConvert; - this.node = node; - this.liveinterval = liveinterval; - this.wsmaxconns = wsmaxconns; - this.wsthreads = wsthreads; - this.wsmaxbody = wsmaxbody; - this.mergemsg = mergemsg; - this.cryptor = cryptor; - this.logger = logger; - this.index = sequence.getAndIncrement(); - } - - void init(AnyValue conf) { - AnyValue props = conf; - if (conf != null && conf.getAnyValue("properties") != null) props = conf.getAnyValue("properties"); - this.liveinterval = props == null ? (liveinterval < 0 ? DEFAILT_LIVEINTERVAL : liveinterval) : props.getIntValue(WEBPARAM__LIVEINTERVAL, (liveinterval < 0 ? DEFAILT_LIVEINTERVAL : liveinterval)); - if (liveinterval <= 0) return; - if (props != null) this.wsmaxconns = props.getIntValue(WEBPARAM__WSMAXCONNS, this.wsmaxconns); - if (props != null) this.wsthreads = props.getIntValue(WEBPARAM__WSTHREADS, this.wsthreads); - if (props != null) this.wsmaxbody = props.getIntValue(WEBPARAM__WSMAXBODY, this.wsmaxbody); - if (scheduler != null) return; - this.scheduler = new ScheduledThreadPoolExecutor(1, (Runnable r) -> { - final Thread t = new Thread(r, "Redkale-" + engineid + "-WebSocket-LiveInterval-Thread"); - t.setDaemon(true); - return t; - }); - long delay = (liveinterval - System.currentTimeMillis() / 1000 % liveinterval) + index * 5; - final int intervalms = liveinterval * 1000; - scheduler.scheduleWithFixedDelay(() -> { - try { - long now = System.currentTimeMillis(); - getLocalWebSockets().stream().filter(x -> ((now - x.getLastReadTime()) > intervalms && (now - x.getLastSendTime()) > intervalms)).forEach(x -> x.sendPing()); - } catch (Throwable t) { - logger.log(Level.SEVERE, "WebSocketEngine schedule(interval=" + liveinterval + "s) ping error", t); - } - }, delay, liveinterval, TimeUnit.SECONDS); - if (logger.isLoggable(Level.FINEST)) logger.finest(this.getClass().getSimpleName() + "(" + engineid + ")" + " start keeplive(wsmaxconns:" + wsmaxconns + ", delay:" + delay + "s, interval:" + liveinterval + "s) scheduler executor"); - } - - void destroy(AnyValue conf) { - if (scheduler != null) scheduler.shutdownNow(); - } - - @Comment("娣诲姞WebSocket") - CompletableFuture addLocal(WebSocket socket) { - if (single) { - currconns.incrementAndGet(); - websockets.put(socket._userid, socket); - } else { //闈炵嚎绋嬪畨鍏紝 鍦ㄥ父瑙勫満鏅腑鏃犻渶閿 - List list = websockets2.get(socket._userid); - if (list == null) { - list = new CopyOnWriteArrayList<>(); - websockets2.put(socket._userid, list); - } - currconns.incrementAndGet(); - list.add(socket); - } - if (node != null) return node.connect(socket._userid); - return null; - } - - @Comment("浠嶹ebSocketEngine鍒犻櫎鎸囧畾WebSocket") - CompletableFuture removeLocalThenDisconnect(WebSocket socket) { - Serializable userid = socket._userid; - if (userid == null) return null; //灏氭湭鐧诲綍鎴愬姛 - if (single) { - currconns.decrementAndGet(); - websockets.remove(userid); - if (node != null) return node.disconnect(userid); - } else { //闈炵嚎绋嬪畨鍏紝 鍦ㄥ父瑙勫満鏅腑鏃犻渶閿 - List list = websockets2.get(userid); - if (list != null) { - currconns.decrementAndGet(); - list.remove(socket); - if (list.isEmpty()) { - websockets2.remove(userid); - return node.disconnect(userid); - } - } - } - return null; - } - - @Comment("鏇存敼WebSocket鐨剈serid") - CompletableFuture changeLocalUserid(WebSocket socket, final Serializable newuserid) { - if (newuserid == null) throw new NullPointerException("newuserid is null"); - final Serializable olduserid = socket._userid; - socket._userid = newuserid; - if (single) { - websockets.remove(olduserid); - websockets.put(newuserid, socket); - } else { //闈炵嚎绋嬪畨鍏紝 鍦ㄥ父瑙勫満鏅腑鏃犻渶閿 - List oldlist = websockets2.get(olduserid); - if (oldlist != null) { - oldlist.remove(socket); - if (oldlist.isEmpty()) websockets2.remove(olduserid); - } - List newlist = websockets2.get(newuserid); - if (newlist == null) { - newlist = new CopyOnWriteArrayList<>(); - websockets2.put(newuserid, newlist); - } - newlist.add(socket); - } - if (node != null) return node.changeUserid(olduserid, newuserid); - return CompletableFuture.completedFuture(null); - } - - @Comment("寮哄埗鍏抽棴鏈湴鐢ㄦ埛鐨刉ebSocket") - public int forceCloseLocalWebSocket(Serializable userid) { - if (single) { - WebSocket ws = websockets.get(userid); - if (ws == null) return 0; - ws.close(); - return 1; - } - List list = websockets2.get(userid); - if (list == null || list.isEmpty()) return 0; - List list2 = new ArrayList<>(list); - for (WebSocket ws : list2) { - ws.close(); - } - return list2.size(); - } - - @Comment("缁欐墍鏈夎繛鎺ョ敤鎴峰彂閫佹秷鎭") - public CompletableFuture broadcastLocalMessage(final Object message, final boolean last) { - return WebSocketEngine.this.broadcastLocalMessage((Predicate) null, message, last); - } - - @Comment("缁欐寚瀹歐ebSocket杩炴帴鐢ㄦ埛鍙戦佹秷鎭") - public CompletableFuture broadcastLocalMessage(final WebSocketRange wsrange, final Object message, final boolean last) { - Predicate predicate = wsrange == null ? null : (ws) -> ws.predicate(wsrange); - return WebSocketEngine.this.broadcastLocalMessage(predicate, message, last); - } - - @Comment("缁欐寚瀹歐ebSocket杩炴帴鐢ㄦ埛鍙戦佹秷鎭") - public CompletableFuture broadcastLocalMessage(final Predicate predicate, final Object message, final boolean last) { - if (message instanceof CompletableFuture) { - return ((CompletableFuture) message).thenCompose((json) -> WebSocketEngine.this.broadcastLocalMessage(predicate, json, last)); - } -// final boolean more = (!(message instanceof WebSocketPacket) || ((WebSocketPacket) message).sendBuffers == null); -// if (more) { -// Supplier bufferSupplier = null; -// Consumer bufferConsumer = null; -// //姝ゅ鐨刉ebSocketPacket鍙兘鏄寘鍚玴ayload鎴朾ytes鍐呭鐨勶紝涓嶈兘鍖呭惈sendConvert銆乻endJson銆乻endBuffers -// final WebSocketPacket packet = (message instanceof WebSocketPacket) ? (WebSocketPacket) message -// : ((message == null || message instanceof CharSequence || message instanceof byte[]) -// ? new WebSocketPacket((Serializable) message, last) : new WebSocketPacket(this.sendConvert, message, last)); -// //packet.setSendBuffers(packet.encode(context.getBufferSupplier(), context.getBufferConsumer(), cryptor)); -// CompletableFuture future = null; -// if (single) { -// for (WebSocket websocket : websockets.values()) { -// if (predicate != null && !predicate.test(websocket)) continue; -// if (bufferSupplier == null) { -// bufferSupplier = websocket.getBufferSupplier(); -// bufferConsumer = websocket.getBufferConsumer(); -// packet.encodePacket(bufferSupplier, bufferConsumer, cryptor); -// } -// future = future == null ? websocket.sendPacket(packet) : future.thenCombine(websocket.sendPacket(packet), (a, b) -> a | (Integer) b); -// } -// } else { -// for (List list : websockets2.values()) { -// for (WebSocket websocket : list) { -// if (predicate != null && !predicate.test(websocket)) continue; -// if (bufferSupplier == null) { -// bufferSupplier = websocket.getBufferSupplier(); -// bufferConsumer = websocket.getBufferConsumer(); -// packet.encodePacket(bufferSupplier, bufferConsumer, cryptor); -// } -// future = future == null ? websocket.sendPacket(packet) : future.thenCombine(websocket.sendPacket(packet), (a, b) -> a | (Integer) b); -// } -// } -// } -// final Consumer bufferConsumer0 = bufferConsumer; -// if (future != null) future.whenComplete((rs, ex) -> { -// if (packet.sendBuffers != null && bufferConsumer0 != null) { -// for (ByteBuffer buffer : packet.sendBuffers) { -// bufferConsumer0.accept(buffer); -// } -// } -// }); -// return future == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : future; -// } else { - CompletableFuture future = null; - if (single) { - for (WebSocket websocket : websockets.values()) { - if (predicate != null && !predicate.test(websocket)) continue; - future = future == null ? websocket.send(message, last) : future.thenCombine(websocket.send(message, last), (a, b) -> a | (Integer) b); - } - } else { - for (List list : websockets2.values()) { - for (WebSocket websocket : list) { - if (predicate != null && !predicate.test(websocket)) continue; - future = future == null ? websocket.send(message, last) : future.thenCombine(websocket.send(message, last), (a, b) -> a | (Integer) b); - } - } - } - return future == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : future; - //} - } - - @Comment("缁欐寚瀹氱敤鎴风粍鍙戦佹秷鎭") - public CompletableFuture sendLocalMessage(final Object message, final boolean last, final Stream userids) { - Object[] array = userids.toArray(); - Serializable[] ss = new Serializable[array.length]; - for (int i = 0; i < array.length; i++) { - ss[i] = (Serializable) array[i]; - } - return WebSocketEngine.this.sendLocalMessage(message, last, ss); - } - - @Comment("缁欐寚瀹氱敤鎴风粍鍙戦佹秷鎭") - public CompletableFuture sendLocalMessage(final Object message, final boolean last, final Serializable... userids) { - if (message instanceof CompletableFuture) { - return ((CompletableFuture) message).thenCompose((json) -> WebSocketEngine.this.sendLocalMessage(json, last, userids)); - } -// final boolean more = userids.length > 1; -// if (more) { -// Supplier bufferSupplier = null; -// Consumer bufferConsumer = null; -// //姝ゅ鐨刉ebSocketPacket鍙兘鏄寘鍚玴ayload鎴朾ytes鍐呭鐨勶紝涓嶈兘鍖呭惈sendConvert銆乻endJson銆乻endBuffers -// final WebSocketPacket packet = (message instanceof WebSocketPacket) ? (WebSocketPacket) message -// : ((message == null || message instanceof CharSequence || message instanceof byte[]) -// ? new WebSocketPacket((Serializable) message, last) : new WebSocketPacket(this.sendConvert, message, last)); -// //packet.encode(context.getBufferSupplier(), context.getBufferConsumer(), cryptor); -// CompletableFuture future = null; -// if (single) { -// for (Serializable userid : userids) { -// WebSocket websocket = websockets.get(userid); -// if (websocket == null) continue; -// if (bufferSupplier == null) { -// bufferSupplier = websocket.getBufferSupplier(); -// bufferConsumer = websocket.getBufferConsumer(); -// packet.encodePacket(bufferSupplier, bufferConsumer, cryptor); -// } -// future = future == null ? websocket.sendPacket(packet) : future.thenCombine(websocket.sendPacket(packet), (a, b) -> a | (Integer) b); -// } -// } else { -// for (Serializable userid : userids) { -// List list = websockets2.get(userid); -// if (list == null) continue; -// for (WebSocket websocket : list) { -// if (bufferSupplier == null) { -// bufferSupplier = websocket.getBufferSupplier(); -// bufferConsumer = websocket.getBufferConsumer(); -// packet.encodePacket(bufferSupplier, bufferConsumer, cryptor); -// } -// future = future == null ? websocket.sendPacket(packet) : future.thenCombine(websocket.sendPacket(packet), (a, b) -> a | (Integer) b); -// } -// } -// } -// final Consumer bufferConsumer0 = bufferConsumer; -// if (future != null) future.whenComplete((rs, ex) -> { -// if (packet.sendBuffers != null && bufferConsumer0 != null) { -// for (ByteBuffer buffer : packet.sendBuffers) { -// bufferConsumer0.accept(buffer); -// } -// } -// }); -// return future == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : future; -// } else { - CompletableFuture future = null; - if (single) { - for (Serializable userid : userids) { - WebSocket websocket = websockets.get(userid); - if (websocket == null) continue; - future = future == null ? websocket.send(message, last) : future.thenCombine(websocket.send(message, last), (a, b) -> a | (Integer) b); - } - } else { - for (Serializable userid : userids) { - List list = websockets2.get(userid); - if (list == null) continue; - for (WebSocket websocket : list) { - future = future == null ? websocket.send(message, last) : future.thenCombine(websocket.send(message, last), (a, b) -> a | (Integer) b); - } - } - } - return future == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : future; - //} - } - - @Comment("缁欐寚瀹歐ebSocket杩炴帴鐢ㄦ埛鍙戣捣鎿嶄綔鎸囦护") - public CompletableFuture broadcastLocalAction(final WebSocketAction action) { - CompletableFuture future = null; - if (single) { - for (WebSocket websocket : websockets.values()) { - future = future == null ? websocket.action(action) : future.thenCombine(websocket.action(action), (a, b) -> a | (Integer) b); - } - } else { - for (List list : websockets2.values()) { - for (WebSocket websocket : list) { - future = future == null ? websocket.action(action) : future.thenCombine(websocket.action(action), (a, b) -> a | (Integer) b); - } - } - } - return future == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : future; - } - - @Comment("缁欐寚瀹氱敤鎴风粍鍙戦佹搷浣") - public CompletableFuture sendLocalAction(final WebSocketAction action, final Stream userids) { - Object[] array = userids.toArray(); - Serializable[] ss = new Serializable[array.length]; - for (int i = 0; i < array.length; i++) { - ss[i] = (Serializable) array[i]; - } - return WebSocketEngine.this.sendLocalAction(action, ss); - } - - @Comment("缁欐寚瀹氱敤鎴风粍鍙戦佹搷浣") - public CompletableFuture sendLocalAction(final WebSocketAction action, final Serializable... userids) { - CompletableFuture future = null; - if (single) { - for (Serializable userid : userids) { - WebSocket websocket = websockets.get(userid); - if (websocket == null) continue; - future = future == null ? websocket.action(action) : future.thenCombine(websocket.action(action), (a, b) -> a | (Integer) b); - } - } else { - for (Serializable userid : userids) { - List list = websockets2.get(userid); - if (list == null) continue; - for (WebSocket websocket : list) { - future = future == null ? websocket.action(action) : future.thenCombine(websocket.action(action), (a, b) -> a | (Integer) b); - } - } - } - return future == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : future; - } - - @Comment("鑾峰彇WebSocketNode瀵硅薄") - public WebSocketNode getWebSocketNode() { - return node; - } - - @Comment("鑾峰彇鏈澶ц繛鎺ユ暟") - public int getLocalWsmaxconns() { - return this.wsmaxconns; - } - - @Comment("杩炴帴鏁版槸鍚﹁揪鍒颁笂闄") - public boolean isLocalConnLimited() { - if (this.wsmaxconns < 1) return false; - return currconns.get() >= this.wsmaxconns; - } - - @Comment("鑾峰彇鎵鏈夎繛鎺") - public Collection getLocalWebSockets() { - if (single) return websockets.values(); - List list = new ArrayList<>(); - websockets2.values().forEach(x -> list.addAll(x)); - return list; - } - - @Comment("鑾峰彇鎵鏈夎繛鎺") - public void forEachLocalWebSocket(Consumer consumer) { - if (consumer == null) return; - if (single) { - websockets.values().stream().forEach(consumer); - } else { - websockets2.values().forEach(x -> x.stream().forEach(consumer)); - } - } - - @Comment("鑾峰彇褰撳墠杩炴帴鎬绘暟") - public int getLocalWebSocketSize() { - if (single) return websockets.size(); - return (int) websockets2.values().stream().mapToInt(sublist -> sublist.size()).count(); - } - - @Comment("鑾峰彇褰撳墠鐢ㄦ埛鎬绘暟") - public Set getLocalUserSet() { - return single ? new LinkedHashSet<>(websockets.keySet()) : new LinkedHashSet<>(websockets2.keySet()); - } - - @Comment("鑾峰彇褰撳墠鐢ㄦ埛鎬绘暟") - public int getLocalUserSize() { - return single ? websockets.size() : websockets2.size(); - } - - @Comment("閫傜敤浜庡崟鐢ㄦ埛鍗曡繛鎺ユā寮") - public WebSocket findLocalWebSocket(Serializable userid) { - if (single) return websockets.get(userid); - List list = websockets2.get(userid); - return (list == null || list.isEmpty()) ? null : list.get(list.size() - 1); - } - - @Comment("閫傜敤浜庡崟鐢ㄦ埛澶氳繛鎺ユā寮") - public Stream getLocalWebSockets(Serializable userid) { - if (single) { - WebSocket websocket = websockets.get(userid); - return websocket == null ? Stream.empty() : Stream.of(websocket); - } else { - List list = websockets2.get(userid); - return list == null ? Stream.empty() : list.stream(); - } - } - - public boolean existsLocalWebSocket(Serializable userid) { - return single ? websockets.containsKey(userid) : websockets2.containsKey(userid); - } - - public String getEngineid() { - return engineid; - } -} +/* + * 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 static org.redkale.net.http.WebSocketServlet.DEFAILT_LIVEINTERVAL; +import java.io.*; +import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.*; +import java.util.function.*; +import java.util.logging.*; +import java.util.stream.*; +import org.redkale.convert.Convert; +import org.redkale.net.Cryptor; +import static org.redkale.net.http.WebSocket.RETCODE_GROUP_EMPTY; +import static org.redkale.net.http.WebSocketServlet.*; +import org.redkale.util.*; + +/** + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public class WebSocketEngine { + + @Comment("鍏ㄥ眬鑷闀縄D, 涓轰簡纭繚鍦ㄤ竴涓繘绋嬮噷澶氫釜WebSocketEngine瀹氭椂鍙戦乸ing鏃朵笉浼氬悓鏃惰繘琛") + private static final AtomicInteger sequence = new AtomicInteger(); + + @Comment("Engine鑷闀垮簭鍙稩D") + private final int index; + + @Comment("褰撳墠WebSocket瀵瑰簲鐨凟ngine") + private final String engineid; + + @Comment("褰撳墠WebSocket瀵瑰簲鐨凬ode") + protected final WebSocketNode node; + + //HttpContext + protected final HttpContext context; + + //Convert + protected final Convert sendConvert; + + @Comment("鏄惁鍗曠敤鎴峰崟杩炴帴") + protected final boolean single; + + @Comment("鍦ㄧ嚎鐢ㄦ埛ID瀵瑰簲鐨刉ebSocket缁勶紝鐢ㄤ簬鍗曠敤鎴峰崟杩炴帴妯″紡") + private final Map websockets = new ConcurrentHashMap<>(); + + @Comment("鍦ㄧ嚎鐢ㄦ埛ID瀵瑰簲鐨刉ebSocket缁勶紝鐢ㄤ簬鍗曠敤鎴峰杩炴帴妯″紡") + private final Map> websockets2 = new ConcurrentHashMap<>(); + + @Comment("褰撳墠杩炴帴鏁") + protected final AtomicInteger currconns = new AtomicInteger(); + + @Comment("鐢ㄤ簬PING鐨勫畾鏃跺櫒") + private ScheduledThreadPoolExecutor scheduler; + + @Comment("鏃ュ織") + protected final Logger logger; + + @Comment("PING鐨勯棿闅旂鏁") + protected int liveinterval; + + @Comment("鏈澶ц繛鎺ユ暟, 涓0琛ㄧず鏃犻檺鍒") + protected int wsmaxconns; + + @Comment("鎿嶄綔WebSocketNode瀵瑰簲CacheSource骞跺彂鏁, 涓-1琛ㄧず鏃犻檺鍒讹紝涓0琛ㄧず绯荤粺榛樿鍊(CPU*8)") + protected int wsthreads; + + @Comment("鏈澶ф秷鎭綋闀垮害, 灏忎簬1琛ㄧず鏃犻檺鍒") + protected int wsmaxbody; + + @Comment("鎺ユ敹瀹㈡埛绔殑鍒嗗寘(last=false)娑堟伅鏃舵槸鍚﹁嚜鍔ㄥ悎骞跺寘") + protected boolean mergemsg = true; + + @Comment("鍔犲瘑瑙e瘑鍣") + protected Cryptor cryptor; + + protected WebSocketEngine(String engineid, boolean single, HttpContext context, int liveinterval, int wsmaxconns, + int wsthreads, int wsmaxbody, boolean mergemsg, Cryptor cryptor, WebSocketNode node, Convert sendConvert, Logger logger) { + this.engineid = engineid; + this.single = single; + this.context = context; + this.sendConvert = sendConvert; + this.node = node; + this.liveinterval = liveinterval; + this.wsmaxconns = wsmaxconns; + this.wsthreads = wsthreads; + this.wsmaxbody = wsmaxbody; + this.mergemsg = mergemsg; + this.cryptor = cryptor; + this.logger = logger; + this.index = sequence.getAndIncrement(); + } + + void init(AnyValue conf) { + AnyValue props = conf; + if (conf != null && conf.getAnyValue("properties") != null) props = conf.getAnyValue("properties"); + this.liveinterval = props == null ? (liveinterval < 0 ? DEFAILT_LIVEINTERVAL : liveinterval) : props.getIntValue(WEBPARAM__LIVEINTERVAL, (liveinterval < 0 ? DEFAILT_LIVEINTERVAL : liveinterval)); + if (liveinterval <= 0) return; + if (props != null) this.wsmaxconns = props.getIntValue(WEBPARAM__WSMAXCONNS, this.wsmaxconns); + if (props != null) this.wsthreads = props.getIntValue(WEBPARAM__WSTHREADS, this.wsthreads); + if (props != null) this.wsmaxbody = props.getIntValue(WEBPARAM__WSMAXBODY, this.wsmaxbody); + if (scheduler != null) return; + this.scheduler = new ScheduledThreadPoolExecutor(1, (Runnable r) -> { + final Thread t = new Thread(r, "Redkale-" + engineid + "-WebSocket-LiveInterval-Thread"); + t.setDaemon(true); + return t; + }); + long delay = (liveinterval - System.currentTimeMillis() / 1000 % liveinterval) + index * 5; + final int intervalms = liveinterval * 1000; + scheduler.scheduleWithFixedDelay(() -> { + try { + long now = System.currentTimeMillis(); + getLocalWebSockets().stream().filter(x -> ((now - x.getLastReadTime()) > intervalms && (now - x.getLastSendTime()) > intervalms)).forEach(x -> x.sendPing()); + } catch (Throwable t) { + logger.log(Level.SEVERE, "WebSocketEngine schedule(interval=" + liveinterval + "s) ping error", t); + } + }, delay, liveinterval, TimeUnit.SECONDS); + if (logger.isLoggable(Level.FINEST)) logger.finest(this.getClass().getSimpleName() + "(" + engineid + ")" + " start keeplive(wsmaxconns:" + wsmaxconns + ", delay:" + delay + "s, interval:" + liveinterval + "s) scheduler executor"); + } + + void destroy(AnyValue conf) { + if (scheduler != null) scheduler.shutdownNow(); + } + + @Comment("娣诲姞WebSocket") + CompletableFuture addLocal(WebSocket socket) { + if (single) { + currconns.incrementAndGet(); + websockets.put(socket._userid, socket); + } else { //闈炵嚎绋嬪畨鍏紝 鍦ㄥ父瑙勫満鏅腑鏃犻渶閿 + List list = websockets2.get(socket._userid); + if (list == null) { + list = new CopyOnWriteArrayList<>(); + websockets2.put(socket._userid, list); + } + currconns.incrementAndGet(); + list.add(socket); + } + if (node != null) return node.connect(socket._userid); + return null; + } + + @Comment("浠嶹ebSocketEngine鍒犻櫎鎸囧畾WebSocket") + CompletableFuture removeLocalThenDisconnect(WebSocket socket) { + Serializable userid = socket._userid; + if (userid == null) return null; //灏氭湭鐧诲綍鎴愬姛 + if (single) { + currconns.decrementAndGet(); + websockets.remove(userid); + if (node != null) return node.disconnect(userid); + } else { //闈炵嚎绋嬪畨鍏紝 鍦ㄥ父瑙勫満鏅腑鏃犻渶閿 + List list = websockets2.get(userid); + if (list != null) { + currconns.decrementAndGet(); + list.remove(socket); + if (list.isEmpty()) { + websockets2.remove(userid); + return node.disconnect(userid); + } + } + } + return null; + } + + @Comment("鏇存敼WebSocket鐨剈serid") + CompletableFuture changeLocalUserid(WebSocket socket, final Serializable newuserid) { + if (newuserid == null) throw new NullPointerException("newuserid is null"); + final Serializable olduserid = socket._userid; + socket._userid = newuserid; + if (single) { + websockets.remove(olduserid); + websockets.put(newuserid, socket); + } else { //闈炵嚎绋嬪畨鍏紝 鍦ㄥ父瑙勫満鏅腑鏃犻渶閿 + List oldlist = websockets2.get(olduserid); + if (oldlist != null) { + oldlist.remove(socket); + if (oldlist.isEmpty()) websockets2.remove(olduserid); + } + List newlist = websockets2.get(newuserid); + if (newlist == null) { + newlist = new CopyOnWriteArrayList<>(); + websockets2.put(newuserid, newlist); + } + newlist.add(socket); + } + if (node != null) return node.changeUserid(olduserid, newuserid); + return CompletableFuture.completedFuture(null); + } + + @Comment("寮哄埗鍏抽棴鏈湴鐢ㄦ埛鐨刉ebSocket") + public int forceCloseLocalWebSocket(Serializable userid) { + if (single) { + WebSocket ws = websockets.get(userid); + if (ws == null) return 0; + ws.close(); + return 1; + } + List list = websockets2.get(userid); + if (list == null || list.isEmpty()) return 0; + List list2 = new ArrayList<>(list); + for (WebSocket ws : list2) { + ws.close(); + } + return list2.size(); + } + + @Comment("缁欐墍鏈夎繛鎺ョ敤鎴峰彂閫佹秷鎭") + public CompletableFuture broadcastLocalMessage(final Object message, final boolean last) { + return WebSocketEngine.this.broadcastLocalMessage((Predicate) null, message, last); + } + + @Comment("缁欐寚瀹歐ebSocket杩炴帴鐢ㄦ埛鍙戦佹秷鎭") + public CompletableFuture broadcastLocalMessage(final WebSocketRange wsrange, final Object message, final boolean last) { + Predicate predicate = wsrange == null ? null : (ws) -> ws.predicate(wsrange); + return WebSocketEngine.this.broadcastLocalMessage(predicate, message, last); + } + + @Comment("缁欐寚瀹歐ebSocket杩炴帴鐢ㄦ埛鍙戦佹秷鎭") + public CompletableFuture broadcastLocalMessage(final Predicate predicate, final Object message, final boolean last) { + if (message instanceof CompletableFuture) { + return ((CompletableFuture) message).thenCompose((json) -> WebSocketEngine.this.broadcastLocalMessage(predicate, json, last)); + } +// final boolean more = (!(message instanceof WebSocketPacket) || ((WebSocketPacket) message).sendBuffers == null); +// if (more) { +// Supplier bufferSupplier = null; +// Consumer bufferConsumer = null; +// //姝ゅ鐨刉ebSocketPacket鍙兘鏄寘鍚玴ayload鎴朾ytes鍐呭鐨勶紝涓嶈兘鍖呭惈sendConvert銆乻endJson銆乻endBuffers +// final WebSocketPacket packet = (message instanceof WebSocketPacket) ? (WebSocketPacket) message +// : ((message == null || message instanceof CharSequence || message instanceof byte[]) +// ? new WebSocketPacket((Serializable) message, last) : new WebSocketPacket(this.sendConvert, message, last)); +// //packet.setSendBuffers(packet.encode(context.getBufferSupplier(), context.getBufferConsumer(), cryptor)); +// CompletableFuture future = null; +// if (single) { +// for (WebSocket websocket : websockets.values()) { +// if (predicate != null && !predicate.test(websocket)) continue; +// if (bufferSupplier == null) { +// bufferSupplier = websocket.getBufferSupplier(); +// bufferConsumer = websocket.getBufferConsumer(); +// packet.encodePacket(bufferSupplier, bufferConsumer, cryptor); +// } +// future = future == null ? websocket.sendPacket(packet) : future.thenCombine(websocket.sendPacket(packet), (a, b) -> a | (Integer) b); +// } +// } else { +// for (List list : websockets2.values()) { +// for (WebSocket websocket : list) { +// if (predicate != null && !predicate.test(websocket)) continue; +// if (bufferSupplier == null) { +// bufferSupplier = websocket.getBufferSupplier(); +// bufferConsumer = websocket.getBufferConsumer(); +// packet.encodePacket(bufferSupplier, bufferConsumer, cryptor); +// } +// future = future == null ? websocket.sendPacket(packet) : future.thenCombine(websocket.sendPacket(packet), (a, b) -> a | (Integer) b); +// } +// } +// } +// final Consumer bufferConsumer0 = bufferConsumer; +// if (future != null) future.whenComplete((rs, ex) -> { +// if (packet.sendBuffers != null && bufferConsumer0 != null) { +// for (ByteBuffer buffer : packet.sendBuffers) { +// bufferConsumer0.accept(buffer); +// } +// } +// }); +// return future == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : future; +// } else { + CompletableFuture future = null; + if (single) { + for (WebSocket websocket : websockets.values()) { + if (predicate != null && !predicate.test(websocket)) continue; + future = future == null ? websocket.send(message, last) : future.thenCombine(websocket.send(message, last), (a, b) -> a | (Integer) b); + } + } else { + for (List list : websockets2.values()) { + for (WebSocket websocket : list) { + if (predicate != null && !predicate.test(websocket)) continue; + future = future == null ? websocket.send(message, last) : future.thenCombine(websocket.send(message, last), (a, b) -> a | (Integer) b); + } + } + } + return future == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : future; + //} + } + + @Comment("缁欐寚瀹氱敤鎴风粍鍙戦佹秷鎭") + public CompletableFuture sendLocalMessage(final Object message, final boolean last, final Stream userids) { + Object[] array = userids.toArray(); + Serializable[] ss = new Serializable[array.length]; + for (int i = 0; i < array.length; i++) { + ss[i] = (Serializable) array[i]; + } + return WebSocketEngine.this.sendLocalMessage(message, last, ss); + } + + @Comment("缁欐寚瀹氱敤鎴风粍鍙戦佹秷鎭") + public CompletableFuture sendLocalMessage(final Object message, final boolean last, final Serializable... userids) { + if (message instanceof CompletableFuture) { + return ((CompletableFuture) message).thenCompose((json) -> WebSocketEngine.this.sendLocalMessage(json, last, userids)); + } +// final boolean more = userids.length > 1; +// if (more) { +// Supplier bufferSupplier = null; +// Consumer bufferConsumer = null; +// //姝ゅ鐨刉ebSocketPacket鍙兘鏄寘鍚玴ayload鎴朾ytes鍐呭鐨勶紝涓嶈兘鍖呭惈sendConvert銆乻endJson銆乻endBuffers +// final WebSocketPacket packet = (message instanceof WebSocketPacket) ? (WebSocketPacket) message +// : ((message == null || message instanceof CharSequence || message instanceof byte[]) +// ? new WebSocketPacket((Serializable) message, last) : new WebSocketPacket(this.sendConvert, message, last)); +// //packet.encode(context.getBufferSupplier(), context.getBufferConsumer(), cryptor); +// CompletableFuture future = null; +// if (single) { +// for (Serializable userid : userids) { +// WebSocket websocket = websockets.get(userid); +// if (websocket == null) continue; +// if (bufferSupplier == null) { +// bufferSupplier = websocket.getBufferSupplier(); +// bufferConsumer = websocket.getBufferConsumer(); +// packet.encodePacket(bufferSupplier, bufferConsumer, cryptor); +// } +// future = future == null ? websocket.sendPacket(packet) : future.thenCombine(websocket.sendPacket(packet), (a, b) -> a | (Integer) b); +// } +// } else { +// for (Serializable userid : userids) { +// List list = websockets2.get(userid); +// if (list == null) continue; +// for (WebSocket websocket : list) { +// if (bufferSupplier == null) { +// bufferSupplier = websocket.getBufferSupplier(); +// bufferConsumer = websocket.getBufferConsumer(); +// packet.encodePacket(bufferSupplier, bufferConsumer, cryptor); +// } +// future = future == null ? websocket.sendPacket(packet) : future.thenCombine(websocket.sendPacket(packet), (a, b) -> a | (Integer) b); +// } +// } +// } +// final Consumer bufferConsumer0 = bufferConsumer; +// if (future != null) future.whenComplete((rs, ex) -> { +// if (packet.sendBuffers != null && bufferConsumer0 != null) { +// for (ByteBuffer buffer : packet.sendBuffers) { +// bufferConsumer0.accept(buffer); +// } +// } +// }); +// return future == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : future; +// } else { + CompletableFuture future = null; + if (single) { + for (Serializable userid : userids) { + WebSocket websocket = websockets.get(userid); + if (websocket == null) continue; + future = future == null ? websocket.send(message, last) : future.thenCombine(websocket.send(message, last), (a, b) -> a | (Integer) b); + } + } else { + for (Serializable userid : userids) { + List list = websockets2.get(userid); + if (list == null) continue; + for (WebSocket websocket : list) { + future = future == null ? websocket.send(message, last) : future.thenCombine(websocket.send(message, last), (a, b) -> a | (Integer) b); + } + } + } + return future == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : future; + //} + } + + @Comment("缁欐寚瀹歐ebSocket杩炴帴鐢ㄦ埛鍙戣捣鎿嶄綔鎸囦护") + public CompletableFuture broadcastLocalAction(final WebSocketAction action) { + CompletableFuture future = null; + if (single) { + for (WebSocket websocket : websockets.values()) { + future = future == null ? websocket.action(action) : future.thenCombine(websocket.action(action), (a, b) -> a | (Integer) b); + } + } else { + for (List list : websockets2.values()) { + for (WebSocket websocket : list) { + future = future == null ? websocket.action(action) : future.thenCombine(websocket.action(action), (a, b) -> a | (Integer) b); + } + } + } + return future == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : future; + } + + @Comment("缁欐寚瀹氱敤鎴风粍鍙戦佹搷浣") + public CompletableFuture sendLocalAction(final WebSocketAction action, final Stream userids) { + Object[] array = userids.toArray(); + Serializable[] ss = new Serializable[array.length]; + for (int i = 0; i < array.length; i++) { + ss[i] = (Serializable) array[i]; + } + return WebSocketEngine.this.sendLocalAction(action, ss); + } + + @Comment("缁欐寚瀹氱敤鎴风粍鍙戦佹搷浣") + public CompletableFuture sendLocalAction(final WebSocketAction action, final Serializable... userids) { + CompletableFuture future = null; + if (single) { + for (Serializable userid : userids) { + WebSocket websocket = websockets.get(userid); + if (websocket == null) continue; + future = future == null ? websocket.action(action) : future.thenCombine(websocket.action(action), (a, b) -> a | (Integer) b); + } + } else { + for (Serializable userid : userids) { + List list = websockets2.get(userid); + if (list == null) continue; + for (WebSocket websocket : list) { + future = future == null ? websocket.action(action) : future.thenCombine(websocket.action(action), (a, b) -> a | (Integer) b); + } + } + } + return future == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : future; + } + + @Comment("鑾峰彇WebSocketNode瀵硅薄") + public WebSocketNode getWebSocketNode() { + return node; + } + + @Comment("鑾峰彇鏈澶ц繛鎺ユ暟") + public int getLocalWsmaxconns() { + return this.wsmaxconns; + } + + @Comment("杩炴帴鏁版槸鍚﹁揪鍒颁笂闄") + public boolean isLocalConnLimited() { + if (this.wsmaxconns < 1) return false; + return currconns.get() >= this.wsmaxconns; + } + + @Comment("鑾峰彇鎵鏈夎繛鎺") + public Collection getLocalWebSockets() { + if (single) return websockets.values(); + List list = new ArrayList<>(); + websockets2.values().forEach(x -> list.addAll(x)); + return list; + } + + @Comment("鑾峰彇鎵鏈夎繛鎺") + public void forEachLocalWebSocket(Consumer consumer) { + if (consumer == null) return; + if (single) { + websockets.values().stream().forEach(consumer); + } else { + websockets2.values().forEach(x -> x.stream().forEach(consumer)); + } + } + + @Comment("鑾峰彇褰撳墠杩炴帴鎬绘暟") + public int getLocalWebSocketSize() { + if (single) return websockets.size(); + return (int) websockets2.values().stream().mapToInt(sublist -> sublist.size()).count(); + } + + @Comment("鑾峰彇褰撳墠鐢ㄦ埛鎬绘暟") + public Set getLocalUserSet() { + return single ? new LinkedHashSet<>(websockets.keySet()) : new LinkedHashSet<>(websockets2.keySet()); + } + + @Comment("鑾峰彇褰撳墠鐢ㄦ埛鎬绘暟") + public int getLocalUserSize() { + return single ? websockets.size() : websockets2.size(); + } + + @Comment("閫傜敤浜庡崟鐢ㄦ埛鍗曡繛鎺ユā寮") + public WebSocket findLocalWebSocket(Serializable userid) { + if (single) return websockets.get(userid); + List list = websockets2.get(userid); + return (list == null || list.isEmpty()) ? null : list.get(list.size() - 1); + } + + @Comment("閫傜敤浜庡崟鐢ㄦ埛澶氳繛鎺ユā寮") + public Stream getLocalWebSockets(Serializable userid) { + if (single) { + WebSocket websocket = websockets.get(userid); + return websocket == null ? Stream.empty() : Stream.of(websocket); + } else { + List list = websockets2.get(userid); + return list == null ? Stream.empty() : list.stream(); + } + } + + public boolean existsLocalWebSocket(Serializable userid) { + return single ? websockets.containsKey(userid) : websockets2.containsKey(userid); + } + + public String getEngineid() { + return engineid; + } +} diff --git a/src/main/java/org/redkale/net/http/WebSocketNode.java b/src/main/java/org/redkale/net/http/WebSocketNode.java index 3c7c0819f..eef5ddcbc 100644 --- a/src/main/java/org/redkale/net/http/WebSocketNode.java +++ b/src/main/java/org/redkale/net/http/WebSocketNode.java @@ -1,1022 +1,1022 @@ -/* - * 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 static org.redkale.net.http.WebSocket.*; -import java.io.*; -import java.net.*; -import java.util.*; -import java.util.concurrent.*; -import java.util.logging.*; -import java.util.stream.*; -import javax.annotation.*; -import org.redkale.boot.*; -import org.redkale.convert.*; -import org.redkale.convert.json.JsonConvert; -import org.redkale.mq.MessageAgent; -import org.redkale.service.*; -import org.redkale.source.*; -import org.redkale.util.*; - -/** - * 娉: 閮ㄧ讲浜哤ebSocketNodeService灏卞繀鐒惰閰嶇疆SNCP鍗忚鐨凷erver锛屼笉鐒舵棤娉曞仛鍒癢ebSocketNode.sendMessage鏂规硶鐨勬湁鏁堟 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public abstract class WebSocketNode { - - @Comment("瀛樺偍鐢ㄦ埛ID鐨刱ey鍓嶇紑") - public static final String WS_SOURCE_KEY_USERID_PREFIX = "sncpws_uid:"; - - @Comment("瀛樺偍褰撳墠SNCP鑺傜偣鍒楄〃鐨刱ey") - public static final String WS_SOURCE_KEY_NODES = "sncpws_nodes"; - - protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); - - //"SNCP_ADDR" 濡傛灉涓嶆槸鍒嗗竷寮(娌℃湁SNCP) 鍊间负null - @Resource(name = Application.RESNAME_SNCP_ADDR) - protected InetSocketAddress localSncpAddress; //涓篠ncpServer鐨勬湇鍔ddress - - protected WebSocketAddress wsNodeAddress; - - protected String name; - - //濡傛灉涓嶆槸鍒嗗竷寮(娌℃湁SNCP) 鍊间负null - @RpcRemote - protected WebSocketNode remoteNode; - - @Resource(name = "$_sendconvert") - protected Convert sendConvert; - - //瀛樻斁鎵鏈夌敤鎴峰垎甯冨湪鑺傜偣涓婄殑闃熷垪淇℃伅,Set 涓 sncpnode 鐨勯泦鍚堬紝 key: groupid - //闆嗗悎鍖呭惈 localSncpAddress - //濡傛灉涓嶆槸鍒嗗竷寮(娌℃湁SNCP)锛宻ource 灏嗕笉浼氳鐢ㄥ埌 - @Resource(name = "$") - protected CacheSource source; - - //褰撳墠鑺傜偣鐨勬湰鍦癢ebSocketEngine - protected WebSocketEngine localEngine; - - protected MessageAgent messageAgent; - - protected Semaphore semaphore; - - private int tryAcquireSeconds = 12; - - public void init(AnyValue conf) { - this.tryAcquireSeconds = Integer.getInteger("redkale.http.websocket.tryAcquireSeconds", 12); - - if (localEngine != null) { - int wsthreads = localEngine.wsthreads; - if (wsthreads == 0) wsthreads = Utility.cpus() * 8; - if (wsthreads > 0) this.semaphore = new Semaphore(wsthreads); - } - String mqtopic = this.messageAgent == null ? null : this.messageAgent.generateSncpReqTopic((Service) this); - if (mqtopic != null || this.localSncpAddress != null) { - this.wsNodeAddress = new WebSocketAddress(mqtopic, localSncpAddress); - } - if (source != null && this.wsNodeAddress == null) { //闈炲垎甯冨紡妯″紡 - this.wsNodeAddress = new WebSocketAddress(mqtopic, new InetSocketAddress("127.0.0.1", 27)); - } - if (source != null && wsNodeAddress != null) { - source.appendSetItem(WS_SOURCE_KEY_NODES, WebSocketAddress.class, this.wsNodeAddress); - } - } - - public void destroy(AnyValue conf) { - } - - @Local - public final Semaphore getSemaphore() { - return semaphore; - } - - @Local - public final MessageAgent getMessageAgent() { - return messageAgent; - } - - @Local - protected void postDestroy(AnyValue conf) { - if (this.localEngine == null) return; - //鍏虫帀鎵鏈夋湰鍦版湰鍦癢ebSocket - this.localEngine.getLocalWebSockets().forEach(g -> g.close()); - if (source != null && wsNodeAddress != null) { - source.removeSetItem(WS_SOURCE_KEY_NODES, WebSocketAddress.class, this.wsNodeAddress); - } - } - - protected abstract CompletableFuture> getWebSocketAddresses(@RpcTargetTopic String topic, @RpcTargetAddress InetSocketAddress targetAddress, Serializable userid); - - protected abstract CompletableFuture sendMessage(@RpcTargetTopic String topic, @RpcTargetAddress InetSocketAddress targetAddress, Object message, boolean last, Serializable... userids); - - protected abstract CompletableFuture broadcastMessage(@RpcTargetTopic String topic, @RpcTargetAddress InetSocketAddress targetAddress, WebSocketRange wsrange, Object message, boolean last); - - protected abstract CompletableFuture sendAction(@RpcTargetTopic String topic, @RpcTargetAddress InetSocketAddress targetAddress, WebSocketAction action, Serializable... userids); - - protected abstract CompletableFuture broadcastAction(@RpcTargetTopic String topic, @RpcTargetAddress InetSocketAddress targetAddress, WebSocketAction action); - - protected abstract CompletableFuture getUserSize(@RpcTargetTopic String topic, @RpcTargetAddress InetSocketAddress targetAddress); - - protected abstract CompletableFuture connect(Serializable userid, WebSocketAddress wsaddr); - - protected abstract CompletableFuture disconnect(Serializable userid, WebSocketAddress wsaddr); - - protected abstract CompletableFuture changeUserid(Serializable fromuserid, Serializable touserid, WebSocketAddress wsaddr); - - protected abstract CompletableFuture existsWebSocket(Serializable userid, @RpcTargetTopic String topic, @RpcTargetAddress InetSocketAddress targetAddress); - - protected abstract CompletableFuture forceCloseWebSocket(Serializable userid, @RpcTargetTopic String topic, @RpcTargetAddress InetSocketAddress targetAddress); - - //-------------------------------------------------------------------------------- - final CompletableFuture connect(final Serializable userid) { - if (logger.isLoggable(Level.FINEST)) logger.finest(wsNodeAddress + " receive websocket connect event (" + userid + " on " + (this.localEngine == null ? null : this.localEngine.getEngineid()) + ")."); - return connect(userid, wsNodeAddress); - } - - final CompletableFuture disconnect(final Serializable userid) { - if (logger.isLoggable(Level.FINEST)) logger.finest(wsNodeAddress + " receive websocket disconnect event (" + userid + " on " + (this.localEngine == null ? null : this.localEngine.getEngineid()) + ")."); - return disconnect(userid, wsNodeAddress); - } - - final CompletableFuture changeUserid(Serializable olduserid, final Serializable newuserid) { - if (logger.isLoggable(Level.FINEST)) logger.finest(wsNodeAddress + " receive websocket changeUserid event (from " + olduserid + " to " + newuserid + " on " + (this.localEngine == null ? null : this.localEngine.getEngineid()) + ")."); - return changeUserid(olduserid, newuserid, wsNodeAddress); - } - - public final String getName() { - return name; - } - - //-------------------------------------------------------------------------------- - /** - * 鑾峰彇鐩爣鍦板潃
- * 璇ユ柟娉曚粎渚涘唴閮ㄨ皟鐢 - * - * @param topic RpcTargetTopic - * @param targetAddress InetSocketAddress - * @param userid Serializable - * - * @return 瀹㈡埛绔湴鍧鍒楄〃 - */ - protected CompletableFuture> remoteWebSocketAddresses(@RpcTargetTopic String topic, @RpcTargetAddress InetSocketAddress targetAddress, Serializable userid) { - if (remoteNode == null) return CompletableFuture.completedFuture(null); - try { - return remoteNode.getWebSocketAddresses(topic, targetAddress, userid); - } catch (Exception e) { - logger.log(Level.WARNING, "remote " + targetAddress + " websocket getOnlineRemoteAddresses error", e); - return CompletableFuture.completedFuture(null); - } - } - - /** - * 鑾峰彇鐢ㄦ埛鍦ㄧ嚎鐨凷NCP鑺傜偣鍦板潃鍒楄〃锛屼笉鏄垎甯冨紡鍒欒繑鍥炲厓绱犳暟閲忎负1锛屼笖鍏冪礌鍊间负null鐨勫垪琛
- * WebSocketAddress 涓 SNCP鑺傜偣鍦板潃 - * - * @param userid Serializable - * - * @return 鍦板潃鍒楄〃 - */ - public CompletableFuture> getRpcNodeAddresses(final Serializable userid) { - if (this.source != null) { - tryAcquireSemaphore(); - CompletableFuture> result = this.source.getCollectionAsync(WS_SOURCE_KEY_USERID_PREFIX + userid, WebSocketAddress.class); - if (semaphore != null) result.whenComplete((r, e) -> releaseSemaphore()); - return result; - } - List rs = new ArrayList<>(); - rs.add(this.wsNodeAddress); - return CompletableFuture.completedFuture(rs); - } - - /** - * 鑾峰彇鍦ㄧ嚎鐢ㄦ埛鐨勮缁嗚繛鎺ヤ俊鎭
- * Map.key 涓 SNCP鑺傜偣鍦板潃, 鍚间负null鐨刱ey琛ㄧず娌℃湁鍒嗗竷寮 - * Map.value 涓 鐢ㄦ埛瀹㈡埛绔殑IP - * - * @param userid Serializable - * - * @return 鍦板潃闆嗗悎 - */ - public CompletableFuture>> getRpcNodeWebSocketAddresses(final Serializable userid) { - CompletableFuture> sncpFuture = getRpcNodeAddresses(userid); - return sncpFuture.thenCompose((Collection addrs) -> { - if (logger.isLoggable(Level.FINEST)) logger.finest("websocket found userid:" + userid + " on " + addrs); - if (addrs == null || addrs.isEmpty()) return CompletableFuture.completedFuture(new HashMap<>()); - CompletableFuture>> future = null; - for (final WebSocketAddress nodeAddress : addrs) { - CompletableFuture>> mapFuture = getWebSocketAddresses(nodeAddress.getTopic(), nodeAddress.getAddr(), userid) - .thenCompose((List list) -> CompletableFuture.completedFuture(Utility.ofMap(nodeAddress, list))); - future = future == null ? mapFuture : future.thenCombine(mapFuture, (a, b) -> Utility.merge(a, b)); - } - return future == null ? CompletableFuture.completedFuture(new HashMap<>()) : future; - }); - } - -// public CompletableFuture getUserSize() { -// if (this.localEngine != null && this.source == null) { -// return CompletableFuture.completedFuture(this.localEngine.getLocalUserSize()); -// } -// tryAcquireSemaphore(); -// CompletableFuture> listFuture = this.source.queryKeysStartsWithAsync(WS_SOURCE_KEY_USERID_PREFIX); -// CompletableFuture rs = listFuture.thenApply(v -> v.size()); -// if (semaphore != null) rs.whenComplete((r, e) -> releaseSemaphore()); -// return rs; -// } - /** - * 鑾峰彇鍦ㄧ嚎鐢ㄦ埛鎬绘暟 - * - * - * @return boolean - */ - @Local - public CompletableFuture getUserSize() { - if (this.localEngine != null && this.source == null) { //鏈湴妯″紡涓旀病鏈夊垎甯冨紡 - return CompletableFuture.completedFuture(this.localEngine.getLocalUserSize()); - } - CompletableFuture localFuture = this.localEngine == null ? null : CompletableFuture.completedFuture(this.localEngine.getLocalUserSize()); - tryAcquireSemaphore(); - CompletableFuture> addrsFuture = source.getCollectionAsync(WS_SOURCE_KEY_NODES, WebSocketAddress.class); - if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore()); - CompletableFuture remoteFuture = addrsFuture.thenCompose((Collection addrs) -> { - if (logger.isLoggable(Level.FINEST)) logger.finest("websocket getUserSize on " + addrs); - if (addrs == null || addrs.isEmpty()) return CompletableFuture.completedFuture(0); - CompletableFuture future = null; - for (WebSocketAddress addr : addrs) { - if (addr == null || addr.equals(wsNodeAddress)) continue; - future = future == null ? remoteNode.getUserSize(addr.getTopic(), addr.getAddr()) - : future.thenCombine(remoteNode.getUserSize(addr.getTopic(), addr.getAddr()), (a, b) -> a + b); - } - return future == null ? CompletableFuture.completedFuture(0) : future; - }); - return localFuture == null ? remoteFuture : localFuture.thenCombine(remoteFuture, (a, b) -> a + b); - } - - /** - * 鑾峰彇鍦ㄧ嚎鐢ㄦ埛鎬绘暟 - * - * - * @return boolean - */ - public CompletableFuture> getUserSet() { - if (this.localEngine != null && this.source == null) { - return CompletableFuture.completedFuture(new LinkedHashSet<>(this.localEngine.getLocalUserSet().stream().map(x -> String.valueOf(x)).collect(Collectors.toList()))); - } - tryAcquireSemaphore(); - CompletableFuture> listFuture = this.source.queryKeysStartsWithAsync(WS_SOURCE_KEY_USERID_PREFIX); - CompletableFuture> rs = listFuture.thenApply(v -> new LinkedHashSet<>(v.stream().map(x -> x.substring(WS_SOURCE_KEY_USERID_PREFIX.length())).collect(Collectors.toList()))); - if (semaphore != null) rs.whenComplete((r, e) -> releaseSemaphore()); - return rs; - } - - /** - * 鍒ゆ柇鎸囧畾鐢ㄦ埛鏄惁WebSocket鍦ㄧ嚎 - * - * @param userid Serializable - * - * @return boolean - */ - @Local - public CompletableFuture existsWebSocket(final Serializable userid) { - if (userid instanceof WebSocketUserAddress) return existsWebSocket((WebSocketUserAddress) userid); - CompletableFuture localFuture = null; - if (this.localEngine != null) localFuture = CompletableFuture.completedFuture(localEngine.existsLocalWebSocket(userid)); - if (this.source == null || this.remoteNode == null) { - if (logger.isLoggable(Level.FINEST)) logger.finest("websocket " + (this.remoteNode == null ? (this.source == null ? "remote and source" : "remote") : "source") + " node is null"); - //娌℃湁CacheSource灏变笉浼氭湁鍒嗗竷寮忚妭鐐 - return localFuture == null ? CompletableFuture.completedFuture(false) : localFuture; - } - //杩滅▼鑺傜偣鍏抽棴 - tryAcquireSemaphore(); - CompletableFuture> addrsFuture = source.getCollectionAsync(WS_SOURCE_KEY_USERID_PREFIX + userid, WebSocketAddress.class); - if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore()); - CompletableFuture remoteFuture = addrsFuture.thenCompose((Collection addrs) -> { - //if (logger.isLoggable(Level.FINEST)) logger.finest("websocket found userid:" + userid + " on " + addrs); - if (addrs == null || addrs.isEmpty()) return CompletableFuture.completedFuture(false); - CompletableFuture future = null; - for (WebSocketAddress addr : addrs) { - if (addr == null || addr.equals(wsNodeAddress)) continue; - future = future == null ? remoteNode.existsWebSocket(userid, addr.getTopic(), addr.getAddr()) - : future.thenCombine(remoteNode.existsWebSocket(userid, addr.getTopic(), addr.getAddr()), (a, b) -> a | b); - } - return future == null ? CompletableFuture.completedFuture(false) : future; - }); - return localFuture == null ? remoteFuture : localFuture.thenCombine(remoteFuture, (a, b) -> a | b); - } - - /** - * 鍒ゆ柇鎸囧畾鐢ㄦ埛鏄惁WebSocket鍦ㄧ嚎 - * - * @param userAddress WebSocketUserAddress - * - * @return boolean - */ - @Local - public CompletableFuture existsWebSocket(final WebSocketUserAddress userAddress) { - if (this.localEngine != null && localEngine.existsLocalWebSocket(userAddress.userid())) return CompletableFuture.completedFuture(true); - if (this.source == null || this.remoteNode == null) { - if (logger.isLoggable(Level.FINEST)) logger.finest("websocket " + (this.remoteNode == null ? (this.source == null ? "remote and source" : "remote") : "source") + " node is null"); - //娌℃湁CacheSource灏变笉浼氭湁鍒嗗竷寮忚妭鐐 - return CompletableFuture.completedFuture(false); - } - Collection addrs = userAddress.addresses(); - if (addrs != null) addrs = new ArrayList<>(addrs); //涓嶈兘淇敼鍙傛暟鍐呴儴鍊 - if (userAddress.address() != null) { - if (addrs == null) addrs = new ArrayList<>(); - addrs.add(userAddress.address()); - } - if (addrs == null || addrs.isEmpty()) return CompletableFuture.completedFuture(false); - CompletableFuture future = null; - for (WebSocketAddress addr : addrs) { - if (addr == null || addr.equals(wsNodeAddress)) continue; - future = future == null ? remoteNode.existsWebSocket(userAddress.userid(), addr.getTopic(), addr.getAddr()) - : future.thenCombine(remoteNode.existsWebSocket(userAddress.userid(), addr.getTopic(), addr.getAddr()), (a, b) -> a | b); - } - return future == null ? CompletableFuture.completedFuture(false) : future; - } - - /** - * 寮哄埗鍏抽棴鐢ㄦ埛WebSocket - * - * @param userid Serializable - * - * @return int - */ - @Local - public CompletableFuture forceCloseWebSocket(final Serializable userid) { - return forceCloseWebSocket(userid, (WebSocketUserAddress) null); - } - - /** - * 寮哄埗鍏抽棴鐢ㄦ埛WebSocket - * - * @param userAddress WebSocketUserAddress - * - * @return int - */ - @Local - public CompletableFuture forceCloseWebSocket(final WebSocketUserAddress userAddress) { - return forceCloseWebSocket(null, userAddress); - } - - private CompletableFuture forceCloseWebSocket(final Serializable userid, final WebSocketUserAddress userAddress) { - CompletableFuture localFuture = null; - if (this.localEngine != null) localFuture = CompletableFuture.completedFuture(localEngine.forceCloseLocalWebSocket(userAddress == null ? userid : userAddress.userid())); - if (this.source == null || this.remoteNode == null) { - if (logger.isLoggable(Level.FINEST)) logger.finest("websocket " + (this.remoteNode == null ? (this.source == null ? "remote and source" : "remote") : "source") + " node is null"); - //娌℃湁CacheSource灏变笉浼氭湁鍒嗗竷寮忚妭鐐 - return localFuture == null ? CompletableFuture.completedFuture(0) : localFuture; - } - //杩滅▼鑺傜偣鍏抽棴 - CompletableFuture> addrsFuture; - if (userAddress == null) { - tryAcquireSemaphore(); - addrsFuture = source.getCollectionAsync(WS_SOURCE_KEY_USERID_PREFIX + userid, WebSocketAddress.class); - if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore()); - } else { - Collection addrs = userAddress.addresses(); - if (addrs != null) addrs = new ArrayList<>(addrs); //涓嶈兘淇敼鍙傛暟鍐呴儴鍊 - if (userAddress.address() != null) { - if (addrs == null) addrs = new ArrayList<>(); - addrs.add(userAddress.address()); - } - if (addrs == null || addrs.isEmpty()) return CompletableFuture.completedFuture(0); - addrsFuture = CompletableFuture.completedFuture(addrs); - } - CompletableFuture remoteFuture = addrsFuture.thenCompose((Collection addrs) -> { - if (logger.isLoggable(Level.FINEST)) logger.finest("websocket found userid:" + userid + " on " + addrs); - if (addrs == null || addrs.isEmpty()) return CompletableFuture.completedFuture(0); - CompletableFuture future = null; - for (WebSocketAddress addr : addrs) { - if (addr == null || addr.equals(wsNodeAddress)) continue; - future = future == null ? remoteNode.forceCloseWebSocket(userid, addr.getTopic(), addr.getAddr()) - : future.thenCombine(remoteNode.forceCloseWebSocket(userid, addr.getTopic(), addr.getAddr()), (a, b) -> a + b); - } - return future == null ? CompletableFuture.completedFuture(0) : future; - }); - return localFuture == null ? remoteFuture : localFuture.thenCombine(remoteFuture, (a, b) -> a + b); - } - - //-------------------------------------------------------------------------------- - /** - * 鑾峰彇鏈湴鐨刉ebSocketEngine锛屾病鏈夊垯杩斿洖null - * - * - * @return WebSocketEngine - */ - @Local - public final WebSocketEngine getLocalWebSocketEngine() { - return this.localEngine; - } - - /** - * 鍚戞寚瀹氱敤鎴峰彂閫佹秷鎭紝鍏堝彂閫佹湰鍦拌繛鎺ワ紝鍐嶅彂閫佽繙绋嬭繛鎺
- * 濡傛灉褰撳墠WebSocketNode鏄繙绋嬫ā寮忥紝姝ゆ柟娉曞彧鍙戦佽繙绋嬭繛鎺 - * - * @param message 娑堟伅鍐呭 - * @param useridOrAddrs Stream - * - * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 - */ - @Local - public final CompletableFuture sendMessage(Object message, final Stream useridOrAddrs) { - return sendMessage((Convert) null, message, true, useridOrAddrs); - } - - /** - * 鍚戞寚瀹氱敤鎴峰彂閫佹秷鎭紝鍏堝彂閫佹湰鍦拌繛鎺ワ紝鍐嶅彂閫佽繙绋嬭繛鎺
- * 濡傛灉褰撳墠WebSocketNode鏄繙绋嬫ā寮忥紝姝ゆ柟娉曞彧鍙戦佽繙绋嬭繛鎺 - * - * @param message 娑堟伅鍐呭 - * @param useridOrAddrs Serializable[] - * - * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 - */ - @Local - public final CompletableFuture sendMessage(Object message, final Serializable... useridOrAddrs) { - return sendMessage((Convert) null, message, true, useridOrAddrs); - } - - /** - * 鍚戞寚瀹氱敤鎴峰彂閫佹秷鎭紝鍏堝彂閫佹湰鍦拌繛鎺ワ紝鍐嶅彂閫佽繙绋嬭繛鎺
- * 濡傛灉褰撳墠WebSocketNode鏄繙绋嬫ā寮忥紝姝ゆ柟娉曞彧鍙戦佽繙绋嬭繛鎺 - * - * @param convert Convert - * @param message 娑堟伅鍐呭 - * @param useridOrAddrs Stream - * - * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 - */ - @Local - public final CompletableFuture sendMessage(final Convert convert, Object message, final Stream useridOrAddrs) { - return sendMessage(convert, message, true, useridOrAddrs); - } - - /** - * 鍚戞寚瀹氱敤鎴峰彂閫佹秷鎭紝鍏堝彂閫佹湰鍦拌繛鎺ワ紝鍐嶅彂閫佽繙绋嬭繛鎺
- * 濡傛灉褰撳墠WebSocketNode鏄繙绋嬫ā寮忥紝姝ゆ柟娉曞彧鍙戦佽繙绋嬭繛鎺 - * - * @param convert Convert - * @param message 娑堟伅鍐呭 - * @param useridOrAddrs Serializable[] - * - * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 - */ - @Local - public final CompletableFuture sendMessage(final Convert convert, Object message, final Serializable... useridOrAddrs) { - return sendMessage(convert, message, true, useridOrAddrs); - } - - /** - * 鍚戞寚瀹氱敤鎴峰彂閫佹秷鎭紝鍏堝彂閫佹湰鍦拌繛鎺ワ紝鍐嶅彂閫佽繙绋嬭繛鎺
- * 濡傛灉褰撳墠WebSocketNode鏄繙绋嬫ā寮忥紝姝ゆ柟娉曞彧鍙戦佽繙绋嬭繛鎺 - * - * @param message 娑堟伅鍐呭 - * @param last 鏄惁鏈鍚庝竴鏉 - * @param useridOrAddrs Stream - * - * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 - */ - @Local - public final CompletableFuture sendMessage(final Object message, final boolean last, final Stream useridOrAddrs) { - return sendMessage((Convert) null, message, last, useridOrAddrs); - } - - /** - * 鍚戞寚瀹氱敤鎴峰彂閫佹秷鎭紝鍏堝彂閫佹湰鍦拌繛鎺ワ紝鍐嶅彂閫佽繙绋嬭繛鎺
- * 濡傛灉褰撳墠WebSocketNode鏄繙绋嬫ā寮忥紝姝ゆ柟娉曞彧鍙戦佽繙绋嬭繛鎺 - * - * @param message 娑堟伅鍐呭 - * @param last 鏄惁鏈鍚庝竴鏉 - * @param useridOrAddrs Serializable[] - * - * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 - */ - @Local - public final CompletableFuture sendMessage(final Object message, final boolean last, final Serializable... useridOrAddrs) { - return sendMessage((Convert) null, message, last, useridOrAddrs); - } - - /** - * 鍚戞寚瀹氱敤鎴峰彂閫佹秷鎭紝鍏堝彂閫佹湰鍦拌繛鎺ワ紝鍐嶅彂閫佽繙绋嬭繛鎺
- * 濡傛灉褰撳墠WebSocketNode鏄繙绋嬫ā寮忥紝姝ゆ柟娉曞彧鍙戦佽繙绋嬭繛鎺 - * - * @param convert Convert - * @param message0 娑堟伅鍐呭 - * @param last 鏄惁鏈鍚庝竴鏉 - * @param userids Stream - * - * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 - */ - @Local - public final CompletableFuture sendMessage(final Convert convert, final Object message0, final boolean last, final Stream userids) { - Object[] array = userids.toArray(); - Serializable[] ss = new Serializable[array.length]; - for (int i = 0; i < array.length; i++) { - ss[i] = (Serializable) array[i]; - } - return sendMessage(convert, message0, last, ss); - } - - /** - * 鍚戞寚瀹氱敤鎴峰彂閫佹秷鎭紝鍏堝彂閫佹湰鍦拌繛鎺ワ紝鍐嶅彂閫佽繙绋嬭繛鎺
- * 濡傛灉褰撳墠WebSocketNode鏄繙绋嬫ā寮忥紝姝ゆ柟娉曞彧鍙戦佽繙绋嬭繛鎺 - * - * @param convert Convert - * @param message0 娑堟伅鍐呭 - * @param last 鏄惁鏈鍚庝竴鏉 - * @param userids Serializable[] - * - * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 - */ - @Local - public CompletableFuture sendMessage(final Convert convert, final Object message0, final boolean last, final Serializable... userids) { - if (userids == null || userids.length < 1) return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); - if (userids[0] instanceof WebSocketUserAddress) { - WebSocketUserAddress[] useraddrs = new WebSocketUserAddress[userids.length]; - for (int i = 0; i < useraddrs.length; i++) { - useraddrs[i] = (WebSocketUserAddress) userids[i]; - } - return sendMessage(convert, message0, last, useraddrs); - } - if (message0 instanceof CompletableFuture) return ((CompletableFuture) message0).thenApply(msg -> sendMessage(convert, msg, last, userids)); - final Object message = (convert == null || message0 instanceof WebSocketPacket) ? message0 : ((convert instanceof TextConvert) ? new WebSocketPacket(WebSocketPacket.FrameType.TEXT, ((TextConvert) convert).convertToBytes(message0), last) : new WebSocketPacket(WebSocketPacket.FrameType.BINARY, ((BinaryConvert) convert).convertToBytes(message0), last)); - if (this.localEngine != null && this.source == null) { //鏈湴妯″紡涓旀病鏈夊垎甯冨紡 - return this.localEngine.sendLocalMessage(message, last, userids); - } - final Object remoteMessage = formatRemoteMessage(message); - CompletableFuture rsfuture; - if (userids.length == 1) { - rsfuture = sendOneUserMessage(remoteMessage, last, userids[0]); - } else { - String[] keys = new String[userids.length]; - final Map keyuser = new HashMap<>(); - for (int i = 0; i < userids.length; i++) { - keys[i] = WS_SOURCE_KEY_USERID_PREFIX + userids[i]; - keyuser.put(keys[i], userids[i]); - } - tryAcquireSemaphore(); - CompletableFuture>> addrsFuture = source.getCollectionMapAsync(true, WebSocketAddress.class, keys); - if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore()); - rsfuture = addrsFuture.thenCompose((Map> addrs) -> { - if (addrs == null || addrs.isEmpty()) { - if (logger.isLoggable(Level.FINER)) logger.finer("websocket not found userids:" + JsonConvert.root().convertTo(userids) + " on any node "); - return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); - } - Map> addrUsers = new HashMap<>(); - addrs.forEach((key, as) -> { - for (WebSocketAddress a : as) { - addrUsers.computeIfAbsent(a, k -> new ArrayList<>()).add(keyuser.get(key)); - } - }); - if (logger.isLoggable(Level.FINEST)) { - logger.finest("websocket(localaddr=" + localSncpAddress + ", userids=" + JsonConvert.root().convertTo(userids) + ") found message-addr-userids: " + addrUsers); - } - CompletableFuture future = null; - for (Map.Entry> en : addrUsers.entrySet()) { - Serializable[] oneaddrUserids = en.getValue().toArray(new Serializable[en.getValue().size()]); - future = future == null ? sendOneAddrMessage(en.getKey(), remoteMessage, last, oneaddrUserids) - : future.thenCombine(sendOneAddrMessage(en.getKey(), remoteMessage, last, oneaddrUserids), (a, b) -> a | b); - } - return future == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : future; - }); - } - return rsfuture == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : rsfuture; - } - - /** - * 鍚戞寚瀹氱敤鎴峰彂閫佹秷鎭紝鍏堝彂閫佹湰鍦拌繛鎺ワ紝鍐嶅彂閫佽繙绋嬭繛鎺
- * 濡傛灉褰撳墠WebSocketNode鏄繙绋嬫ā寮忥紝姝ゆ柟娉曞彧鍙戦佽繙绋嬭繛鎺 - * - * @param convert Convert - * @param message0 娑堟伅鍐呭 - * @param last 鏄惁鏈鍚庝竴鏉 - * @param useraddrs WebSocketUserAddress[] - * - * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 - */ - @Local - public CompletableFuture sendMessage(final Convert convert, final Object message0, final boolean last, final WebSocketUserAddress... useraddrs) { - if (useraddrs == null || useraddrs.length < 1) return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); - if (message0 instanceof CompletableFuture) return ((CompletableFuture) message0).thenApply(msg -> sendMessage(convert, msg, last, useraddrs)); - final Object message = (convert == null || message0 instanceof WebSocketPacket) ? message0 : ((convert instanceof TextConvert) ? new WebSocketPacket(((TextConvert) convert).convertTo(message0), last) : new WebSocketPacket(((BinaryConvert) convert).convertTo(message0), last)); - if (this.localEngine != null && this.source == null) { //鏈湴妯″紡涓旀病鏈夊垎甯冨紡 - return this.localEngine.sendLocalMessage(message, last, userAddressToUserids(useraddrs)); - } - - final Object remoteMessage = formatRemoteMessage(message); - final Map> addrUsers = userAddressToAddrMap(useraddrs); - if (logger.isLoggable(Level.FINEST)) { - logger.finest("websocket(localaddr=" + localSncpAddress + ", useraddrs=" + JsonConvert.root().convertTo(useraddrs) + ") found message-addr-userids: " + addrUsers); - } - CompletableFuture future = null; - for (Map.Entry> en : addrUsers.entrySet()) { - Serializable[] oneaddrUserids = en.getValue().toArray(new Serializable[en.getValue().size()]); - future = future == null ? sendOneAddrMessage(en.getKey(), remoteMessage, last, oneaddrUserids) - : future.thenCombine(sendOneAddrMessage(en.getKey(), remoteMessage, last, oneaddrUserids), (a, b) -> a | b); - } - return future == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : future; - - } - - protected CompletableFuture sendOneUserMessage(final Object message, final boolean last, final Serializable userid) { - if (message instanceof CompletableFuture) return ((CompletableFuture) message).thenApply(msg -> sendOneUserMessage(msg, last, userid)); - if (logger.isLoggable(Level.FINEST)) { - logger.finest("websocket want send message {userid:" + userid + ", content:" + (message instanceof WebSocketPacket ? ((WebSocketPacket) message).toSimpleString() : (message instanceof CharSequence ? message : JsonConvert.root().convertTo(message))) + "} from locale node to " + ((this.localEngine != null) ? "locale" : "remote") + " engine"); - } - CompletableFuture localFuture = null; - if (this.localEngine != null) localFuture = localEngine.sendLocalMessage(message, last, userid); - if (this.source == null || this.remoteNode == null) { - if (logger.isLoggable(Level.FINEST)) logger.finest("websocket " + (this.remoteNode == null ? (this.source == null ? "remote and source" : "remote") : "source") + " node is null"); - //娌℃湁CacheSource灏变笉浼氭湁鍒嗗竷寮忚妭鐐 - return localFuture == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : localFuture; - } - //杩滅▼鑺傜偣鍙戦佹秷鎭 - final Object remoteMessage = formatRemoteMessage(message); - tryAcquireSemaphore(); - CompletableFuture> addrsFuture = source.getCollectionAsync(WS_SOURCE_KEY_USERID_PREFIX + userid, WebSocketAddress.class); - if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore()); - CompletableFuture remoteFuture = addrsFuture.thenCompose((Collection addrs) -> { - if (addrs == null || addrs.isEmpty()) { - if (logger.isLoggable(Level.FINER)) logger.finer("websocket not found userid:" + userid + " on any node "); - return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); - } - if (logger.isLoggable(Level.FINEST)) logger.finest("websocket(localaddr=" + wsNodeAddress + ") found userid:" + userid + " on " + addrs); - CompletableFuture future = null; - for (WebSocketAddress addr : addrs) { - if (addr == null || addr.equals(wsNodeAddress)) continue; - future = future == null ? remoteNode.sendMessage(addr.getTopic(), addr.getAddr(), remoteMessage, last, userid) - : future.thenCombine(remoteNode.sendMessage(addr.getTopic(), addr.getAddr(), remoteMessage, last, userid), (a, b) -> a | b); - } - return future == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : future; - }); - return localFuture == null ? remoteFuture : localFuture.thenCombine(remoteFuture, (a, b) -> a | b); - } - - protected CompletableFuture sendOneAddrMessage(final WebSocketAddress addr, final Object message, final boolean last, final Serializable... userids) { - if (message instanceof CompletableFuture) return ((CompletableFuture) message).thenApply(msg -> sendOneAddrMessage(addr, msg, last, userids)); - if (logger.isLoggable(Level.FINEST) && this.localEngine == null) { //鍙墦鍗拌繙绋嬫ā寮忕殑 - logger.finest("websocket want send message {userids:" + JsonConvert.root().convertTo(userids) + ", sncpaddr:" + addr + ", content:" + (message instanceof WebSocketPacket ? ((WebSocketPacket) message).toSimpleString() : (message instanceof CharSequence ? message : JsonConvert.root().convertTo(message))) + "} from locale node to " + ((this.localEngine != null) ? "locale" : "remote") + " engine"); - } - if (Objects.equals(addr, this.wsNodeAddress)) { - return this.localEngine == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : localEngine.sendLocalMessage(message, last, userids); - } - if (this.source == null || this.remoteNode == null) { - if (logger.isLoggable(Level.FINEST)) logger.finest("websocket " + (this.remoteNode == null ? (this.source == null ? "remote and source" : "remote") : "source") + " node is null"); - //娌℃湁CacheSource灏变笉浼氭湁鍒嗗竷寮忚妭鐐 - return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); - } - final Object remoteMessage = formatRemoteMessage(message); - return remoteNode.sendMessage(addr.getTopic(), addr.getAddr(), remoteMessage, last, userids); - } - - protected Serializable[] userAddressToUserids(WebSocketUserAddress... useraddrs) { - if (useraddrs == null || useraddrs.length == 1) return new Serializable[0]; - Set set = new HashSet<>(); - for (WebSocketUserAddress userAddress : useraddrs) { - set.add(userAddress.userid()); - } - return set.toArray(new Serializable[set.size()]); - } - - protected Map> userAddressToAddrMap(WebSocketUserAddress... useraddrs) { - final Map> addrUsers = new HashMap<>(); - for (WebSocketUserAddress userAddress : useraddrs) { - if (userAddress.address() != null) { - addrUsers.computeIfAbsent(userAddress.address(), k -> new ArrayList<>()).add(userAddress.userid()); - } - if (userAddress.addresses() != null) { - for (WebSocketAddress addr : userAddress.addresses()) { - if (addr != null) { - addrUsers.computeIfAbsent(addr, k -> new ArrayList<>()).add(userAddress.userid()); - } - } - } - } - return addrUsers; - } - - /** - * 骞挎挱娑堟伅锛 缁欐墍鏈変汉鍙戞秷鎭 - * - * @param message 娑堟伅鍐呭 - * - * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 - */ - @Local - public final CompletableFuture broadcastMessage(final Object message) { - return broadcastMessage((Convert) null, message, true); - } - - /** - * 骞挎挱娑堟伅锛 缁欐墍鏈変汉鍙戞秷鎭 - * - * @param wsrange 杩囨护鏉′欢 - * @param message 娑堟伅鍐呭 - * - * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 - */ - @Local - public final CompletableFuture broadcastMessage(final WebSocketRange wsrange, final Object message) { - return broadcastMessage(wsrange, (Convert) null, message, true); - } - - /** - * 骞挎挱娑堟伅锛 缁欐墍鏈変汉鍙戞秷鎭 - * - * @param convert Convert - * @param message 娑堟伅鍐呭 - * - * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 - */ - @Local - public final CompletableFuture broadcastMessage(final Convert convert, final Object message) { - return broadcastMessage(convert, message, true); - } - - /** - * 骞挎挱娑堟伅锛 缁欐墍鏈変汉鍙戞秷鎭 - * - * @param wsrange 杩囨护鏉′欢 - * @param convert Convert - * @param message 娑堟伅鍐呭 - * - * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 - */ - @Local - public final CompletableFuture broadcastMessage(final WebSocketRange wsrange, final Convert convert, final Object message) { - return broadcastMessage(wsrange, convert, message, true); - } - - /** - * 骞挎挱娑堟伅锛 缁欐墍鏈変汉鍙戞秷鎭 - * - * @param message 娑堟伅鍐呭 - * @param last 鏄惁鏈鍚庝竴鏉 - * - * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 - */ - @Local - public final CompletableFuture broadcastMessage(final Object message, final boolean last) { - return broadcastMessage((Convert) null, message, last); - } - - /** - * 骞挎挱娑堟伅锛 缁欐墍鏈変汉鍙戞秷鎭 - * - * @param wsrange 杩囨护鏉′欢 - * @param message 娑堟伅鍐呭 - * @param last 鏄惁鏈鍚庝竴鏉 - * - * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 - */ - @Local - public final CompletableFuture broadcastMessage(final WebSocketRange wsrange, final Object message, final boolean last) { - return broadcastMessage(wsrange, (Convert) null, message, last); - } - - /** - * 骞挎挱娑堟伅锛 缁欐墍鏈変汉鍙戞秷鎭 - * - * @param convert Convert - * @param message0 娑堟伅鍐呭 - * @param last 鏄惁鏈鍚庝竴鏉 - * - * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 - */ - @Local - public final CompletableFuture broadcastMessage(final Convert convert, final Object message0, final boolean last) { - return broadcastMessage((WebSocketRange) null, convert, message0, last); - } - - /** - * 骞挎挱娑堟伅锛 缁欐墍鏈変汉鍙戞秷鎭 - * - * @param wsrange 杩囨护鏉′欢 - * @param convert Convert - * @param message0 娑堟伅鍐呭 - * @param last 鏄惁鏈鍚庝竴鏉 - * - * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 - */ - @Local - public CompletableFuture broadcastMessage(final WebSocketRange wsrange, final Convert convert, final Object message0, final boolean last) { - if (message0 instanceof CompletableFuture) return ((CompletableFuture) message0).thenApply(msg -> broadcastMessage(wsrange, convert, msg, last)); - final Object message = (convert == null || message0 instanceof WebSocketPacket) ? message0 : ((convert instanceof TextConvert) ? new WebSocketPacket(((TextConvert) convert).convertTo(message0), last) : new WebSocketPacket(((BinaryConvert) convert).convertTo(message0), last)); - if (this.localEngine != null && this.source == null) { //鏈湴妯″紡涓旀病鏈夊垎甯冨紡 - return this.localEngine.broadcastLocalMessage(wsrange, message, last); - } - final Object remoteMessage = formatRemoteMessage(message); - CompletableFuture localFuture = this.localEngine == null ? null : this.localEngine.broadcastLocalMessage(wsrange, message, last); - tryAcquireSemaphore(); - CompletableFuture> addrsFuture = source.getCollectionAsync(WS_SOURCE_KEY_NODES, WebSocketAddress.class); - if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore()); - CompletableFuture remoteFuture = addrsFuture.thenCompose((Collection addrs) -> { - if (logger.isLoggable(Level.FINEST)) logger.finest("websocket broadcast message (" + remoteMessage + ") on " + addrs); - if (addrs == null || addrs.isEmpty()) return CompletableFuture.completedFuture(0); - CompletableFuture future = null; - for (WebSocketAddress addr : addrs) { - if (addr == null || addr.equals(wsNodeAddress)) continue; - future = future == null ? remoteNode.broadcastMessage(addr.getTopic(), addr.getAddr(), wsrange, remoteMessage, last) - : future.thenCombine(remoteNode.broadcastMessage(addr.getTopic(), addr.getAddr(), wsrange, remoteMessage, last), (a, b) -> a | b); - } - return future == null ? CompletableFuture.completedFuture(0) : future; - }); - return localFuture == null ? remoteFuture : localFuture.thenCombine(remoteFuture, (a, b) -> a | b); - } - - /** - * 骞挎挱鎿嶄綔锛 缁欐墍鏈変汉鍙戞搷浣 - * - * @param action 鎿嶄綔鍙傛暟 - * - * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 - */ - @Local - public CompletableFuture broadcastAction(final WebSocketAction action) { - if (this.localEngine != null && this.source == null) { //鏈湴妯″紡涓旀病鏈夊垎甯冨紡 - return this.localEngine.broadcastLocalAction(action); - } - CompletableFuture localFuture = this.localEngine == null ? null : this.localEngine.broadcastLocalAction(action); - tryAcquireSemaphore(); - CompletableFuture> addrsFuture = source.getCollectionAsync(WS_SOURCE_KEY_NODES, WebSocketAddress.class); - if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore()); - CompletableFuture remoteFuture = addrsFuture.thenCompose((Collection addrs) -> { - if (logger.isLoggable(Level.FINEST)) logger.finest("websocket broadcast action (" + action + ") on " + addrs); - if (addrs == null || addrs.isEmpty()) return CompletableFuture.completedFuture(0); - CompletableFuture future = null; - for (WebSocketAddress addr : addrs) { - if (addr == null || addr.equals(wsNodeAddress)) continue; - future = future == null ? remoteNode.broadcastAction(addr.getTopic(), addr.getAddr(), action) - : future.thenCombine(remoteNode.broadcastAction(addr.getTopic(), addr.getAddr(), action), (a, b) -> a | b); - } - return future == null ? CompletableFuture.completedFuture(0) : future; - }); - return localFuture == null ? remoteFuture : localFuture.thenCombine(remoteFuture, (a, b) -> a | b); - } - - /** - * 鍚戞寚瀹氱敤鎴峰彂閫佹搷浣滐紝鍏堝彂閫佹湰鍦拌繛鎺ワ紝鍐嶅彂閫佽繙绋嬭繛鎺
- * 濡傛灉褰撳墠WebSocketNode鏄繙绋嬫ā寮忥紝姝ゆ柟娉曞彧鍙戦佽繙绋嬭繛鎺 - * - * @param action 鎿嶄綔鍙傛暟 - * @param userids Serializable[] - * - * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 - */ - @Local - public CompletableFuture sendAction(final WebSocketAction action, final Serializable... userids) { - if (userids == null || userids.length < 1) return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); - if (userids[0] instanceof WebSocketUserAddress) { - WebSocketUserAddress[] useraddrs = new WebSocketUserAddress[userids.length]; - for (int i = 0; i < useraddrs.length; i++) { - useraddrs[i] = (WebSocketUserAddress) userids[i]; - } - return sendAction(action, useraddrs); - } - if (this.localEngine != null && this.source == null) { //鏈湴妯″紡涓旀病鏈夊垎甯冨紡 - return this.localEngine.sendLocalAction(action, userids); - } - CompletableFuture rsfuture; - if (userids.length == 1) { - rsfuture = sendOneUserAction(action, userids[0]); - } else { - String[] keys = new String[userids.length]; - final Map keyuser = new HashMap<>(); - for (int i = 0; i < userids.length; i++) { - keys[i] = WS_SOURCE_KEY_USERID_PREFIX + userids[i]; - keyuser.put(keys[i], userids[i]); - } - tryAcquireSemaphore(); - CompletableFuture>> addrsFuture = source.getCollectionMapAsync(true, WebSocketAddress.class, keys); - if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore()); - rsfuture = addrsFuture.thenCompose((Map> addrs) -> { - if (addrs == null || addrs.isEmpty()) { - if (logger.isLoggable(Level.FINER)) logger.finer("websocket not found userids:" + JsonConvert.root().convertTo(userids) + " on any node "); - return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); - } - Map> addrUsers = new HashMap<>(); - addrs.forEach((key, as) -> { - for (WebSocketAddress a : as) { - addrUsers.computeIfAbsent(a, k -> new ArrayList<>()).add(keyuser.get(key)); - } - }); - if (logger.isLoggable(Level.FINEST)) { - logger.finest("websocket(localaddr=" + localSncpAddress + ", userids=" + JsonConvert.root().convertTo(userids) + ") found action-userid-addrs: " + addrUsers); - } - CompletableFuture future = null; - for (Map.Entry> en : addrUsers.entrySet()) { - Serializable[] oneaddrUserids = en.getValue().toArray(new Serializable[en.getValue().size()]); - future = future == null ? sendOneAddrAction(en.getKey(), action, oneaddrUserids) - : future.thenCombine(sendOneAddrAction(en.getKey(), action, oneaddrUserids), (a, b) -> a | b); - } - return future == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : future; - }); - } - return rsfuture == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : rsfuture; - } - - /** - * 鍚戞寚瀹氱敤鎴峰彂閫佹搷浣滐紝鍏堝彂閫佹湰鍦拌繛鎺ワ紝鍐嶅彂閫佽繙绋嬭繛鎺
- * 濡傛灉褰撳墠WebSocketNode鏄繙绋嬫ā寮忥紝姝ゆ柟娉曞彧鍙戦佽繙绋嬭繛鎺 - * - * @param action 鎿嶄綔鍙傛暟 - * @param useraddrs WebSocketUserAddress[] - * - * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 - */ - @Local - public CompletableFuture sendAction(final WebSocketAction action, final WebSocketUserAddress... useraddrs) { - if (useraddrs == null || useraddrs.length < 1) return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); - if (this.localEngine != null && this.source == null) { //鏈湴妯″紡涓旀病鏈夊垎甯冨紡 - return this.localEngine.sendLocalAction(action, userAddressToUserids(useraddrs)); - } - - final Map> addrUsers = userAddressToAddrMap(useraddrs); - if (logger.isLoggable(Level.FINEST)) { - logger.finest("websocket(localaddr=" + localSncpAddress + ", useraddrs=" + JsonConvert.root().convertTo(useraddrs) + ") found action-userid-addrs: " + addrUsers); - } - CompletableFuture future = null; - for (Map.Entry> en : addrUsers.entrySet()) { - Serializable[] oneaddrUserids = en.getValue().toArray(new Serializable[en.getValue().size()]); - future = future == null ? sendOneAddrAction(en.getKey(), action, oneaddrUserids) - : future.thenCombine(sendOneAddrAction(en.getKey(), action, oneaddrUserids), (a, b) -> a | b); - } - return future == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : future; - } - - protected CompletableFuture sendOneUserAction(final WebSocketAction action, final Serializable userid) { - if (logger.isLoggable(Level.FINEST)) { - logger.finest("websocket want send action {userid:" + userid + ", action:" + action + "} from locale node to " + ((this.localEngine != null) ? "locale" : "remote") + " engine"); - } - CompletableFuture localFuture = null; - if (this.localEngine != null) localFuture = localEngine.sendLocalAction(action, userid); - if (this.source == null || this.remoteNode == null) { - if (logger.isLoggable(Level.FINEST)) logger.finest("websocket " + (this.remoteNode == null ? (this.source == null ? "remote and source" : "remote") : "source") + " node is null"); - //娌℃湁CacheSource灏变笉浼氭湁鍒嗗竷寮忚妭鐐 - return localFuture == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : localFuture; - } - //杩滅▼鑺傜偣鍙戦佹搷浣 - tryAcquireSemaphore(); - CompletableFuture> addrsFuture = source.getCollectionAsync(WS_SOURCE_KEY_USERID_PREFIX + userid, WebSocketAddress.class); - if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore()); - CompletableFuture remoteFuture = addrsFuture.thenCompose((Collection addrs) -> { - if (addrs == null || addrs.isEmpty()) { - if (logger.isLoggable(Level.FINER)) logger.finer("websocket not found userid:" + userid + " on any node "); - return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); - } - if (logger.isLoggable(Level.FINEST)) logger.finest("websocket(localaddr=" + localSncpAddress + ") found userid:" + userid + " on " + addrs); - CompletableFuture future = null; - for (WebSocketAddress addr : addrs) { - if (addr == null || addr.equals(wsNodeAddress)) continue; - future = future == null ? remoteNode.sendAction(addr.getTopic(), addr.getAddr(), action, userid) - : future.thenCombine(remoteNode.sendAction(addr.getTopic(), addr.getAddr(), action, userid), (a, b) -> a | b); - } - return future == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : future; - }); - return localFuture == null ? remoteFuture : localFuture.thenCombine(remoteFuture, (a, b) -> a | b); - } - - protected CompletableFuture sendOneAddrAction(final WebSocketAddress addr, final WebSocketAction action, final Serializable... userids) { - if (logger.isLoggable(Level.FINEST) && this.localEngine == null) { //鍙墦鍗拌繙绋嬫ā寮忕殑 - logger.finest("websocket want send action {userids:" + JsonConvert.root().convertTo(userids) + ", sncpaddr:" + addr + ", action:" + action + " from locale node to " + ((this.localEngine != null) ? "locale" : "remote") + " engine"); - } - if (Objects.equals(addr, this.wsNodeAddress)) { - return this.localEngine == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : localEngine.sendLocalAction(action, userids); - } - if (this.source == null || this.remoteNode == null) { - if (logger.isLoggable(Level.FINEST)) logger.finest("websocket " + (this.remoteNode == null ? (this.source == null ? "remote and source" : "remote") : "source") + " node is null"); - //娌℃湁CacheSource灏变笉浼氭湁鍒嗗竷寮忚妭鐐 - return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); - } - return remoteNode.sendAction(addr.getTopic(), addr.getAddr(), action, userids); - } - - protected Object formatRemoteMessage(Object message) { - if (message instanceof WebSocketPacket) return message; - if (message instanceof byte[]) return message; - if (message instanceof CharSequence) return message; - if (sendConvert instanceof TextConvert) ((TextConvert) sendConvert).convertTo(message); - if (sendConvert instanceof BinaryConvert) ((BinaryConvert) sendConvert).convertTo(message); - return JsonConvert.root().convertTo(message); - } - - protected boolean tryAcquireSemaphore() { - if (this.semaphore == null) return true; - try { - return this.semaphore.tryAcquire(tryAcquireSeconds, TimeUnit.SECONDS); - } catch (Exception e) { - return false; - } - } - - protected void releaseSemaphore() { - if (this.semaphore != null) this.semaphore.release(); - } -} +/* + * 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 static org.redkale.net.http.WebSocket.*; +import java.io.*; +import java.net.*; +import java.util.*; +import java.util.concurrent.*; +import java.util.logging.*; +import java.util.stream.*; +import javax.annotation.*; +import org.redkale.boot.*; +import org.redkale.convert.*; +import org.redkale.convert.json.JsonConvert; +import org.redkale.mq.MessageAgent; +import org.redkale.service.*; +import org.redkale.source.*; +import org.redkale.util.*; + +/** + * 娉: 閮ㄧ讲浜哤ebSocketNodeService灏卞繀鐒惰閰嶇疆SNCP鍗忚鐨凷erver锛屼笉鐒舵棤娉曞仛鍒癢ebSocketNode.sendMessage鏂规硶鐨勬湁鏁堟 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public abstract class WebSocketNode { + + @Comment("瀛樺偍鐢ㄦ埛ID鐨刱ey鍓嶇紑") + public static final String WS_SOURCE_KEY_USERID_PREFIX = "sncpws_uid:"; + + @Comment("瀛樺偍褰撳墠SNCP鑺傜偣鍒楄〃鐨刱ey") + public static final String WS_SOURCE_KEY_NODES = "sncpws_nodes"; + + protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); + + //"SNCP_ADDR" 濡傛灉涓嶆槸鍒嗗竷寮(娌℃湁SNCP) 鍊间负null + @Resource(name = Application.RESNAME_SNCP_ADDR) + protected InetSocketAddress localSncpAddress; //涓篠ncpServer鐨勬湇鍔ddress + + protected WebSocketAddress wsNodeAddress; + + protected String name; + + //濡傛灉涓嶆槸鍒嗗竷寮(娌℃湁SNCP) 鍊间负null + @RpcRemote + protected WebSocketNode remoteNode; + + @Resource(name = "$_sendconvert") + protected Convert sendConvert; + + //瀛樻斁鎵鏈夌敤鎴峰垎甯冨湪鑺傜偣涓婄殑闃熷垪淇℃伅,Set 涓 sncpnode 鐨勯泦鍚堬紝 key: groupid + //闆嗗悎鍖呭惈 localSncpAddress + //濡傛灉涓嶆槸鍒嗗竷寮(娌℃湁SNCP)锛宻ource 灏嗕笉浼氳鐢ㄥ埌 + @Resource(name = "$") + protected CacheSource source; + + //褰撳墠鑺傜偣鐨勬湰鍦癢ebSocketEngine + protected WebSocketEngine localEngine; + + protected MessageAgent messageAgent; + + protected Semaphore semaphore; + + private int tryAcquireSeconds = 12; + + public void init(AnyValue conf) { + this.tryAcquireSeconds = Integer.getInteger("redkale.http.websocket.tryAcquireSeconds", 12); + + if (localEngine != null) { + int wsthreads = localEngine.wsthreads; + if (wsthreads == 0) wsthreads = Utility.cpus() * 8; + if (wsthreads > 0) this.semaphore = new Semaphore(wsthreads); + } + String mqtopic = this.messageAgent == null ? null : this.messageAgent.generateSncpReqTopic((Service) this); + if (mqtopic != null || this.localSncpAddress != null) { + this.wsNodeAddress = new WebSocketAddress(mqtopic, localSncpAddress); + } + if (source != null && this.wsNodeAddress == null) { //闈炲垎甯冨紡妯″紡 + this.wsNodeAddress = new WebSocketAddress(mqtopic, new InetSocketAddress("127.0.0.1", 27)); + } + if (source != null && wsNodeAddress != null) { + source.appendSetItem(WS_SOURCE_KEY_NODES, WebSocketAddress.class, this.wsNodeAddress); + } + } + + public void destroy(AnyValue conf) { + } + + @Local + public final Semaphore getSemaphore() { + return semaphore; + } + + @Local + public final MessageAgent getMessageAgent() { + return messageAgent; + } + + @Local + protected void postDestroy(AnyValue conf) { + if (this.localEngine == null) return; + //鍏虫帀鎵鏈夋湰鍦版湰鍦癢ebSocket + this.localEngine.getLocalWebSockets().forEach(g -> g.close()); + if (source != null && wsNodeAddress != null) { + source.removeSetItem(WS_SOURCE_KEY_NODES, WebSocketAddress.class, this.wsNodeAddress); + } + } + + protected abstract CompletableFuture> getWebSocketAddresses(@RpcTargetTopic String topic, @RpcTargetAddress InetSocketAddress targetAddress, Serializable userid); + + protected abstract CompletableFuture sendMessage(@RpcTargetTopic String topic, @RpcTargetAddress InetSocketAddress targetAddress, Object message, boolean last, Serializable... userids); + + protected abstract CompletableFuture broadcastMessage(@RpcTargetTopic String topic, @RpcTargetAddress InetSocketAddress targetAddress, WebSocketRange wsrange, Object message, boolean last); + + protected abstract CompletableFuture sendAction(@RpcTargetTopic String topic, @RpcTargetAddress InetSocketAddress targetAddress, WebSocketAction action, Serializable... userids); + + protected abstract CompletableFuture broadcastAction(@RpcTargetTopic String topic, @RpcTargetAddress InetSocketAddress targetAddress, WebSocketAction action); + + protected abstract CompletableFuture getUserSize(@RpcTargetTopic String topic, @RpcTargetAddress InetSocketAddress targetAddress); + + protected abstract CompletableFuture connect(Serializable userid, WebSocketAddress wsaddr); + + protected abstract CompletableFuture disconnect(Serializable userid, WebSocketAddress wsaddr); + + protected abstract CompletableFuture changeUserid(Serializable fromuserid, Serializable touserid, WebSocketAddress wsaddr); + + protected abstract CompletableFuture existsWebSocket(Serializable userid, @RpcTargetTopic String topic, @RpcTargetAddress InetSocketAddress targetAddress); + + protected abstract CompletableFuture forceCloseWebSocket(Serializable userid, @RpcTargetTopic String topic, @RpcTargetAddress InetSocketAddress targetAddress); + + //-------------------------------------------------------------------------------- + final CompletableFuture connect(final Serializable userid) { + if (logger.isLoggable(Level.FINEST)) logger.finest(wsNodeAddress + " receive websocket connect event (" + userid + " on " + (this.localEngine == null ? null : this.localEngine.getEngineid()) + ")."); + return connect(userid, wsNodeAddress); + } + + final CompletableFuture disconnect(final Serializable userid) { + if (logger.isLoggable(Level.FINEST)) logger.finest(wsNodeAddress + " receive websocket disconnect event (" + userid + " on " + (this.localEngine == null ? null : this.localEngine.getEngineid()) + ")."); + return disconnect(userid, wsNodeAddress); + } + + final CompletableFuture changeUserid(Serializable olduserid, final Serializable newuserid) { + if (logger.isLoggable(Level.FINEST)) logger.finest(wsNodeAddress + " receive websocket changeUserid event (from " + olduserid + " to " + newuserid + " on " + (this.localEngine == null ? null : this.localEngine.getEngineid()) + ")."); + return changeUserid(olduserid, newuserid, wsNodeAddress); + } + + public final String getName() { + return name; + } + + //-------------------------------------------------------------------------------- + /** + * 鑾峰彇鐩爣鍦板潃
+ * 璇ユ柟娉曚粎渚涘唴閮ㄨ皟鐢 + * + * @param topic RpcTargetTopic + * @param targetAddress InetSocketAddress + * @param userid Serializable + * + * @return 瀹㈡埛绔湴鍧鍒楄〃 + */ + protected CompletableFuture> remoteWebSocketAddresses(@RpcTargetTopic String topic, @RpcTargetAddress InetSocketAddress targetAddress, Serializable userid) { + if (remoteNode == null) return CompletableFuture.completedFuture(null); + try { + return remoteNode.getWebSocketAddresses(topic, targetAddress, userid); + } catch (Exception e) { + logger.log(Level.WARNING, "remote " + targetAddress + " websocket getOnlineRemoteAddresses error", e); + return CompletableFuture.completedFuture(null); + } + } + + /** + * 鑾峰彇鐢ㄦ埛鍦ㄧ嚎鐨凷NCP鑺傜偣鍦板潃鍒楄〃锛屼笉鏄垎甯冨紡鍒欒繑鍥炲厓绱犳暟閲忎负1锛屼笖鍏冪礌鍊间负null鐨勫垪琛
+ * WebSocketAddress 涓 SNCP鑺傜偣鍦板潃 + * + * @param userid Serializable + * + * @return 鍦板潃鍒楄〃 + */ + public CompletableFuture> getRpcNodeAddresses(final Serializable userid) { + if (this.source != null) { + tryAcquireSemaphore(); + CompletableFuture> result = this.source.getCollectionAsync(WS_SOURCE_KEY_USERID_PREFIX + userid, WebSocketAddress.class); + if (semaphore != null) result.whenComplete((r, e) -> releaseSemaphore()); + return result; + } + List rs = new ArrayList<>(); + rs.add(this.wsNodeAddress); + return CompletableFuture.completedFuture(rs); + } + + /** + * 鑾峰彇鍦ㄧ嚎鐢ㄦ埛鐨勮缁嗚繛鎺ヤ俊鎭
+ * Map.key 涓 SNCP鑺傜偣鍦板潃, 鍚间负null鐨刱ey琛ㄧず娌℃湁鍒嗗竷寮 + * Map.value 涓 鐢ㄦ埛瀹㈡埛绔殑IP + * + * @param userid Serializable + * + * @return 鍦板潃闆嗗悎 + */ + public CompletableFuture>> getRpcNodeWebSocketAddresses(final Serializable userid) { + CompletableFuture> sncpFuture = getRpcNodeAddresses(userid); + return sncpFuture.thenCompose((Collection addrs) -> { + if (logger.isLoggable(Level.FINEST)) logger.finest("websocket found userid:" + userid + " on " + addrs); + if (addrs == null || addrs.isEmpty()) return CompletableFuture.completedFuture(new HashMap<>()); + CompletableFuture>> future = null; + for (final WebSocketAddress nodeAddress : addrs) { + CompletableFuture>> mapFuture = getWebSocketAddresses(nodeAddress.getTopic(), nodeAddress.getAddr(), userid) + .thenCompose((List list) -> CompletableFuture.completedFuture(Utility.ofMap(nodeAddress, list))); + future = future == null ? mapFuture : future.thenCombine(mapFuture, (a, b) -> Utility.merge(a, b)); + } + return future == null ? CompletableFuture.completedFuture(new HashMap<>()) : future; + }); + } + +// public CompletableFuture getUserSize() { +// if (this.localEngine != null && this.source == null) { +// return CompletableFuture.completedFuture(this.localEngine.getLocalUserSize()); +// } +// tryAcquireSemaphore(); +// CompletableFuture> listFuture = this.source.queryKeysStartsWithAsync(WS_SOURCE_KEY_USERID_PREFIX); +// CompletableFuture rs = listFuture.thenApply(v -> v.size()); +// if (semaphore != null) rs.whenComplete((r, e) -> releaseSemaphore()); +// return rs; +// } + /** + * 鑾峰彇鍦ㄧ嚎鐢ㄦ埛鎬绘暟 + * + * + * @return boolean + */ + @Local + public CompletableFuture getUserSize() { + if (this.localEngine != null && this.source == null) { //鏈湴妯″紡涓旀病鏈夊垎甯冨紡 + return CompletableFuture.completedFuture(this.localEngine.getLocalUserSize()); + } + CompletableFuture localFuture = this.localEngine == null ? null : CompletableFuture.completedFuture(this.localEngine.getLocalUserSize()); + tryAcquireSemaphore(); + CompletableFuture> addrsFuture = source.getCollectionAsync(WS_SOURCE_KEY_NODES, WebSocketAddress.class); + if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore()); + CompletableFuture remoteFuture = addrsFuture.thenCompose((Collection addrs) -> { + if (logger.isLoggable(Level.FINEST)) logger.finest("websocket getUserSize on " + addrs); + if (addrs == null || addrs.isEmpty()) return CompletableFuture.completedFuture(0); + CompletableFuture future = null; + for (WebSocketAddress addr : addrs) { + if (addr == null || addr.equals(wsNodeAddress)) continue; + future = future == null ? remoteNode.getUserSize(addr.getTopic(), addr.getAddr()) + : future.thenCombine(remoteNode.getUserSize(addr.getTopic(), addr.getAddr()), (a, b) -> a + b); + } + return future == null ? CompletableFuture.completedFuture(0) : future; + }); + return localFuture == null ? remoteFuture : localFuture.thenCombine(remoteFuture, (a, b) -> a + b); + } + + /** + * 鑾峰彇鍦ㄧ嚎鐢ㄦ埛鎬绘暟 + * + * + * @return boolean + */ + public CompletableFuture> getUserSet() { + if (this.localEngine != null && this.source == null) { + return CompletableFuture.completedFuture(new LinkedHashSet<>(this.localEngine.getLocalUserSet().stream().map(x -> String.valueOf(x)).collect(Collectors.toList()))); + } + tryAcquireSemaphore(); + CompletableFuture> listFuture = this.source.queryKeysStartsWithAsync(WS_SOURCE_KEY_USERID_PREFIX); + CompletableFuture> rs = listFuture.thenApply(v -> new LinkedHashSet<>(v.stream().map(x -> x.substring(WS_SOURCE_KEY_USERID_PREFIX.length())).collect(Collectors.toList()))); + if (semaphore != null) rs.whenComplete((r, e) -> releaseSemaphore()); + return rs; + } + + /** + * 鍒ゆ柇鎸囧畾鐢ㄦ埛鏄惁WebSocket鍦ㄧ嚎 + * + * @param userid Serializable + * + * @return boolean + */ + @Local + public CompletableFuture existsWebSocket(final Serializable userid) { + if (userid instanceof WebSocketUserAddress) return existsWebSocket((WebSocketUserAddress) userid); + CompletableFuture localFuture = null; + if (this.localEngine != null) localFuture = CompletableFuture.completedFuture(localEngine.existsLocalWebSocket(userid)); + if (this.source == null || this.remoteNode == null) { + if (logger.isLoggable(Level.FINEST)) logger.finest("websocket " + (this.remoteNode == null ? (this.source == null ? "remote and source" : "remote") : "source") + " node is null"); + //娌℃湁CacheSource灏变笉浼氭湁鍒嗗竷寮忚妭鐐 + return localFuture == null ? CompletableFuture.completedFuture(false) : localFuture; + } + //杩滅▼鑺傜偣鍏抽棴 + tryAcquireSemaphore(); + CompletableFuture> addrsFuture = source.getCollectionAsync(WS_SOURCE_KEY_USERID_PREFIX + userid, WebSocketAddress.class); + if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore()); + CompletableFuture remoteFuture = addrsFuture.thenCompose((Collection addrs) -> { + //if (logger.isLoggable(Level.FINEST)) logger.finest("websocket found userid:" + userid + " on " + addrs); + if (addrs == null || addrs.isEmpty()) return CompletableFuture.completedFuture(false); + CompletableFuture future = null; + for (WebSocketAddress addr : addrs) { + if (addr == null || addr.equals(wsNodeAddress)) continue; + future = future == null ? remoteNode.existsWebSocket(userid, addr.getTopic(), addr.getAddr()) + : future.thenCombine(remoteNode.existsWebSocket(userid, addr.getTopic(), addr.getAddr()), (a, b) -> a | b); + } + return future == null ? CompletableFuture.completedFuture(false) : future; + }); + return localFuture == null ? remoteFuture : localFuture.thenCombine(remoteFuture, (a, b) -> a | b); + } + + /** + * 鍒ゆ柇鎸囧畾鐢ㄦ埛鏄惁WebSocket鍦ㄧ嚎 + * + * @param userAddress WebSocketUserAddress + * + * @return boolean + */ + @Local + public CompletableFuture existsWebSocket(final WebSocketUserAddress userAddress) { + if (this.localEngine != null && localEngine.existsLocalWebSocket(userAddress.userid())) return CompletableFuture.completedFuture(true); + if (this.source == null || this.remoteNode == null) { + if (logger.isLoggable(Level.FINEST)) logger.finest("websocket " + (this.remoteNode == null ? (this.source == null ? "remote and source" : "remote") : "source") + " node is null"); + //娌℃湁CacheSource灏变笉浼氭湁鍒嗗竷寮忚妭鐐 + return CompletableFuture.completedFuture(false); + } + Collection addrs = userAddress.addresses(); + if (addrs != null) addrs = new ArrayList<>(addrs); //涓嶈兘淇敼鍙傛暟鍐呴儴鍊 + if (userAddress.address() != null) { + if (addrs == null) addrs = new ArrayList<>(); + addrs.add(userAddress.address()); + } + if (addrs == null || addrs.isEmpty()) return CompletableFuture.completedFuture(false); + CompletableFuture future = null; + for (WebSocketAddress addr : addrs) { + if (addr == null || addr.equals(wsNodeAddress)) continue; + future = future == null ? remoteNode.existsWebSocket(userAddress.userid(), addr.getTopic(), addr.getAddr()) + : future.thenCombine(remoteNode.existsWebSocket(userAddress.userid(), addr.getTopic(), addr.getAddr()), (a, b) -> a | b); + } + return future == null ? CompletableFuture.completedFuture(false) : future; + } + + /** + * 寮哄埗鍏抽棴鐢ㄦ埛WebSocket + * + * @param userid Serializable + * + * @return int + */ + @Local + public CompletableFuture forceCloseWebSocket(final Serializable userid) { + return forceCloseWebSocket(userid, (WebSocketUserAddress) null); + } + + /** + * 寮哄埗鍏抽棴鐢ㄦ埛WebSocket + * + * @param userAddress WebSocketUserAddress + * + * @return int + */ + @Local + public CompletableFuture forceCloseWebSocket(final WebSocketUserAddress userAddress) { + return forceCloseWebSocket(null, userAddress); + } + + private CompletableFuture forceCloseWebSocket(final Serializable userid, final WebSocketUserAddress userAddress) { + CompletableFuture localFuture = null; + if (this.localEngine != null) localFuture = CompletableFuture.completedFuture(localEngine.forceCloseLocalWebSocket(userAddress == null ? userid : userAddress.userid())); + if (this.source == null || this.remoteNode == null) { + if (logger.isLoggable(Level.FINEST)) logger.finest("websocket " + (this.remoteNode == null ? (this.source == null ? "remote and source" : "remote") : "source") + " node is null"); + //娌℃湁CacheSource灏变笉浼氭湁鍒嗗竷寮忚妭鐐 + return localFuture == null ? CompletableFuture.completedFuture(0) : localFuture; + } + //杩滅▼鑺傜偣鍏抽棴 + CompletableFuture> addrsFuture; + if (userAddress == null) { + tryAcquireSemaphore(); + addrsFuture = source.getCollectionAsync(WS_SOURCE_KEY_USERID_PREFIX + userid, WebSocketAddress.class); + if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore()); + } else { + Collection addrs = userAddress.addresses(); + if (addrs != null) addrs = new ArrayList<>(addrs); //涓嶈兘淇敼鍙傛暟鍐呴儴鍊 + if (userAddress.address() != null) { + if (addrs == null) addrs = new ArrayList<>(); + addrs.add(userAddress.address()); + } + if (addrs == null || addrs.isEmpty()) return CompletableFuture.completedFuture(0); + addrsFuture = CompletableFuture.completedFuture(addrs); + } + CompletableFuture remoteFuture = addrsFuture.thenCompose((Collection addrs) -> { + if (logger.isLoggable(Level.FINEST)) logger.finest("websocket found userid:" + userid + " on " + addrs); + if (addrs == null || addrs.isEmpty()) return CompletableFuture.completedFuture(0); + CompletableFuture future = null; + for (WebSocketAddress addr : addrs) { + if (addr == null || addr.equals(wsNodeAddress)) continue; + future = future == null ? remoteNode.forceCloseWebSocket(userid, addr.getTopic(), addr.getAddr()) + : future.thenCombine(remoteNode.forceCloseWebSocket(userid, addr.getTopic(), addr.getAddr()), (a, b) -> a + b); + } + return future == null ? CompletableFuture.completedFuture(0) : future; + }); + return localFuture == null ? remoteFuture : localFuture.thenCombine(remoteFuture, (a, b) -> a + b); + } + + //-------------------------------------------------------------------------------- + /** + * 鑾峰彇鏈湴鐨刉ebSocketEngine锛屾病鏈夊垯杩斿洖null + * + * + * @return WebSocketEngine + */ + @Local + public final WebSocketEngine getLocalWebSocketEngine() { + return this.localEngine; + } + + /** + * 鍚戞寚瀹氱敤鎴峰彂閫佹秷鎭紝鍏堝彂閫佹湰鍦拌繛鎺ワ紝鍐嶅彂閫佽繙绋嬭繛鎺
+ * 濡傛灉褰撳墠WebSocketNode鏄繙绋嬫ā寮忥紝姝ゆ柟娉曞彧鍙戦佽繙绋嬭繛鎺 + * + * @param message 娑堟伅鍐呭 + * @param useridOrAddrs Stream + * + * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 + */ + @Local + public final CompletableFuture sendMessage(Object message, final Stream useridOrAddrs) { + return sendMessage((Convert) null, message, true, useridOrAddrs); + } + + /** + * 鍚戞寚瀹氱敤鎴峰彂閫佹秷鎭紝鍏堝彂閫佹湰鍦拌繛鎺ワ紝鍐嶅彂閫佽繙绋嬭繛鎺
+ * 濡傛灉褰撳墠WebSocketNode鏄繙绋嬫ā寮忥紝姝ゆ柟娉曞彧鍙戦佽繙绋嬭繛鎺 + * + * @param message 娑堟伅鍐呭 + * @param useridOrAddrs Serializable[] + * + * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 + */ + @Local + public final CompletableFuture sendMessage(Object message, final Serializable... useridOrAddrs) { + return sendMessage((Convert) null, message, true, useridOrAddrs); + } + + /** + * 鍚戞寚瀹氱敤鎴峰彂閫佹秷鎭紝鍏堝彂閫佹湰鍦拌繛鎺ワ紝鍐嶅彂閫佽繙绋嬭繛鎺
+ * 濡傛灉褰撳墠WebSocketNode鏄繙绋嬫ā寮忥紝姝ゆ柟娉曞彧鍙戦佽繙绋嬭繛鎺 + * + * @param convert Convert + * @param message 娑堟伅鍐呭 + * @param useridOrAddrs Stream + * + * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 + */ + @Local + public final CompletableFuture sendMessage(final Convert convert, Object message, final Stream useridOrAddrs) { + return sendMessage(convert, message, true, useridOrAddrs); + } + + /** + * 鍚戞寚瀹氱敤鎴峰彂閫佹秷鎭紝鍏堝彂閫佹湰鍦拌繛鎺ワ紝鍐嶅彂閫佽繙绋嬭繛鎺
+ * 濡傛灉褰撳墠WebSocketNode鏄繙绋嬫ā寮忥紝姝ゆ柟娉曞彧鍙戦佽繙绋嬭繛鎺 + * + * @param convert Convert + * @param message 娑堟伅鍐呭 + * @param useridOrAddrs Serializable[] + * + * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 + */ + @Local + public final CompletableFuture sendMessage(final Convert convert, Object message, final Serializable... useridOrAddrs) { + return sendMessage(convert, message, true, useridOrAddrs); + } + + /** + * 鍚戞寚瀹氱敤鎴峰彂閫佹秷鎭紝鍏堝彂閫佹湰鍦拌繛鎺ワ紝鍐嶅彂閫佽繙绋嬭繛鎺
+ * 濡傛灉褰撳墠WebSocketNode鏄繙绋嬫ā寮忥紝姝ゆ柟娉曞彧鍙戦佽繙绋嬭繛鎺 + * + * @param message 娑堟伅鍐呭 + * @param last 鏄惁鏈鍚庝竴鏉 + * @param useridOrAddrs Stream + * + * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 + */ + @Local + public final CompletableFuture sendMessage(final Object message, final boolean last, final Stream useridOrAddrs) { + return sendMessage((Convert) null, message, last, useridOrAddrs); + } + + /** + * 鍚戞寚瀹氱敤鎴峰彂閫佹秷鎭紝鍏堝彂閫佹湰鍦拌繛鎺ワ紝鍐嶅彂閫佽繙绋嬭繛鎺
+ * 濡傛灉褰撳墠WebSocketNode鏄繙绋嬫ā寮忥紝姝ゆ柟娉曞彧鍙戦佽繙绋嬭繛鎺 + * + * @param message 娑堟伅鍐呭 + * @param last 鏄惁鏈鍚庝竴鏉 + * @param useridOrAddrs Serializable[] + * + * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 + */ + @Local + public final CompletableFuture sendMessage(final Object message, final boolean last, final Serializable... useridOrAddrs) { + return sendMessage((Convert) null, message, last, useridOrAddrs); + } + + /** + * 鍚戞寚瀹氱敤鎴峰彂閫佹秷鎭紝鍏堝彂閫佹湰鍦拌繛鎺ワ紝鍐嶅彂閫佽繙绋嬭繛鎺
+ * 濡傛灉褰撳墠WebSocketNode鏄繙绋嬫ā寮忥紝姝ゆ柟娉曞彧鍙戦佽繙绋嬭繛鎺 + * + * @param convert Convert + * @param message0 娑堟伅鍐呭 + * @param last 鏄惁鏈鍚庝竴鏉 + * @param userids Stream + * + * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 + */ + @Local + public final CompletableFuture sendMessage(final Convert convert, final Object message0, final boolean last, final Stream userids) { + Object[] array = userids.toArray(); + Serializable[] ss = new Serializable[array.length]; + for (int i = 0; i < array.length; i++) { + ss[i] = (Serializable) array[i]; + } + return sendMessage(convert, message0, last, ss); + } + + /** + * 鍚戞寚瀹氱敤鎴峰彂閫佹秷鎭紝鍏堝彂閫佹湰鍦拌繛鎺ワ紝鍐嶅彂閫佽繙绋嬭繛鎺
+ * 濡傛灉褰撳墠WebSocketNode鏄繙绋嬫ā寮忥紝姝ゆ柟娉曞彧鍙戦佽繙绋嬭繛鎺 + * + * @param convert Convert + * @param message0 娑堟伅鍐呭 + * @param last 鏄惁鏈鍚庝竴鏉 + * @param userids Serializable[] + * + * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 + */ + @Local + public CompletableFuture sendMessage(final Convert convert, final Object message0, final boolean last, final Serializable... userids) { + if (userids == null || userids.length < 1) return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); + if (userids[0] instanceof WebSocketUserAddress) { + WebSocketUserAddress[] useraddrs = new WebSocketUserAddress[userids.length]; + for (int i = 0; i < useraddrs.length; i++) { + useraddrs[i] = (WebSocketUserAddress) userids[i]; + } + return sendMessage(convert, message0, last, useraddrs); + } + if (message0 instanceof CompletableFuture) return ((CompletableFuture) message0).thenApply(msg -> sendMessage(convert, msg, last, userids)); + final Object message = (convert == null || message0 instanceof WebSocketPacket) ? message0 : ((convert instanceof TextConvert) ? new WebSocketPacket(WebSocketPacket.FrameType.TEXT, ((TextConvert) convert).convertToBytes(message0), last) : new WebSocketPacket(WebSocketPacket.FrameType.BINARY, ((BinaryConvert) convert).convertToBytes(message0), last)); + if (this.localEngine != null && this.source == null) { //鏈湴妯″紡涓旀病鏈夊垎甯冨紡 + return this.localEngine.sendLocalMessage(message, last, userids); + } + final Object remoteMessage = formatRemoteMessage(message); + CompletableFuture rsfuture; + if (userids.length == 1) { + rsfuture = sendOneUserMessage(remoteMessage, last, userids[0]); + } else { + String[] keys = new String[userids.length]; + final Map keyuser = new HashMap<>(); + for (int i = 0; i < userids.length; i++) { + keys[i] = WS_SOURCE_KEY_USERID_PREFIX + userids[i]; + keyuser.put(keys[i], userids[i]); + } + tryAcquireSemaphore(); + CompletableFuture>> addrsFuture = source.getCollectionMapAsync(true, WebSocketAddress.class, keys); + if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore()); + rsfuture = addrsFuture.thenCompose((Map> addrs) -> { + if (addrs == null || addrs.isEmpty()) { + if (logger.isLoggable(Level.FINER)) logger.finer("websocket not found userids:" + JsonConvert.root().convertTo(userids) + " on any node "); + return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); + } + Map> addrUsers = new HashMap<>(); + addrs.forEach((key, as) -> { + for (WebSocketAddress a : as) { + addrUsers.computeIfAbsent(a, k -> new ArrayList<>()).add(keyuser.get(key)); + } + }); + if (logger.isLoggable(Level.FINEST)) { + logger.finest("websocket(localaddr=" + localSncpAddress + ", userids=" + JsonConvert.root().convertTo(userids) + ") found message-addr-userids: " + addrUsers); + } + CompletableFuture future = null; + for (Map.Entry> en : addrUsers.entrySet()) { + Serializable[] oneaddrUserids = en.getValue().toArray(new Serializable[en.getValue().size()]); + future = future == null ? sendOneAddrMessage(en.getKey(), remoteMessage, last, oneaddrUserids) + : future.thenCombine(sendOneAddrMessage(en.getKey(), remoteMessage, last, oneaddrUserids), (a, b) -> a | b); + } + return future == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : future; + }); + } + return rsfuture == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : rsfuture; + } + + /** + * 鍚戞寚瀹氱敤鎴峰彂閫佹秷鎭紝鍏堝彂閫佹湰鍦拌繛鎺ワ紝鍐嶅彂閫佽繙绋嬭繛鎺
+ * 濡傛灉褰撳墠WebSocketNode鏄繙绋嬫ā寮忥紝姝ゆ柟娉曞彧鍙戦佽繙绋嬭繛鎺 + * + * @param convert Convert + * @param message0 娑堟伅鍐呭 + * @param last 鏄惁鏈鍚庝竴鏉 + * @param useraddrs WebSocketUserAddress[] + * + * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 + */ + @Local + public CompletableFuture sendMessage(final Convert convert, final Object message0, final boolean last, final WebSocketUserAddress... useraddrs) { + if (useraddrs == null || useraddrs.length < 1) return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); + if (message0 instanceof CompletableFuture) return ((CompletableFuture) message0).thenApply(msg -> sendMessage(convert, msg, last, useraddrs)); + final Object message = (convert == null || message0 instanceof WebSocketPacket) ? message0 : ((convert instanceof TextConvert) ? new WebSocketPacket(((TextConvert) convert).convertTo(message0), last) : new WebSocketPacket(((BinaryConvert) convert).convertTo(message0), last)); + if (this.localEngine != null && this.source == null) { //鏈湴妯″紡涓旀病鏈夊垎甯冨紡 + return this.localEngine.sendLocalMessage(message, last, userAddressToUserids(useraddrs)); + } + + final Object remoteMessage = formatRemoteMessage(message); + final Map> addrUsers = userAddressToAddrMap(useraddrs); + if (logger.isLoggable(Level.FINEST)) { + logger.finest("websocket(localaddr=" + localSncpAddress + ", useraddrs=" + JsonConvert.root().convertTo(useraddrs) + ") found message-addr-userids: " + addrUsers); + } + CompletableFuture future = null; + for (Map.Entry> en : addrUsers.entrySet()) { + Serializable[] oneaddrUserids = en.getValue().toArray(new Serializable[en.getValue().size()]); + future = future == null ? sendOneAddrMessage(en.getKey(), remoteMessage, last, oneaddrUserids) + : future.thenCombine(sendOneAddrMessage(en.getKey(), remoteMessage, last, oneaddrUserids), (a, b) -> a | b); + } + return future == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : future; + + } + + protected CompletableFuture sendOneUserMessage(final Object message, final boolean last, final Serializable userid) { + if (message instanceof CompletableFuture) return ((CompletableFuture) message).thenApply(msg -> sendOneUserMessage(msg, last, userid)); + if (logger.isLoggable(Level.FINEST)) { + logger.finest("websocket want send message {userid:" + userid + ", content:" + (message instanceof WebSocketPacket ? ((WebSocketPacket) message).toSimpleString() : (message instanceof CharSequence ? message : JsonConvert.root().convertTo(message))) + "} from locale node to " + ((this.localEngine != null) ? "locale" : "remote") + " engine"); + } + CompletableFuture localFuture = null; + if (this.localEngine != null) localFuture = localEngine.sendLocalMessage(message, last, userid); + if (this.source == null || this.remoteNode == null) { + if (logger.isLoggable(Level.FINEST)) logger.finest("websocket " + (this.remoteNode == null ? (this.source == null ? "remote and source" : "remote") : "source") + " node is null"); + //娌℃湁CacheSource灏变笉浼氭湁鍒嗗竷寮忚妭鐐 + return localFuture == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : localFuture; + } + //杩滅▼鑺傜偣鍙戦佹秷鎭 + final Object remoteMessage = formatRemoteMessage(message); + tryAcquireSemaphore(); + CompletableFuture> addrsFuture = source.getCollectionAsync(WS_SOURCE_KEY_USERID_PREFIX + userid, WebSocketAddress.class); + if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore()); + CompletableFuture remoteFuture = addrsFuture.thenCompose((Collection addrs) -> { + if (addrs == null || addrs.isEmpty()) { + if (logger.isLoggable(Level.FINER)) logger.finer("websocket not found userid:" + userid + " on any node "); + return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); + } + if (logger.isLoggable(Level.FINEST)) logger.finest("websocket(localaddr=" + wsNodeAddress + ") found userid:" + userid + " on " + addrs); + CompletableFuture future = null; + for (WebSocketAddress addr : addrs) { + if (addr == null || addr.equals(wsNodeAddress)) continue; + future = future == null ? remoteNode.sendMessage(addr.getTopic(), addr.getAddr(), remoteMessage, last, userid) + : future.thenCombine(remoteNode.sendMessage(addr.getTopic(), addr.getAddr(), remoteMessage, last, userid), (a, b) -> a | b); + } + return future == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : future; + }); + return localFuture == null ? remoteFuture : localFuture.thenCombine(remoteFuture, (a, b) -> a | b); + } + + protected CompletableFuture sendOneAddrMessage(final WebSocketAddress addr, final Object message, final boolean last, final Serializable... userids) { + if (message instanceof CompletableFuture) return ((CompletableFuture) message).thenApply(msg -> sendOneAddrMessage(addr, msg, last, userids)); + if (logger.isLoggable(Level.FINEST) && this.localEngine == null) { //鍙墦鍗拌繙绋嬫ā寮忕殑 + logger.finest("websocket want send message {userids:" + JsonConvert.root().convertTo(userids) + ", sncpaddr:" + addr + ", content:" + (message instanceof WebSocketPacket ? ((WebSocketPacket) message).toSimpleString() : (message instanceof CharSequence ? message : JsonConvert.root().convertTo(message))) + "} from locale node to " + ((this.localEngine != null) ? "locale" : "remote") + " engine"); + } + if (Objects.equals(addr, this.wsNodeAddress)) { + return this.localEngine == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : localEngine.sendLocalMessage(message, last, userids); + } + if (this.source == null || this.remoteNode == null) { + if (logger.isLoggable(Level.FINEST)) logger.finest("websocket " + (this.remoteNode == null ? (this.source == null ? "remote and source" : "remote") : "source") + " node is null"); + //娌℃湁CacheSource灏变笉浼氭湁鍒嗗竷寮忚妭鐐 + return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); + } + final Object remoteMessage = formatRemoteMessage(message); + return remoteNode.sendMessage(addr.getTopic(), addr.getAddr(), remoteMessage, last, userids); + } + + protected Serializable[] userAddressToUserids(WebSocketUserAddress... useraddrs) { + if (useraddrs == null || useraddrs.length == 1) return new Serializable[0]; + Set set = new HashSet<>(); + for (WebSocketUserAddress userAddress : useraddrs) { + set.add(userAddress.userid()); + } + return set.toArray(new Serializable[set.size()]); + } + + protected Map> userAddressToAddrMap(WebSocketUserAddress... useraddrs) { + final Map> addrUsers = new HashMap<>(); + for (WebSocketUserAddress userAddress : useraddrs) { + if (userAddress.address() != null) { + addrUsers.computeIfAbsent(userAddress.address(), k -> new ArrayList<>()).add(userAddress.userid()); + } + if (userAddress.addresses() != null) { + for (WebSocketAddress addr : userAddress.addresses()) { + if (addr != null) { + addrUsers.computeIfAbsent(addr, k -> new ArrayList<>()).add(userAddress.userid()); + } + } + } + } + return addrUsers; + } + + /** + * 骞挎挱娑堟伅锛 缁欐墍鏈変汉鍙戞秷鎭 + * + * @param message 娑堟伅鍐呭 + * + * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 + */ + @Local + public final CompletableFuture broadcastMessage(final Object message) { + return broadcastMessage((Convert) null, message, true); + } + + /** + * 骞挎挱娑堟伅锛 缁欐墍鏈変汉鍙戞秷鎭 + * + * @param wsrange 杩囨护鏉′欢 + * @param message 娑堟伅鍐呭 + * + * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 + */ + @Local + public final CompletableFuture broadcastMessage(final WebSocketRange wsrange, final Object message) { + return broadcastMessage(wsrange, (Convert) null, message, true); + } + + /** + * 骞挎挱娑堟伅锛 缁欐墍鏈変汉鍙戞秷鎭 + * + * @param convert Convert + * @param message 娑堟伅鍐呭 + * + * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 + */ + @Local + public final CompletableFuture broadcastMessage(final Convert convert, final Object message) { + return broadcastMessage(convert, message, true); + } + + /** + * 骞挎挱娑堟伅锛 缁欐墍鏈変汉鍙戞秷鎭 + * + * @param wsrange 杩囨护鏉′欢 + * @param convert Convert + * @param message 娑堟伅鍐呭 + * + * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 + */ + @Local + public final CompletableFuture broadcastMessage(final WebSocketRange wsrange, final Convert convert, final Object message) { + return broadcastMessage(wsrange, convert, message, true); + } + + /** + * 骞挎挱娑堟伅锛 缁欐墍鏈変汉鍙戞秷鎭 + * + * @param message 娑堟伅鍐呭 + * @param last 鏄惁鏈鍚庝竴鏉 + * + * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 + */ + @Local + public final CompletableFuture broadcastMessage(final Object message, final boolean last) { + return broadcastMessage((Convert) null, message, last); + } + + /** + * 骞挎挱娑堟伅锛 缁欐墍鏈変汉鍙戞秷鎭 + * + * @param wsrange 杩囨护鏉′欢 + * @param message 娑堟伅鍐呭 + * @param last 鏄惁鏈鍚庝竴鏉 + * + * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 + */ + @Local + public final CompletableFuture broadcastMessage(final WebSocketRange wsrange, final Object message, final boolean last) { + return broadcastMessage(wsrange, (Convert) null, message, last); + } + + /** + * 骞挎挱娑堟伅锛 缁欐墍鏈変汉鍙戞秷鎭 + * + * @param convert Convert + * @param message0 娑堟伅鍐呭 + * @param last 鏄惁鏈鍚庝竴鏉 + * + * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 + */ + @Local + public final CompletableFuture broadcastMessage(final Convert convert, final Object message0, final boolean last) { + return broadcastMessage((WebSocketRange) null, convert, message0, last); + } + + /** + * 骞挎挱娑堟伅锛 缁欐墍鏈変汉鍙戞秷鎭 + * + * @param wsrange 杩囨护鏉′欢 + * @param convert Convert + * @param message0 娑堟伅鍐呭 + * @param last 鏄惁鏈鍚庝竴鏉 + * + * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 + */ + @Local + public CompletableFuture broadcastMessage(final WebSocketRange wsrange, final Convert convert, final Object message0, final boolean last) { + if (message0 instanceof CompletableFuture) return ((CompletableFuture) message0).thenApply(msg -> broadcastMessage(wsrange, convert, msg, last)); + final Object message = (convert == null || message0 instanceof WebSocketPacket) ? message0 : ((convert instanceof TextConvert) ? new WebSocketPacket(((TextConvert) convert).convertTo(message0), last) : new WebSocketPacket(((BinaryConvert) convert).convertTo(message0), last)); + if (this.localEngine != null && this.source == null) { //鏈湴妯″紡涓旀病鏈夊垎甯冨紡 + return this.localEngine.broadcastLocalMessage(wsrange, message, last); + } + final Object remoteMessage = formatRemoteMessage(message); + CompletableFuture localFuture = this.localEngine == null ? null : this.localEngine.broadcastLocalMessage(wsrange, message, last); + tryAcquireSemaphore(); + CompletableFuture> addrsFuture = source.getCollectionAsync(WS_SOURCE_KEY_NODES, WebSocketAddress.class); + if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore()); + CompletableFuture remoteFuture = addrsFuture.thenCompose((Collection addrs) -> { + if (logger.isLoggable(Level.FINEST)) logger.finest("websocket broadcast message (" + remoteMessage + ") on " + addrs); + if (addrs == null || addrs.isEmpty()) return CompletableFuture.completedFuture(0); + CompletableFuture future = null; + for (WebSocketAddress addr : addrs) { + if (addr == null || addr.equals(wsNodeAddress)) continue; + future = future == null ? remoteNode.broadcastMessage(addr.getTopic(), addr.getAddr(), wsrange, remoteMessage, last) + : future.thenCombine(remoteNode.broadcastMessage(addr.getTopic(), addr.getAddr(), wsrange, remoteMessage, last), (a, b) -> a | b); + } + return future == null ? CompletableFuture.completedFuture(0) : future; + }); + return localFuture == null ? remoteFuture : localFuture.thenCombine(remoteFuture, (a, b) -> a | b); + } + + /** + * 骞挎挱鎿嶄綔锛 缁欐墍鏈変汉鍙戞搷浣 + * + * @param action 鎿嶄綔鍙傛暟 + * + * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 + */ + @Local + public CompletableFuture broadcastAction(final WebSocketAction action) { + if (this.localEngine != null && this.source == null) { //鏈湴妯″紡涓旀病鏈夊垎甯冨紡 + return this.localEngine.broadcastLocalAction(action); + } + CompletableFuture localFuture = this.localEngine == null ? null : this.localEngine.broadcastLocalAction(action); + tryAcquireSemaphore(); + CompletableFuture> addrsFuture = source.getCollectionAsync(WS_SOURCE_KEY_NODES, WebSocketAddress.class); + if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore()); + CompletableFuture remoteFuture = addrsFuture.thenCompose((Collection addrs) -> { + if (logger.isLoggable(Level.FINEST)) logger.finest("websocket broadcast action (" + action + ") on " + addrs); + if (addrs == null || addrs.isEmpty()) return CompletableFuture.completedFuture(0); + CompletableFuture future = null; + for (WebSocketAddress addr : addrs) { + if (addr == null || addr.equals(wsNodeAddress)) continue; + future = future == null ? remoteNode.broadcastAction(addr.getTopic(), addr.getAddr(), action) + : future.thenCombine(remoteNode.broadcastAction(addr.getTopic(), addr.getAddr(), action), (a, b) -> a | b); + } + return future == null ? CompletableFuture.completedFuture(0) : future; + }); + return localFuture == null ? remoteFuture : localFuture.thenCombine(remoteFuture, (a, b) -> a | b); + } + + /** + * 鍚戞寚瀹氱敤鎴峰彂閫佹搷浣滐紝鍏堝彂閫佹湰鍦拌繛鎺ワ紝鍐嶅彂閫佽繙绋嬭繛鎺
+ * 濡傛灉褰撳墠WebSocketNode鏄繙绋嬫ā寮忥紝姝ゆ柟娉曞彧鍙戦佽繙绋嬭繛鎺 + * + * @param action 鎿嶄綔鍙傛暟 + * @param userids Serializable[] + * + * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 + */ + @Local + public CompletableFuture sendAction(final WebSocketAction action, final Serializable... userids) { + if (userids == null || userids.length < 1) return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); + if (userids[0] instanceof WebSocketUserAddress) { + WebSocketUserAddress[] useraddrs = new WebSocketUserAddress[userids.length]; + for (int i = 0; i < useraddrs.length; i++) { + useraddrs[i] = (WebSocketUserAddress) userids[i]; + } + return sendAction(action, useraddrs); + } + if (this.localEngine != null && this.source == null) { //鏈湴妯″紡涓旀病鏈夊垎甯冨紡 + return this.localEngine.sendLocalAction(action, userids); + } + CompletableFuture rsfuture; + if (userids.length == 1) { + rsfuture = sendOneUserAction(action, userids[0]); + } else { + String[] keys = new String[userids.length]; + final Map keyuser = new HashMap<>(); + for (int i = 0; i < userids.length; i++) { + keys[i] = WS_SOURCE_KEY_USERID_PREFIX + userids[i]; + keyuser.put(keys[i], userids[i]); + } + tryAcquireSemaphore(); + CompletableFuture>> addrsFuture = source.getCollectionMapAsync(true, WebSocketAddress.class, keys); + if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore()); + rsfuture = addrsFuture.thenCompose((Map> addrs) -> { + if (addrs == null || addrs.isEmpty()) { + if (logger.isLoggable(Level.FINER)) logger.finer("websocket not found userids:" + JsonConvert.root().convertTo(userids) + " on any node "); + return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); + } + Map> addrUsers = new HashMap<>(); + addrs.forEach((key, as) -> { + for (WebSocketAddress a : as) { + addrUsers.computeIfAbsent(a, k -> new ArrayList<>()).add(keyuser.get(key)); + } + }); + if (logger.isLoggable(Level.FINEST)) { + logger.finest("websocket(localaddr=" + localSncpAddress + ", userids=" + JsonConvert.root().convertTo(userids) + ") found action-userid-addrs: " + addrUsers); + } + CompletableFuture future = null; + for (Map.Entry> en : addrUsers.entrySet()) { + Serializable[] oneaddrUserids = en.getValue().toArray(new Serializable[en.getValue().size()]); + future = future == null ? sendOneAddrAction(en.getKey(), action, oneaddrUserids) + : future.thenCombine(sendOneAddrAction(en.getKey(), action, oneaddrUserids), (a, b) -> a | b); + } + return future == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : future; + }); + } + return rsfuture == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : rsfuture; + } + + /** + * 鍚戞寚瀹氱敤鎴峰彂閫佹搷浣滐紝鍏堝彂閫佹湰鍦拌繛鎺ワ紝鍐嶅彂閫佽繙绋嬭繛鎺
+ * 濡傛灉褰撳墠WebSocketNode鏄繙绋嬫ā寮忥紝姝ゆ柟娉曞彧鍙戦佽繙绋嬭繛鎺 + * + * @param action 鎿嶄綔鍙傛暟 + * @param useraddrs WebSocketUserAddress[] + * + * @return 涓0琛ㄧず鎴愬姛锛 鍏朵粬鍊艰〃绀洪儴鍒嗗彂閫佸紓甯 + */ + @Local + public CompletableFuture sendAction(final WebSocketAction action, final WebSocketUserAddress... useraddrs) { + if (useraddrs == null || useraddrs.length < 1) return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); + if (this.localEngine != null && this.source == null) { //鏈湴妯″紡涓旀病鏈夊垎甯冨紡 + return this.localEngine.sendLocalAction(action, userAddressToUserids(useraddrs)); + } + + final Map> addrUsers = userAddressToAddrMap(useraddrs); + if (logger.isLoggable(Level.FINEST)) { + logger.finest("websocket(localaddr=" + localSncpAddress + ", useraddrs=" + JsonConvert.root().convertTo(useraddrs) + ") found action-userid-addrs: " + addrUsers); + } + CompletableFuture future = null; + for (Map.Entry> en : addrUsers.entrySet()) { + Serializable[] oneaddrUserids = en.getValue().toArray(new Serializable[en.getValue().size()]); + future = future == null ? sendOneAddrAction(en.getKey(), action, oneaddrUserids) + : future.thenCombine(sendOneAddrAction(en.getKey(), action, oneaddrUserids), (a, b) -> a | b); + } + return future == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : future; + } + + protected CompletableFuture sendOneUserAction(final WebSocketAction action, final Serializable userid) { + if (logger.isLoggable(Level.FINEST)) { + logger.finest("websocket want send action {userid:" + userid + ", action:" + action + "} from locale node to " + ((this.localEngine != null) ? "locale" : "remote") + " engine"); + } + CompletableFuture localFuture = null; + if (this.localEngine != null) localFuture = localEngine.sendLocalAction(action, userid); + if (this.source == null || this.remoteNode == null) { + if (logger.isLoggable(Level.FINEST)) logger.finest("websocket " + (this.remoteNode == null ? (this.source == null ? "remote and source" : "remote") : "source") + " node is null"); + //娌℃湁CacheSource灏变笉浼氭湁鍒嗗竷寮忚妭鐐 + return localFuture == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : localFuture; + } + //杩滅▼鑺傜偣鍙戦佹搷浣 + tryAcquireSemaphore(); + CompletableFuture> addrsFuture = source.getCollectionAsync(WS_SOURCE_KEY_USERID_PREFIX + userid, WebSocketAddress.class); + if (semaphore != null) addrsFuture.whenComplete((r, e) -> releaseSemaphore()); + CompletableFuture remoteFuture = addrsFuture.thenCompose((Collection addrs) -> { + if (addrs == null || addrs.isEmpty()) { + if (logger.isLoggable(Level.FINER)) logger.finer("websocket not found userid:" + userid + " on any node "); + return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); + } + if (logger.isLoggable(Level.FINEST)) logger.finest("websocket(localaddr=" + localSncpAddress + ") found userid:" + userid + " on " + addrs); + CompletableFuture future = null; + for (WebSocketAddress addr : addrs) { + if (addr == null || addr.equals(wsNodeAddress)) continue; + future = future == null ? remoteNode.sendAction(addr.getTopic(), addr.getAddr(), action, userid) + : future.thenCombine(remoteNode.sendAction(addr.getTopic(), addr.getAddr(), action, userid), (a, b) -> a | b); + } + return future == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : future; + }); + return localFuture == null ? remoteFuture : localFuture.thenCombine(remoteFuture, (a, b) -> a | b); + } + + protected CompletableFuture sendOneAddrAction(final WebSocketAddress addr, final WebSocketAction action, final Serializable... userids) { + if (logger.isLoggable(Level.FINEST) && this.localEngine == null) { //鍙墦鍗拌繙绋嬫ā寮忕殑 + logger.finest("websocket want send action {userids:" + JsonConvert.root().convertTo(userids) + ", sncpaddr:" + addr + ", action:" + action + " from locale node to " + ((this.localEngine != null) ? "locale" : "remote") + " engine"); + } + if (Objects.equals(addr, this.wsNodeAddress)) { + return this.localEngine == null ? CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY) : localEngine.sendLocalAction(action, userids); + } + if (this.source == null || this.remoteNode == null) { + if (logger.isLoggable(Level.FINEST)) logger.finest("websocket " + (this.remoteNode == null ? (this.source == null ? "remote and source" : "remote") : "source") + " node is null"); + //娌℃湁CacheSource灏变笉浼氭湁鍒嗗竷寮忚妭鐐 + return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); + } + return remoteNode.sendAction(addr.getTopic(), addr.getAddr(), action, userids); + } + + protected Object formatRemoteMessage(Object message) { + if (message instanceof WebSocketPacket) return message; + if (message instanceof byte[]) return message; + if (message instanceof CharSequence) return message; + if (sendConvert instanceof TextConvert) ((TextConvert) sendConvert).convertTo(message); + if (sendConvert instanceof BinaryConvert) ((BinaryConvert) sendConvert).convertTo(message); + return JsonConvert.root().convertTo(message); + } + + protected boolean tryAcquireSemaphore() { + if (this.semaphore == null) return true; + try { + return this.semaphore.tryAcquire(tryAcquireSeconds, TimeUnit.SECONDS); + } catch (Exception e) { + return false; + } + } + + protected void releaseSemaphore() { + if (this.semaphore != null) this.semaphore.release(); + } +} diff --git a/src/main/java/org/redkale/net/http/WebSocketPacket.java b/src/main/java/org/redkale/net/http/WebSocketPacket.java index 5b468eaba..4cc22bc0e 100644 --- a/src/main/java/org/redkale/net/http/WebSocketPacket.java +++ b/src/main/java/org/redkale/net/http/WebSocketPacket.java @@ -1,123 +1,123 @@ -/* - * 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 java.io.*; -import java.nio.charset.StandardCharsets; -import org.redkale.net.http.WebSocketPacket.FrameType; - -/** - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public final class WebSocketPacket { - - public static final Object MESSAGE_NIL = new Object(); - - static final WebSocketPacket NONE = new WebSocketPacket(); - - public static final WebSocketPacket DEFAULT_PING_PACKET = new WebSocketPacket(FrameType.PING, new byte[0]); - - public static enum MessageType { - STRING, BYTES, OBJECT; - } - - public static enum FrameType { - - SERIES(0x00), TEXT(0x01), BINARY(0x02), CLOSE(0x08), PING(0x09), PONG(0x0A); - - private final int value; - - private FrameType(int v) { - this.value = v; - } - - public int getValue() { - return value; - } - - public static FrameType valueOf(int v) { - switch (v) { - case 0x00: return SERIES; - case 0x01: return TEXT; - case 0x02: return BINARY; - case 0x08: return CLOSE; - case 0x09: return PING; - case 0x0A: return PONG; - default: return null; - } - } - } - - protected FrameType type; - - protected byte[] payload; - - protected boolean last = true; - - public WebSocketPacket() { - } - - public WebSocketPacket(FrameType type, byte[] data) { - this(type, data, true); - } - - public WebSocketPacket(FrameType type, byte[] data, boolean last) { - this.type = type; - this.payload = data; - this.last = last; - } - - public WebSocketPacket(Serializable message, boolean last) { - boolean bin = message != null && message.getClass() == byte[].class; - if (bin) { - this.type = FrameType.BINARY; - this.payload = (byte[]) message; - } else { - this.type = FrameType.TEXT; - this.payload = String.valueOf(message).getBytes(StandardCharsets.UTF_8); - } - this.last = last; - } - - public byte[] getPayload() { - return payload; - } - - public boolean isLast() { - return last; - } - - public FrameType getType() { - return type; - } - - public void setType(FrameType type) { - this.type = type; - } - - public void setPayload(byte[] payload) { - this.payload = payload; - } - - public void setLast(boolean last) { - this.last = last; - } - - public String toSimpleString() { - if (payload == null) return null; - return type == FrameType.TEXT ? new String(payload, StandardCharsets.UTF_8) : ("bytes(" + payload.length + ")"); - } - - @Override - public String toString() { - return this.getClass().getSimpleName() + "[type=" + type + ", last=" + last + ", payload=" + toSimpleString() + "]"; - } - -} +/* + * 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 java.io.*; +import java.nio.charset.StandardCharsets; +import org.redkale.net.http.WebSocketPacket.FrameType; + +/** + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public final class WebSocketPacket { + + public static final Object MESSAGE_NIL = new Object(); + + static final WebSocketPacket NONE = new WebSocketPacket(); + + public static final WebSocketPacket DEFAULT_PING_PACKET = new WebSocketPacket(FrameType.PING, new byte[0]); + + public static enum MessageType { + STRING, BYTES, OBJECT; + } + + public static enum FrameType { + + SERIES(0x00), TEXT(0x01), BINARY(0x02), CLOSE(0x08), PING(0x09), PONG(0x0A); + + private final int value; + + private FrameType(int v) { + this.value = v; + } + + public int getValue() { + return value; + } + + public static FrameType valueOf(int v) { + switch (v) { + case 0x00: return SERIES; + case 0x01: return TEXT; + case 0x02: return BINARY; + case 0x08: return CLOSE; + case 0x09: return PING; + case 0x0A: return PONG; + default: return null; + } + } + } + + protected FrameType type; + + protected byte[] payload; + + protected boolean last = true; + + public WebSocketPacket() { + } + + public WebSocketPacket(FrameType type, byte[] data) { + this(type, data, true); + } + + public WebSocketPacket(FrameType type, byte[] data, boolean last) { + this.type = type; + this.payload = data; + this.last = last; + } + + public WebSocketPacket(Serializable message, boolean last) { + boolean bin = message != null && message.getClass() == byte[].class; + if (bin) { + this.type = FrameType.BINARY; + this.payload = (byte[]) message; + } else { + this.type = FrameType.TEXT; + this.payload = String.valueOf(message).getBytes(StandardCharsets.UTF_8); + } + this.last = last; + } + + public byte[] getPayload() { + return payload; + } + + public boolean isLast() { + return last; + } + + public FrameType getType() { + return type; + } + + public void setType(FrameType type) { + this.type = type; + } + + public void setPayload(byte[] payload) { + this.payload = payload; + } + + public void setLast(boolean last) { + this.last = last; + } + + public String toSimpleString() { + if (payload == null) return null; + return type == FrameType.TEXT ? new String(payload, StandardCharsets.UTF_8) : ("bytes(" + payload.length + ")"); + } + + @Override + public String toString() { + return this.getClass().getSimpleName() + "[type=" + type + ", last=" + last + ", payload=" + toSimpleString() + "]"; + } + +} diff --git a/src/main/java/org/redkale/net/http/WebSocketParam.java b/src/main/java/org/redkale/net/http/WebSocketParam.java index d68db806b..6fdd99bc4 100644 --- a/src/main/java/org/redkale/net/http/WebSocketParam.java +++ b/src/main/java/org/redkale/net/http/WebSocketParam.java @@ -1,48 +1,48 @@ -/* - * 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 java.lang.annotation.Annotation; -import java.lang.reflect.Array; -import java.util.Arrays; - -/** - * - * 渚沇ebSocket.preOnMessage 鏂规硶鑾峰彇RestWebSocket閲孫nMessage鏂规硶鐨勫弬鏁
- *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public interface WebSocketParam { - - public T getValue(String name); - - public String[] getNames(); - - public Annotation[] getAnnotations(); - - default T getAnnotation(Class annotationClass) { - for (Annotation ann : getAnnotations()) { - if (ann.getClass() == annotationClass) return (T) ann; - } - return null; - } - - default T[] getAnnotationsByType(Class annotationClass) { - Annotation[] annotations = getAnnotations(); - if (annotations == null) return (T[]) Array.newInstance(annotationClass, 0); - T[] news = (T[]) Array.newInstance(annotationClass, annotations.length); - int index = 0; - for (Annotation ann : annotations) { - if (ann.getClass() == annotationClass) { - news[index++] = (T) ann; - } - } - if (index < 1) return (T[]) Array.newInstance(annotationClass, 0); - return Arrays.copyOf(news, index); - } -} +/* + * 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 java.lang.annotation.Annotation; +import java.lang.reflect.Array; +import java.util.Arrays; + +/** + * + * 渚沇ebSocket.preOnMessage 鏂规硶鑾峰彇RestWebSocket閲孫nMessage鏂规硶鐨勫弬鏁
+ *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public interface WebSocketParam { + + public T getValue(String name); + + public String[] getNames(); + + public Annotation[] getAnnotations(); + + default T getAnnotation(Class annotationClass) { + for (Annotation ann : getAnnotations()) { + if (ann.getClass() == annotationClass) return (T) ann; + } + return null; + } + + default T[] getAnnotationsByType(Class annotationClass) { + Annotation[] annotations = getAnnotations(); + if (annotations == null) return (T[]) Array.newInstance(annotationClass, 0); + T[] news = (T[]) Array.newInstance(annotationClass, annotations.length); + int index = 0; + for (Annotation ann : annotations) { + if (ann.getClass() == annotationClass) { + news[index++] = (T) ann; + } + } + if (index < 1) return (T[]) Array.newInstance(annotationClass, 0); + return Arrays.copyOf(news, index); + } +} diff --git a/src/main/java/org/redkale/net/http/WebSocketRange.java b/src/main/java/org/redkale/net/http/WebSocketRange.java index 558bc3fe3..70ab73147 100644 --- a/src/main/java/org/redkale/net/http/WebSocketRange.java +++ b/src/main/java/org/redkale/net/http/WebSocketRange.java @@ -1,70 +1,70 @@ -/* - * 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 java.io.Serializable; -import java.util.Map; -import org.redkale.convert.json.JsonConvert; - -/** - * WebSocket.broadcastMessage鏃剁殑杩囨护鏉′欢 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public class WebSocketRange implements Serializable { - - protected String wskey; - - protected Map attach; - - public WebSocketRange() { - } - - public WebSocketRange(String wskey) { - this.wskey = wskey; - } - - public WebSocketRange(String wskey, Map attach) { - this.wskey = wskey; - this.attach = attach; - } - - public boolean containsAttach(String key) { - return this.attach == null ? false : this.attach.containsKey(key); - } - - public String getAttach(String key) { - return this.attach == null ? null : this.attach.get(key); - } - - public String getAttach(String key, String defval) { - return this.attach == null ? defval : this.attach.getOrDefault(key, defval); - } - - public String getWskey() { - return wskey; - } - - public void setWskey(String wskey) { - this.wskey = wskey; - } - - public Map getAttach() { - return attach; - } - - public void setAttach(Map attach) { - this.attach = attach; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } -} +/* + * 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 java.io.Serializable; +import java.util.Map; +import org.redkale.convert.json.JsonConvert; + +/** + * WebSocket.broadcastMessage鏃剁殑杩囨护鏉′欢 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public class WebSocketRange implements Serializable { + + protected String wskey; + + protected Map attach; + + public WebSocketRange() { + } + + public WebSocketRange(String wskey) { + this.wskey = wskey; + } + + public WebSocketRange(String wskey, Map attach) { + this.wskey = wskey; + this.attach = attach; + } + + public boolean containsAttach(String key) { + return this.attach == null ? false : this.attach.containsKey(key); + } + + public String getAttach(String key) { + return this.attach == null ? null : this.attach.get(key); + } + + public String getAttach(String key, String defval) { + return this.attach == null ? defval : this.attach.getOrDefault(key, defval); + } + + public String getWskey() { + return wskey; + } + + public void setWskey(String wskey) { + this.wskey = wskey; + } + + public Map getAttach() { + return attach; + } + + public void setAttach(Map attach) { + this.attach = attach; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } +} diff --git a/src/main/java/org/redkale/net/http/WebSocketReadHandler.java b/src/main/java/org/redkale/net/http/WebSocketReadHandler.java index f6b9ea269..f400d3b2d 100644 --- a/src/main/java/org/redkale/net/http/WebSocketReadHandler.java +++ b/src/main/java/org/redkale/net/http/WebSocketReadHandler.java @@ -1,363 +1,363 @@ -/* - * 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 java.util.logging.*; -import java.nio.ByteBuffer; -import java.nio.channels.CompletionHandler; -import java.nio.charset.StandardCharsets; -import java.util.*; -import java.util.concurrent.CompletableFuture; -import java.util.function.BiConsumer; -import java.util.logging.Level; -import org.redkale.convert.Convert; -import static org.redkale.net.http.WebSocket.*; -import org.redkale.net.http.WebSocketPacket.FrameType; -import org.redkale.util.ByteArray; - -/** - * - * @author zhangjx - */ -public class WebSocketReadHandler implements CompletionHandler { - - protected final HttpContext context; - - protected final WebSocket webSocket; - - protected final BiConsumer restMessageConsumer; //涓昏渚汻estWebSocket浣跨敤 - - protected final Logger logger; - - protected final boolean debug; - - protected final List currPackets = new ArrayList<>(); - - protected ByteArray currSeriesMergeMessageBytes; - - protected FrameType currSeriesMergeMessageType; - - protected final ByteArray halfFrameBytes = new ByteArray(); - - protected byte halfFrameOpcode; - - protected byte halfFrameCrcode; - - protected byte[] halfFrameMasks; - - protected int halfFrameStart; - - protected int halfFrameLength = -1; - - public WebSocketReadHandler(HttpContext context, WebSocket webSocket, BiConsumer messageConsumer) { - this.context = context; - this.restMessageConsumer = messageConsumer; - this.webSocket = webSocket; - this.logger = context.getLogger(); - this.debug = context.getLogger().isLoggable(Level.FINEST); - } - - public void startRead() { - CompletableFuture connectFuture = webSocket.onConnected(); - if (connectFuture == null) { - webSocket._channel.read(this); - } else { - connectFuture.whenComplete((r, t) -> { - webSocket._channel.read(this); - }); - } - } - - /** - * 娑堟伅瑙g爜
- * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-------+-+-------------+-------------------------------+ - * |F|R|R|R| opcode|M| Payload len | Extended payload length | - * |I|S|S|S| (4) |A| (7) | (16/64) | - * |N|V|V|V| |S| | (if payload len==126/127) | - * | |1|2|3| |K| | | - * +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - + - * | Extended payload length continued, if payload len == 127 | - * + - - - - - - - - - - - - - - - +-------------------------------+ - * | |Masking-key, if MASK set to 1 | - * +-------------------------------+-------------------------------+ - * | Masking-key (continued) | Payload Data | - * +-------------------------------- - - - - - - - - - - - - - - - + - * : Payload Data continued : - * + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - * | Payload Data continued | - * +-----------------------------------------------------------------------+ - * - * @param realbuf ByteBuffer - * - */ - protected void readDecode(final ByteBuffer realbuf) { - if (debug && realbuf.remaining() > 6) logger.log(Level.FINEST, "read websocket message's length = " + realbuf.remaining()); - if (!realbuf.hasRemaining()) return; - ByteBuffer buffer = realbuf; - byte frameOpcode; - byte frameCrcode; - byte[] frameMasks; - int frameLength; - //System.out.println("realbuf璇诲埌鐨勯暱搴: " + realbuf.remaining() + ", halfFrameBytes=" + (halfFrameBytes == null ? -1 : halfFrameBytes.length())); - if (halfFrameBytes.length() > 0) { //瀛樺湪鍗婂寘 - int remain = realbuf.remaining(); - if (halfFrameLength == -1) { - int cha = 2 - halfFrameBytes.length(); - if (remain < cha) { //杩樻槸涓嶅2瀛楄妭 - halfFrameBytes.put(realbuf); - return; - } - final byte opcode0 = halfFrameBytes.get(0); //绗竴涓瓧鑺 - final byte crcode0 = halfFrameBytes.get(1); //绗簩涓瓧鑺 - byte lengthCode = crcode0; - final boolean masked = (lengthCode & 0x80) == 0x80; - if (masked) lengthCode ^= 0x80; //mask - int minLength = ((lengthCode <= 0x7D) ? 0 : (lengthCode == 0x7E ? 2 : 8)) + (masked ? 4 : 0); - cha = minLength + 2 - halfFrameBytes.length(); - if (remain < cha) { //杩樹笉澶熻鍙栭暱搴﹀煎拰mask - halfFrameBytes.put(realbuf); - return; - } - int length; - if (lengthCode <= 0x7D) { //125 闀垮害<=125 - length = lengthCode; - } else if (lengthCode == 0x7E) {//0x7E=126 闀垮害:126~65535 - length = (int) realbuf.getChar(); - } else if (lengthCode == 0x7F) {//0x7E=127 闀垮害>65535 - length = (int) realbuf.getLong(); - } else { - throw new RuntimeException("read webSocket packet lengthCode (" + (int) lengthCode + ") error"); - } - byte[] masks0 = null; - if (masked) { - masks0 = new byte[4]; - realbuf.get(masks0); - } - this.halfFrameOpcode = opcode0; - this.halfFrameCrcode = crcode0; - this.halfFrameMasks = masks0; - this.halfFrameStart = 2 + minLength; - this.halfFrameLength = length; - } - //姝ゆ椂蹇呯劧鏈塰alfFrameLength - int bulen = halfFrameLength + halfFrameStart - halfFrameBytes.length(); //杩樺樊澶氬皯瀛楄妭 - if (bulen > remain) { //涓嶅锛岀户缁鍙 - halfFrameBytes.put(realbuf); - return; - } - halfFrameBytes.put(realbuf, bulen); - //姝ゆ椂halfFrameBytes鏄畬鏁寸殑frame鏁版嵁 - buffer = ByteBuffer.wrap(halfFrameBytes.content(), halfFrameStart, halfFrameBytes.length()); - - frameOpcode = this.halfFrameOpcode; - frameCrcode = this.halfFrameCrcode; - frameMasks = this.halfFrameMasks; - frameLength = this.halfFrameLength; - - this.halfFrameBytes.clear(); - this.halfFrameLength = -1; - } else { //绗竴娆″氨鍙湁鍑犱釜瀛楄妭buffer - int remain = realbuf.remaining(); - if (remain < 2) { - this.halfFrameBytes.put(realbuf); - return; - } - final byte opcode0 = realbuf.get(); //绗竴涓瓧鑺 - final byte crcode0 = realbuf.get(); //绗簩涓瓧鑺 - byte lengthCode = crcode0; - final boolean masked = (lengthCode & 0x80) == 0x80; - if (masked) lengthCode ^= 0x80; //mask - int minLength = ((lengthCode <= 0x7D) ? 0 : (lengthCode == 0x7E ? 2 : 8)) + (masked ? 4 : 0); - if (remain < minLength + 2) { //杩樹笉澶熻鍙栭暱搴﹀ - this.halfFrameBytes.put(opcode0, crcode0); - this.halfFrameBytes.put(realbuf); - return; - } - int length; - if (lengthCode <= 0x7D) { //125 闀垮害<=125 - length = lengthCode; - } else if (lengthCode == 0x7E) {//0x7E=126 闀垮害:126~65535 - length = (int) realbuf.getChar(); - } else if (lengthCode == 0x7F) {//0x7E=127 闀垮害>65535 - length = (int) realbuf.getLong(); - } else { - throw new RuntimeException("read webSocket packet lengthCode (" + (int) lengthCode + ") error"); - } - byte[] masks0 = null; - if (masked) { - masks0 = new byte[4]; - realbuf.get(masks0); - } - int bulen = length + minLength + 2; //杩樺樊澶氬皯瀛楄妭 - if (bulen > remain) { //涓嶅锛岀户缁鍙 - this.halfFrameBytes.put(opcode0, crcode0); - if (lengthCode <= 0x7D) { //125 闀垮害<=125 - this.halfFrameBytes.put((byte) length); - } else if (lengthCode == 0x7E) {//0x7E=126 闀垮害:126~65535 - this.halfFrameBytes.putChar((char) length); - } else if (lengthCode == 0x7F) {//0x7E=127 闀垮害>65535 - this.halfFrameBytes.putLong((long) length); - } - if (masks0 != null) this.halfFrameBytes.put(masks0); - this.halfFrameBytes.put(realbuf); - this.halfFrameOpcode = opcode0; - this.halfFrameCrcode = crcode0; - this.halfFrameMasks = masks0; - this.halfFrameStart = 2 + minLength; - this.halfFrameLength = length; - return; - } - frameOpcode = opcode0; - frameCrcode = crcode0; - frameMasks = masks0; - frameLength = length; - } - - final boolean last = (frameOpcode & 0B1000_0000) != 0; - final FrameType type = FrameType.valueOf(frameOpcode & 0B0000_1111); - //0x00 琛ㄧず涓涓悗缁抚 - //0x01 琛ㄧず涓涓枃鏈抚 - //0x02 琛ㄧず涓涓簩杩涘埗甯 - //0x03-07 涓轰互鍚庣殑闈炴帶鍒跺抚淇濈暀 - //0x8 琛ㄧず涓涓繛鎺ュ叧闂 - //0x9 琛ㄧず涓涓猵ing - //0xA 琛ㄧず涓涓猵ong - //0x0B-0F 涓轰互鍚庣殑鎺у埗甯т繚鐣 - final boolean control = (frameOpcode & 0B0000_1000) != 0; //鏄惁鎺у埗甯 - // this.receiveCompress = !control && webSocket.inflater != null && (opcode & 0B0100_0000) != 0; //rsv1 涓 1 - - if (type == FrameType.CLOSE) { - if (debug) logger.log(Level.FINEST, " receive close command from websocket client"); - } - if (type == null) { - logger.log(Level.SEVERE, " receive unknown frametype(opcode=" + (frameOpcode & 0B0000_1111) + ") from websocket client"); - } - final boolean checkrsv = false;//鏆傛椂涓嶆牎楠 - if (checkrsv && (frameOpcode & 0B0111_0000) != 0) { - if (debug) logger.log(Level.FINE, "rsv1 rsv2 rsv3 must be 0, but not (" + frameOpcode + ")"); - return; //rsv1 rsv2 rsv3 must be 0 - } - byte[] content = new byte[frameLength]; - if (frameLength > 0) { - buffer.get(content); - int mi = 0; - if (frameMasks != null) { - for (int i = 0; i < content.length; i++) { - content[i] = (byte) (content[i] ^ frameMasks[mi++ % 4]); - } - } - } - if (!last && (type == FrameType.TEXT || type == FrameType.BINARY)) { - this.currSeriesMergeMessageBytes = new ByteArray(); - this.currSeriesMergeMessageBytes.put(content); - this.currSeriesMergeMessageType = type; - } else if (type == FrameType.SERIES) { - this.currSeriesMergeMessageBytes.put(content); - } else if (last && this.currSeriesMergeMessageBytes != null) { - this.currSeriesMergeMessageBytes.put(content); - byte[] bs = this.currSeriesMergeMessageBytes.getBytes(); - FrameType t = this.currSeriesMergeMessageType; - this.currSeriesMergeMessageBytes = null; - this.currSeriesMergeMessageType = null; - currPackets.add(new WebSocketPacket(t, bs, last)); - } else { - currPackets.add(new WebSocketPacket(type, content, last)); - } - buffer = realbuf; - while (buffer.hasRemaining()) { - readDecode(realbuf); - } - } - - @Override - public void completed(Integer count, ByteBuffer readBuffer) { - if (count < 1) { - if (debug) logger.log(Level.FINEST, "WebSocket(" + webSocket + ") abort on read buffer count, force to close channel, live " + (System.currentTimeMillis() - webSocket.getCreatetime()) / 1000 + " seconds"); - webSocket.kill(CLOSECODE_ILLPACKET, "read buffer count is " + count); - return; - } - try { - webSocket.lastReadTime = System.currentTimeMillis(); - currPackets.clear(); - - readBuffer.flip(); - readDecode(readBuffer); - readBuffer.clear(); - webSocket._channel.setReadBuffer(readBuffer); - try { - //娑堟伅澶勭悊 - for (final WebSocketPacket packet : currPackets) { - if (packet.type == FrameType.TEXT) { - try { - Convert convert = webSocket.getTextConvert(); - if (restMessageConsumer != null) { //涓昏渚汻estWebSocket浣跨敤 - restMessageConsumer.accept(webSocket, convert.convertFrom(webSocket._messageTextType, packet.getPayload())); - } else { - webSocket.onMessage(packet.getPayload() == null ? null : new String(packet.getPayload(), StandardCharsets.UTF_8), packet.last); - } - } catch (Throwable e) { - logger.log(Level.SEVERE, "WebSocket onTextMessage error (" + packet + ")", e); - } - } else if (packet.type == FrameType.BINARY) { - try { - Convert convert = webSocket.getBinaryConvert(); - if (restMessageConsumer != null) { //涓昏渚汻estWebSocket浣跨敤 - restMessageConsumer.accept(webSocket, convert.convertFrom(webSocket._messageTextType, packet.getPayload())); - } else { - webSocket.onMessage(packet.getPayload(), packet.last); - } - } catch (Throwable e) { - logger.log(Level.SEVERE, "WebSocket onBinaryMessage error (" + packet + ")", e); - } - } else if (packet.type == FrameType.PING) { - try { - webSocket.onPing(packet.getPayload()); - } catch (Exception e) { - logger.log(Level.SEVERE, "WebSocket onPing error (" + packet + ")", e); - } - } else if (packet.type == FrameType.PONG) { - try { - //if (debug) logger.log(Level.FINEST, "WebSocket onMessage by PONG FrameType : " + packet); - webSocket.onPong(packet.getPayload()); - } catch (Exception e) { - logger.log(Level.SEVERE, "WebSocket(" + webSocket + ") onPong error (" + packet + ")", e); - } - } else if (packet.type == FrameType.CLOSE) { - webSocket.initiateClosed = true; - if (debug) logger.log(Level.FINEST, "WebSocket(" + webSocket + ") onMessage by CLOSE FrameType : " + packet); - webSocket.kill(CLOSECODE_CLIENTCLOSE, "received CLOSE frame-type message"); - return; - } else { - logger.log(Level.WARNING, "WebSocket(" + webSocket + ") onMessage by unknown FrameType : " + packet); - webSocket.kill(CLOSECODE_ILLPACKET, "received unknown frame-type message"); - return; - } - } - } catch (Throwable t) { - logger.log(Level.WARNING, "WebSocket(" + webSocket + ") onMessage error", t); - } - webSocket._channel.read(this); - } catch (Exception e) { - logger.log(Level.WARNING, "WebSocket(" + webSocket + ") onMessage by received error", e); - webSocket.kill(CLOSECODE_WSEXCEPTION, "websocket-received error"); - } - } - - @Override - public void failed(Throwable exc, ByteBuffer attachment2) { - if (webSocket.initiateClosed) return; - if (exc != null) { - if (debug) context.getLogger().log(Level.FINEST, "WebSocket(" + webSocket + ") read WebSocketPacket failed, force to close channel, live " + (System.currentTimeMillis() - webSocket.getCreatetime()) / 1000 + " seconds", exc); - webSocket.kill(CLOSECODE_WSEXCEPTION, "read websocket-packet failed"); - } else { - webSocket.kill(CLOSECODE_WSEXCEPTION, "decode websocket-packet error"); - } - } - -} +/* + * 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 java.util.logging.*; +import java.nio.ByteBuffer; +import java.nio.channels.CompletionHandler; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.function.BiConsumer; +import java.util.logging.Level; +import org.redkale.convert.Convert; +import static org.redkale.net.http.WebSocket.*; +import org.redkale.net.http.WebSocketPacket.FrameType; +import org.redkale.util.ByteArray; + +/** + * + * @author zhangjx + */ +public class WebSocketReadHandler implements CompletionHandler { + + protected final HttpContext context; + + protected final WebSocket webSocket; + + protected final BiConsumer restMessageConsumer; //涓昏渚汻estWebSocket浣跨敤 + + protected final Logger logger; + + protected final boolean debug; + + protected final List currPackets = new ArrayList<>(); + + protected ByteArray currSeriesMergeMessageBytes; + + protected FrameType currSeriesMergeMessageType; + + protected final ByteArray halfFrameBytes = new ByteArray(); + + protected byte halfFrameOpcode; + + protected byte halfFrameCrcode; + + protected byte[] halfFrameMasks; + + protected int halfFrameStart; + + protected int halfFrameLength = -1; + + public WebSocketReadHandler(HttpContext context, WebSocket webSocket, BiConsumer messageConsumer) { + this.context = context; + this.restMessageConsumer = messageConsumer; + this.webSocket = webSocket; + this.logger = context.getLogger(); + this.debug = context.getLogger().isLoggable(Level.FINEST); + } + + public void startRead() { + CompletableFuture connectFuture = webSocket.onConnected(); + if (connectFuture == null) { + webSocket._channel.read(this); + } else { + connectFuture.whenComplete((r, t) -> { + webSocket._channel.read(this); + }); + } + } + + /** + * 娑堟伅瑙g爜
+ * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-------+-+-------------+-------------------------------+ + * |F|R|R|R| opcode|M| Payload len | Extended payload length | + * |I|S|S|S| (4) |A| (7) | (16/64) | + * |N|V|V|V| |S| | (if payload len==126/127) | + * | |1|2|3| |K| | | + * +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - + + * | Extended payload length continued, if payload len == 127 | + * + - - - - - - - - - - - - - - - +-------------------------------+ + * | |Masking-key, if MASK set to 1 | + * +-------------------------------+-------------------------------+ + * | Masking-key (continued) | Payload Data | + * +-------------------------------- - - - - - - - - - - - - - - - + + * : Payload Data continued : + * + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + * | Payload Data continued | + * +-----------------------------------------------------------------------+ + * + * @param realbuf ByteBuffer + * + */ + protected void readDecode(final ByteBuffer realbuf) { + if (debug && realbuf.remaining() > 6) logger.log(Level.FINEST, "read websocket message's length = " + realbuf.remaining()); + if (!realbuf.hasRemaining()) return; + ByteBuffer buffer = realbuf; + byte frameOpcode; + byte frameCrcode; + byte[] frameMasks; + int frameLength; + //System.out.println("realbuf璇诲埌鐨勯暱搴: " + realbuf.remaining() + ", halfFrameBytes=" + (halfFrameBytes == null ? -1 : halfFrameBytes.length())); + if (halfFrameBytes.length() > 0) { //瀛樺湪鍗婂寘 + int remain = realbuf.remaining(); + if (halfFrameLength == -1) { + int cha = 2 - halfFrameBytes.length(); + if (remain < cha) { //杩樻槸涓嶅2瀛楄妭 + halfFrameBytes.put(realbuf); + return; + } + final byte opcode0 = halfFrameBytes.get(0); //绗竴涓瓧鑺 + final byte crcode0 = halfFrameBytes.get(1); //绗簩涓瓧鑺 + byte lengthCode = crcode0; + final boolean masked = (lengthCode & 0x80) == 0x80; + if (masked) lengthCode ^= 0x80; //mask + int minLength = ((lengthCode <= 0x7D) ? 0 : (lengthCode == 0x7E ? 2 : 8)) + (masked ? 4 : 0); + cha = minLength + 2 - halfFrameBytes.length(); + if (remain < cha) { //杩樹笉澶熻鍙栭暱搴﹀煎拰mask + halfFrameBytes.put(realbuf); + return; + } + int length; + if (lengthCode <= 0x7D) { //125 闀垮害<=125 + length = lengthCode; + } else if (lengthCode == 0x7E) {//0x7E=126 闀垮害:126~65535 + length = (int) realbuf.getChar(); + } else if (lengthCode == 0x7F) {//0x7E=127 闀垮害>65535 + length = (int) realbuf.getLong(); + } else { + throw new RuntimeException("read webSocket packet lengthCode (" + (int) lengthCode + ") error"); + } + byte[] masks0 = null; + if (masked) { + masks0 = new byte[4]; + realbuf.get(masks0); + } + this.halfFrameOpcode = opcode0; + this.halfFrameCrcode = crcode0; + this.halfFrameMasks = masks0; + this.halfFrameStart = 2 + minLength; + this.halfFrameLength = length; + } + //姝ゆ椂蹇呯劧鏈塰alfFrameLength + int bulen = halfFrameLength + halfFrameStart - halfFrameBytes.length(); //杩樺樊澶氬皯瀛楄妭 + if (bulen > remain) { //涓嶅锛岀户缁鍙 + halfFrameBytes.put(realbuf); + return; + } + halfFrameBytes.put(realbuf, bulen); + //姝ゆ椂halfFrameBytes鏄畬鏁寸殑frame鏁版嵁 + buffer = ByteBuffer.wrap(halfFrameBytes.content(), halfFrameStart, halfFrameBytes.length()); + + frameOpcode = this.halfFrameOpcode; + frameCrcode = this.halfFrameCrcode; + frameMasks = this.halfFrameMasks; + frameLength = this.halfFrameLength; + + this.halfFrameBytes.clear(); + this.halfFrameLength = -1; + } else { //绗竴娆″氨鍙湁鍑犱釜瀛楄妭buffer + int remain = realbuf.remaining(); + if (remain < 2) { + this.halfFrameBytes.put(realbuf); + return; + } + final byte opcode0 = realbuf.get(); //绗竴涓瓧鑺 + final byte crcode0 = realbuf.get(); //绗簩涓瓧鑺 + byte lengthCode = crcode0; + final boolean masked = (lengthCode & 0x80) == 0x80; + if (masked) lengthCode ^= 0x80; //mask + int minLength = ((lengthCode <= 0x7D) ? 0 : (lengthCode == 0x7E ? 2 : 8)) + (masked ? 4 : 0); + if (remain < minLength + 2) { //杩樹笉澶熻鍙栭暱搴﹀ + this.halfFrameBytes.put(opcode0, crcode0); + this.halfFrameBytes.put(realbuf); + return; + } + int length; + if (lengthCode <= 0x7D) { //125 闀垮害<=125 + length = lengthCode; + } else if (lengthCode == 0x7E) {//0x7E=126 闀垮害:126~65535 + length = (int) realbuf.getChar(); + } else if (lengthCode == 0x7F) {//0x7E=127 闀垮害>65535 + length = (int) realbuf.getLong(); + } else { + throw new RuntimeException("read webSocket packet lengthCode (" + (int) lengthCode + ") error"); + } + byte[] masks0 = null; + if (masked) { + masks0 = new byte[4]; + realbuf.get(masks0); + } + int bulen = length + minLength + 2; //杩樺樊澶氬皯瀛楄妭 + if (bulen > remain) { //涓嶅锛岀户缁鍙 + this.halfFrameBytes.put(opcode0, crcode0); + if (lengthCode <= 0x7D) { //125 闀垮害<=125 + this.halfFrameBytes.put((byte) length); + } else if (lengthCode == 0x7E) {//0x7E=126 闀垮害:126~65535 + this.halfFrameBytes.putChar((char) length); + } else if (lengthCode == 0x7F) {//0x7E=127 闀垮害>65535 + this.halfFrameBytes.putLong((long) length); + } + if (masks0 != null) this.halfFrameBytes.put(masks0); + this.halfFrameBytes.put(realbuf); + this.halfFrameOpcode = opcode0; + this.halfFrameCrcode = crcode0; + this.halfFrameMasks = masks0; + this.halfFrameStart = 2 + minLength; + this.halfFrameLength = length; + return; + } + frameOpcode = opcode0; + frameCrcode = crcode0; + frameMasks = masks0; + frameLength = length; + } + + final boolean last = (frameOpcode & 0B1000_0000) != 0; + final FrameType type = FrameType.valueOf(frameOpcode & 0B0000_1111); + //0x00 琛ㄧず涓涓悗缁抚 + //0x01 琛ㄧず涓涓枃鏈抚 + //0x02 琛ㄧず涓涓簩杩涘埗甯 + //0x03-07 涓轰互鍚庣殑闈炴帶鍒跺抚淇濈暀 + //0x8 琛ㄧず涓涓繛鎺ュ叧闂 + //0x9 琛ㄧず涓涓猵ing + //0xA 琛ㄧず涓涓猵ong + //0x0B-0F 涓轰互鍚庣殑鎺у埗甯т繚鐣 + final boolean control = (frameOpcode & 0B0000_1000) != 0; //鏄惁鎺у埗甯 + // this.receiveCompress = !control && webSocket.inflater != null && (opcode & 0B0100_0000) != 0; //rsv1 涓 1 + + if (type == FrameType.CLOSE) { + if (debug) logger.log(Level.FINEST, " receive close command from websocket client"); + } + if (type == null) { + logger.log(Level.SEVERE, " receive unknown frametype(opcode=" + (frameOpcode & 0B0000_1111) + ") from websocket client"); + } + final boolean checkrsv = false;//鏆傛椂涓嶆牎楠 + if (checkrsv && (frameOpcode & 0B0111_0000) != 0) { + if (debug) logger.log(Level.FINE, "rsv1 rsv2 rsv3 must be 0, but not (" + frameOpcode + ")"); + return; //rsv1 rsv2 rsv3 must be 0 + } + byte[] content = new byte[frameLength]; + if (frameLength > 0) { + buffer.get(content); + int mi = 0; + if (frameMasks != null) { + for (int i = 0; i < content.length; i++) { + content[i] = (byte) (content[i] ^ frameMasks[mi++ % 4]); + } + } + } + if (!last && (type == FrameType.TEXT || type == FrameType.BINARY)) { + this.currSeriesMergeMessageBytes = new ByteArray(); + this.currSeriesMergeMessageBytes.put(content); + this.currSeriesMergeMessageType = type; + } else if (type == FrameType.SERIES) { + this.currSeriesMergeMessageBytes.put(content); + } else if (last && this.currSeriesMergeMessageBytes != null) { + this.currSeriesMergeMessageBytes.put(content); + byte[] bs = this.currSeriesMergeMessageBytes.getBytes(); + FrameType t = this.currSeriesMergeMessageType; + this.currSeriesMergeMessageBytes = null; + this.currSeriesMergeMessageType = null; + currPackets.add(new WebSocketPacket(t, bs, last)); + } else { + currPackets.add(new WebSocketPacket(type, content, last)); + } + buffer = realbuf; + while (buffer.hasRemaining()) { + readDecode(realbuf); + } + } + + @Override + public void completed(Integer count, ByteBuffer readBuffer) { + if (count < 1) { + if (debug) logger.log(Level.FINEST, "WebSocket(" + webSocket + ") abort on read buffer count, force to close channel, live " + (System.currentTimeMillis() - webSocket.getCreatetime()) / 1000 + " seconds"); + webSocket.kill(CLOSECODE_ILLPACKET, "read buffer count is " + count); + return; + } + try { + webSocket.lastReadTime = System.currentTimeMillis(); + currPackets.clear(); + + readBuffer.flip(); + readDecode(readBuffer); + readBuffer.clear(); + webSocket._channel.setReadBuffer(readBuffer); + try { + //娑堟伅澶勭悊 + for (final WebSocketPacket packet : currPackets) { + if (packet.type == FrameType.TEXT) { + try { + Convert convert = webSocket.getTextConvert(); + if (restMessageConsumer != null) { //涓昏渚汻estWebSocket浣跨敤 + restMessageConsumer.accept(webSocket, convert.convertFrom(webSocket._messageTextType, packet.getPayload())); + } else { + webSocket.onMessage(packet.getPayload() == null ? null : new String(packet.getPayload(), StandardCharsets.UTF_8), packet.last); + } + } catch (Throwable e) { + logger.log(Level.SEVERE, "WebSocket onTextMessage error (" + packet + ")", e); + } + } else if (packet.type == FrameType.BINARY) { + try { + Convert convert = webSocket.getBinaryConvert(); + if (restMessageConsumer != null) { //涓昏渚汻estWebSocket浣跨敤 + restMessageConsumer.accept(webSocket, convert.convertFrom(webSocket._messageTextType, packet.getPayload())); + } else { + webSocket.onMessage(packet.getPayload(), packet.last); + } + } catch (Throwable e) { + logger.log(Level.SEVERE, "WebSocket onBinaryMessage error (" + packet + ")", e); + } + } else if (packet.type == FrameType.PING) { + try { + webSocket.onPing(packet.getPayload()); + } catch (Exception e) { + logger.log(Level.SEVERE, "WebSocket onPing error (" + packet + ")", e); + } + } else if (packet.type == FrameType.PONG) { + try { + //if (debug) logger.log(Level.FINEST, "WebSocket onMessage by PONG FrameType : " + packet); + webSocket.onPong(packet.getPayload()); + } catch (Exception e) { + logger.log(Level.SEVERE, "WebSocket(" + webSocket + ") onPong error (" + packet + ")", e); + } + } else if (packet.type == FrameType.CLOSE) { + webSocket.initiateClosed = true; + if (debug) logger.log(Level.FINEST, "WebSocket(" + webSocket + ") onMessage by CLOSE FrameType : " + packet); + webSocket.kill(CLOSECODE_CLIENTCLOSE, "received CLOSE frame-type message"); + return; + } else { + logger.log(Level.WARNING, "WebSocket(" + webSocket + ") onMessage by unknown FrameType : " + packet); + webSocket.kill(CLOSECODE_ILLPACKET, "received unknown frame-type message"); + return; + } + } + } catch (Throwable t) { + logger.log(Level.WARNING, "WebSocket(" + webSocket + ") onMessage error", t); + } + webSocket._channel.read(this); + } catch (Exception e) { + logger.log(Level.WARNING, "WebSocket(" + webSocket + ") onMessage by received error", e); + webSocket.kill(CLOSECODE_WSEXCEPTION, "websocket-received error"); + } + } + + @Override + public void failed(Throwable exc, ByteBuffer attachment2) { + if (webSocket.initiateClosed) return; + if (exc != null) { + if (debug) context.getLogger().log(Level.FINEST, "WebSocket(" + webSocket + ") read WebSocketPacket failed, force to close channel, live " + (System.currentTimeMillis() - webSocket.getCreatetime()) / 1000 + " seconds", exc); + webSocket.kill(CLOSECODE_WSEXCEPTION, "read websocket-packet failed"); + } else { + webSocket.kill(CLOSECODE_WSEXCEPTION, "decode websocket-packet error"); + } + } + +} diff --git a/src/main/java/org/redkale/net/http/WebSocketServlet.java b/src/main/java/org/redkale/net/http/WebSocketServlet.java index 601554351..6b8b718b7 100644 --- a/src/main/java/org/redkale/net/http/WebSocketServlet.java +++ b/src/main/java/org/redkale/net/http/WebSocketServlet.java @@ -1,387 +1,387 @@ -/* - * 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 java.io.*; -import java.lang.reflect.*; -import java.net.*; -import java.nio.*; -import java.nio.channels.CompletionHandler; -import java.security.*; -import java.util.*; -import java.util.concurrent.CompletableFuture; -import java.util.function.*; -import java.util.logging.*; -import java.util.zip.*; -import javax.annotation.*; -import org.redkale.boot.Application; -import org.redkale.convert.Convert; -import org.redkale.mq.MessageAgent; -import org.redkale.net.Cryptor; -import org.redkale.service.*; -import org.redkale.util.*; - -/** - *

- * 褰揥ebSocketServlet鎺ユ敹涓涓猅CP杩炴帴鍚庯紝杩涜鍗忚鍒ゆ柇锛屽鏋滄垚鍔熷氨浼氬垱寤轰竴涓猈ebSocket銆
- *
- *                                    WebSocketServlet
- *                                            |
- *                                            |
- *                                   WebSocketEngine
- *                                    WebSocketNode
- *                                   /             \
- *                                 /                \
- *                               /                   \
- *                     WebSocket1                 WebSocket2
- *
- * 
- * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public abstract class WebSocketServlet extends HttpServlet implements Resourcable { - - @Comment("WebScoket鏈嶅姟鍣ㄧ粰瀹㈡埛绔繘琛宲ing鎿嶄綔鐨勯棿闅旀椂闂, 鍗曚綅: 绉") - public static final String WEBPARAM__LIVEINTERVAL = "liveinterval"; - - @Comment("WebScoket鏈嶅姟鍣ㄦ渶澶ц繛鎺ユ暟锛屼负0琛ㄧず鏃犻檺鍒") - public static final String WEBPARAM__WSMAXCONNS = "wsmaxconns"; - - @Comment("WebScoket鏈嶅姟鍣ㄦ搷浣淲ebSocketNode瀵瑰簲CacheSource骞跺彂鏁, 涓-1琛ㄧず鏃犻檺鍒讹紝涓0琛ㄧず绯荤粺榛樿鍊(CPU*8)") - public static final String WEBPARAM__WSTHREADS = "wsthreads"; - - @Comment("鏈澶ф秷鎭綋闀垮害, 灏忎簬1琛ㄧず鏃犻檺鍒") - public static final String WEBPARAM__WSMAXBODY = "wsmaxbody"; - - @Comment("鎺ユ敹瀹㈡埛绔殑鍒嗗寘(last=false)娑堟伅鏃舵槸鍚﹁嚜鍔ㄥ悎骞跺寘") - public static final String WEBPARAM__WSMERGEMSG = "wsmergemsg"; - - @Comment("鍔犲瘑瑙e瘑鍣") - public static final String WEBPARAM__CRYPTOR = "cryptor"; - - @Comment("WebScoket鏈嶅姟鍣ㄧ粰瀹㈡埛绔繘琛宲ing鎿嶄綔鐨勯粯璁ら棿闅旀椂闂, 鍗曚綅: 绉") - public static final int DEFAILT_LIVEINTERVAL = 15; - - protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); - - private final MessageDigest digest = getMessageDigest(); - - private final BiConsumer restMessageConsumer = createRestOnMessageConsumer(); - - protected Type messageTextType; //RestWebSocket鏃朵細琚慨鏀 - - //鍚孯estWebSocket.single - protected boolean single = true; //鏄惁鍗曠敤鎴峰崟杩炴帴 - - //鍚孯estWebSocket.liveinterval - protected int liveinterval = DEFAILT_LIVEINTERVAL; - - //鍚孯estWebSocket.wsmaxconns - protected int wsmaxconns = 0; - - //鍚孯estWebSocket.wsthreads - protected int wsthreads = 0; - - //鍚孯estWebSocket.wsmaxbody - protected int wsmaxbody = 32 * 1024; - - //鍚孯estWebSocket.anyuser - protected boolean anyuser = false; - - //鍚孯estWebSocket.mergemsg - protected boolean mergemsg = true; - - //鍚孯estWebSocket.cryptor, 鍙橀噺鍚嶄笉鍙敼锛 琚玆est.createRestWebSocketServlet鐢ㄥ埌 - protected Cryptor cryptor; - - protected boolean permessageDeflate = false; - - protected MessageAgent messageAgent; - - @Resource(name = "jsonconvert") - protected Convert jsonConvert; - - @Resource(name = "$_textconvert") - protected Convert textConvert; - - @Resource(name = "$_binaryconvert") - protected Convert binaryConvert; - - @Resource(name = "$_sendconvert") - protected Convert sendConvert; - - @Resource(name = "$") - protected WebSocketNode node; - - @Resource(name = "SERVER_RESFACTORY") - protected ResourceFactory resourceFactory; - - protected WebSocketServlet() { - Type msgtype = String.class; - try { - for (Method method : this.getClass().getDeclaredMethods()) { - if (!method.getName().equals("createWebSocket")) continue; - if (method.getParameterCount() > 0) continue; - Type rt = TypeToken.getGenericType(method.getGenericReturnType(), this.getClass()); - if (rt instanceof ParameterizedType) { - msgtype = ((ParameterizedType) rt).getActualTypeArguments()[1]; - } - if (msgtype == Object.class) msgtype = String.class; - break; - } - } catch (Exception e) { - logger.warning(this.getClass().getName() + " not designate text message type on createWebSocket Method"); - } - this.messageTextType = msgtype; - } - - @Override - final void preInit(Application application, HttpContext context, AnyValue conf) { - if (this.textConvert == null) this.textConvert = jsonConvert; - if (this.sendConvert == null) this.sendConvert = jsonConvert; - InetSocketAddress addr = context.getServerAddress(); - if (this.node == null) this.node = createWebSocketNode(); - if (this.node == null) { //娌℃湁閮ㄧ讲SNCP锛屽嵆涓嶆槸鍒嗗竷寮 - this.node = new WebSocketNodeService(); - if (logger.isLoggable(Level.WARNING)) logger.warning("Not found WebSocketNode, create a default value for " + getClass().getName()); - } - if (this.node.sendConvert == null) this.node.sendConvert = this.sendConvert; - if (this.messageAgent != null) this.node.messageAgent = this.messageAgent; - { - AnyValue props = conf; - if (conf != null && conf.getAnyValue("properties") != null) props = conf.getAnyValue("properties"); - if (props != null) { - String cryptorClass = props.getValue(WEBPARAM__CRYPTOR); - if (cryptorClass != null && !cryptorClass.isEmpty()) { - try { - Class clazz = Thread.currentThread().getContextClassLoader().loadClass(cryptorClass); - this.cryptor = (Cryptor) clazz.getDeclaredConstructor().newInstance(); - RedkaleClassLoader.putReflectionDeclaredConstructors(clazz, cryptorClass); - if (resourceFactory != null && this.cryptor != null) resourceFactory.inject(this.cryptor); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - } - } - if (application != null && application.isCompileMode()) return; - //瀛樺湪WebSocketServlet锛屽垯姝ebSocketNode蹇呴』鏄湰鍦版ā寮廠ervice - this.node.localEngine = new WebSocketEngine("WebSocketEngine-" + addr.getHostString() + ":" + addr.getPort() + "-[" + resourceName() + "]", - this.single, context, liveinterval, wsmaxconns, wsthreads, wsmaxbody, mergemsg, this.cryptor, this.node, this.sendConvert, logger); - this.node.init(conf); - this.node.localEngine.init(conf); - - } - - @Override - final void postDestroy(Application application, HttpContext context, AnyValue conf) { - this.node.postDestroy(conf); - super.destroy(context, conf); - if (application != null && application.isCompileMode()) return; - this.node.localEngine.destroy(conf); - } - - @Override - public String resourceName() { - return this.getClass().getSimpleName().replace("_Dyn", "").toLowerCase().replaceAll("websocket.*$", "").replaceAll("servlet.*$", ""); - } - - @Override - public final void execute(final HttpRequest request, final HttpResponse response) throws IOException { - final boolean debug = logger.isLoggable(Level.FINEST); - if (!request.isWebSocket()) { - if (debug) logger.finest("WebSocket connect abort, (Not GET Method) or (Connection != Upgrade) or (Upgrade != websocket). request=" + request); - response.finish(true); - return; - } - final String key = request.getHeader("Sec-WebSocket-Key"); - if (key == null) { - if (debug) logger.finest("WebSocket connect abort, Not found Sec-WebSocket-Key header. request=" + request); - response.finish(true); - return; - } - if (this.node.localEngine.isLocalConnLimited()) { - if (debug) logger.finest("WebSocket connections limit, wsmaxconns=" + this.node.localEngine.getLocalWsmaxconns()); - response.finish(true); - return; - } - final WebSocket webSocket = this.createWebSocket(); - webSocket._engine = this.node.localEngine; - webSocket._channel = response.getChannel(); - webSocket._messageTextType = this.messageTextType; - webSocket._textConvert = textConvert; - webSocket._binaryConvert = binaryConvert; - webSocket._sendConvert = sendConvert; - webSocket._remoteAddress = request.getRemoteAddress(); - webSocket._remoteAddr = request.getRemoteAddr(); - webSocket._sncpAddress = this.node.localSncpAddress; - if (this.permessageDeflate && request.getHeader("Sec-WebSocket-Extensions", "").contains("permessage-deflate")) { - webSocket.deflater = new Deflater(Deflater.DEFAULT_COMPRESSION, true); - webSocket.inflater = new Inflater(true); - } - initRestWebSocket(webSocket); - CompletableFuture sessionFuture = webSocket.onOpen(request); - if (sessionFuture == null) { - if (debug) logger.finest("WebSocket connect abort, Not found sessionid. request=" + request); - response.finish(true); - return; - } - sessionFuture.whenComplete((sessionid, ex) -> { - if ((sessionid == null && webSocket.delayPackets == null) || ex != null) { - if (debug || ex != null) logger.log(ex == null ? Level.FINEST : Level.FINE, "WebSocket connect abort, Not found sessionid or occur error. request=" + request, ex); - response.finish(true); - return; - } - //onOpen鎴愬姛鎴栬呭瓨鍦╠elayPackets - webSocket._sessionid = sessionid; - request.setKeepAlive(true); - byte[] bytes = (key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11").getBytes(); - synchronized (digest) { - bytes = digest.digest(bytes); - } - response.setStatus(101); - response.setHeader("Connection", "Upgrade"); - response.addHeader("Upgrade", "websocket"); - response.addHeader("Sec-WebSocket-Accept", Base64.getEncoder().encodeToString(bytes)); - if (webSocket.deflater != null) response.addHeader("Sec-WebSocket-Extensions", "permessage-deflate"); - - response.sendBody((ByteBuffer) null, new CompletionHandler() { - - @Override - public void completed(Integer result, Void attachment) { - webSocket._readHandler = new WebSocketReadHandler(response.getContext(), webSocket, restMessageConsumer); - webSocket._writeHandler = new WebSocketWriteHandler(response.getContext(), webSocket); - Runnable createUseridHandler = () -> { - CompletableFuture userFuture = webSocket.createUserid(); - if (userFuture == null) { - if (debug) logger.finest("WebSocket connect abort, Create userid abort. request = " + request); - response.finish(true); - return; - } - userFuture.whenComplete((userid, ex2) -> { - if ((userid == null && webSocket.delayPackets == null) || ex2 != null) { - if (debug || ex2 != null) logger.log(ex2 == null ? Level.FINEST : Level.FINE, "WebSocket connect abort, Create userid abort. request = " + request, ex2); - response.finish(true); - return; - } - Runnable runHandler = () -> { - webSocket._userid = userid; - if (single && !anyuser) { - WebSocketServlet.this.node.existsWebSocket(userid).whenComplete((rs, nex) -> { - if (rs) { - CompletableFuture rcFuture = webSocket.onSingleRepeatConnect(); - Consumer task = (oldkilled) -> { - if (oldkilled) { - WebSocketServlet.this.node.localEngine.addLocal(webSocket); - response.removeChannel(); - webSocket._readHandler.startRead(); -// WebSocketRunner runner = new WebSocketRunner(context, webSocket, restMessageConsumer); -// webSocket._runner = runner; -// runner.run(); //context.runAsync(runner); - response.finish(true); - } else { //鍏抽棴鏂拌繛鎺 - response.finish(true); - } - }; - if (rcFuture == null) { - task.accept(false); - } else { - rcFuture.whenComplete((r, e) -> { - if (e != null) { - response.finish(true); - } else { - task.accept(r); - } - }); - } - } else { - WebSocketServlet.this.node.localEngine.addLocal(webSocket); - response.removeChannel(); - webSocket._readHandler.startRead(); -// WebSocketRunner runner = new WebSocketRunner(context, webSocket, restMessageConsumer); -// webSocket._runner = runner; -// runner.run(); //context.runAsync(runner); - response.finish(true); - } - }); - } else { - WebSocketServlet.this.node.localEngine.addLocal(webSocket); - response.removeChannel(); - webSocket._readHandler.startRead(); -// WebSocketRunner runner = new WebSocketRunner(context, webSocket, restMessageConsumer); -// webSocket._runner = runner; -// runner.run(); //context.runAsync(runner); - response.finish(true); - } - }; - if (webSocket.delayPackets != null) { //瀛樺湪寰呭彂閫佺殑娑堟伅 - List delayPackets = webSocket.delayPackets; - webSocket.delayPackets = null; - CompletableFuture cf = webSocket._writeHandler.send(delayPackets.toArray(new WebSocketPacket[delayPackets.size()])); - cf.whenComplete((Integer v, Throwable t) -> { - if (userid == null || t != null) { - if (t != null) logger.log(Level.FINEST, "WebSocket connect abort, Response send delayPackets abort. request = " + request, t); - response.finish(true); - } else { - runHandler.run(); - } - }); - } else { - runHandler.run(); - } - }); - }; - if (webSocket.delayPackets != null) { //瀛樺湪寰呭彂閫佺殑娑堟伅 - List delayPackets = webSocket.delayPackets; - webSocket.delayPackets = null; - CompletableFuture cf = webSocket._writeHandler.send(delayPackets.toArray(new WebSocketPacket[delayPackets.size()])); - cf.whenComplete((Integer v, Throwable t) -> { - if (sessionid == null || t != null) { - if (t != null) logger.log(Level.FINEST, "WebSocket connect abort, Response send delayPackets abort. request = " + request, t); - response.finish(true); - } else { - createUseridHandler.run(); - } - }); - } else { - createUseridHandler.run(); - } - } - - @Override - public void failed(Throwable exc, Void attachment) { - logger.log(Level.FINEST, "WebSocket connect abort, Response send abort. request = " + request, exc); - response.finish(true); - } - }); - }); - } - - protected abstract WebSocket createWebSocket(); - - protected WebSocketNode createWebSocketNode() { - return null; - } - - protected void initRestWebSocket(WebSocket websocket) { //璁剧疆WebSocket涓殑@Resource璧勬簮 - } - - protected BiConsumer createRestOnMessageConsumer() { - return null; - } - - private static MessageDigest getMessageDigest() { - try { - return MessageDigest.getInstance("SHA-1"); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - -} +/* + * 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 java.io.*; +import java.lang.reflect.*; +import java.net.*; +import java.nio.*; +import java.nio.channels.CompletionHandler; +import java.security.*; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.function.*; +import java.util.logging.*; +import java.util.zip.*; +import javax.annotation.*; +import org.redkale.boot.Application; +import org.redkale.convert.Convert; +import org.redkale.mq.MessageAgent; +import org.redkale.net.Cryptor; +import org.redkale.service.*; +import org.redkale.util.*; + +/** + *

+ * 褰揥ebSocketServlet鎺ユ敹涓涓猅CP杩炴帴鍚庯紝杩涜鍗忚鍒ゆ柇锛屽鏋滄垚鍔熷氨浼氬垱寤轰竴涓猈ebSocket銆
+ *
+ *                                    WebSocketServlet
+ *                                            |
+ *                                            |
+ *                                   WebSocketEngine
+ *                                    WebSocketNode
+ *                                   /             \
+ *                                 /                \
+ *                               /                   \
+ *                     WebSocket1                 WebSocket2
+ *
+ * 
+ * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public abstract class WebSocketServlet extends HttpServlet implements Resourcable { + + @Comment("WebScoket鏈嶅姟鍣ㄧ粰瀹㈡埛绔繘琛宲ing鎿嶄綔鐨勯棿闅旀椂闂, 鍗曚綅: 绉") + public static final String WEBPARAM__LIVEINTERVAL = "liveinterval"; + + @Comment("WebScoket鏈嶅姟鍣ㄦ渶澶ц繛鎺ユ暟锛屼负0琛ㄧず鏃犻檺鍒") + public static final String WEBPARAM__WSMAXCONNS = "wsmaxconns"; + + @Comment("WebScoket鏈嶅姟鍣ㄦ搷浣淲ebSocketNode瀵瑰簲CacheSource骞跺彂鏁, 涓-1琛ㄧず鏃犻檺鍒讹紝涓0琛ㄧず绯荤粺榛樿鍊(CPU*8)") + public static final String WEBPARAM__WSTHREADS = "wsthreads"; + + @Comment("鏈澶ф秷鎭綋闀垮害, 灏忎簬1琛ㄧず鏃犻檺鍒") + public static final String WEBPARAM__WSMAXBODY = "wsmaxbody"; + + @Comment("鎺ユ敹瀹㈡埛绔殑鍒嗗寘(last=false)娑堟伅鏃舵槸鍚﹁嚜鍔ㄥ悎骞跺寘") + public static final String WEBPARAM__WSMERGEMSG = "wsmergemsg"; + + @Comment("鍔犲瘑瑙e瘑鍣") + public static final String WEBPARAM__CRYPTOR = "cryptor"; + + @Comment("WebScoket鏈嶅姟鍣ㄧ粰瀹㈡埛绔繘琛宲ing鎿嶄綔鐨勯粯璁ら棿闅旀椂闂, 鍗曚綅: 绉") + public static final int DEFAILT_LIVEINTERVAL = 15; + + protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); + + private final MessageDigest digest = getMessageDigest(); + + private final BiConsumer restMessageConsumer = createRestOnMessageConsumer(); + + protected Type messageTextType; //RestWebSocket鏃朵細琚慨鏀 + + //鍚孯estWebSocket.single + protected boolean single = true; //鏄惁鍗曠敤鎴峰崟杩炴帴 + + //鍚孯estWebSocket.liveinterval + protected int liveinterval = DEFAILT_LIVEINTERVAL; + + //鍚孯estWebSocket.wsmaxconns + protected int wsmaxconns = 0; + + //鍚孯estWebSocket.wsthreads + protected int wsthreads = 0; + + //鍚孯estWebSocket.wsmaxbody + protected int wsmaxbody = 32 * 1024; + + //鍚孯estWebSocket.anyuser + protected boolean anyuser = false; + + //鍚孯estWebSocket.mergemsg + protected boolean mergemsg = true; + + //鍚孯estWebSocket.cryptor, 鍙橀噺鍚嶄笉鍙敼锛 琚玆est.createRestWebSocketServlet鐢ㄥ埌 + protected Cryptor cryptor; + + protected boolean permessageDeflate = false; + + protected MessageAgent messageAgent; + + @Resource(name = "jsonconvert") + protected Convert jsonConvert; + + @Resource(name = "$_textconvert") + protected Convert textConvert; + + @Resource(name = "$_binaryconvert") + protected Convert binaryConvert; + + @Resource(name = "$_sendconvert") + protected Convert sendConvert; + + @Resource(name = "$") + protected WebSocketNode node; + + @Resource(name = "SERVER_RESFACTORY") + protected ResourceFactory resourceFactory; + + protected WebSocketServlet() { + Type msgtype = String.class; + try { + for (Method method : this.getClass().getDeclaredMethods()) { + if (!method.getName().equals("createWebSocket")) continue; + if (method.getParameterCount() > 0) continue; + Type rt = TypeToken.getGenericType(method.getGenericReturnType(), this.getClass()); + if (rt instanceof ParameterizedType) { + msgtype = ((ParameterizedType) rt).getActualTypeArguments()[1]; + } + if (msgtype == Object.class) msgtype = String.class; + break; + } + } catch (Exception e) { + logger.warning(this.getClass().getName() + " not designate text message type on createWebSocket Method"); + } + this.messageTextType = msgtype; + } + + @Override + final void preInit(Application application, HttpContext context, AnyValue conf) { + if (this.textConvert == null) this.textConvert = jsonConvert; + if (this.sendConvert == null) this.sendConvert = jsonConvert; + InetSocketAddress addr = context.getServerAddress(); + if (this.node == null) this.node = createWebSocketNode(); + if (this.node == null) { //娌℃湁閮ㄧ讲SNCP锛屽嵆涓嶆槸鍒嗗竷寮 + this.node = new WebSocketNodeService(); + if (logger.isLoggable(Level.WARNING)) logger.warning("Not found WebSocketNode, create a default value for " + getClass().getName()); + } + if (this.node.sendConvert == null) this.node.sendConvert = this.sendConvert; + if (this.messageAgent != null) this.node.messageAgent = this.messageAgent; + { + AnyValue props = conf; + if (conf != null && conf.getAnyValue("properties") != null) props = conf.getAnyValue("properties"); + if (props != null) { + String cryptorClass = props.getValue(WEBPARAM__CRYPTOR); + if (cryptorClass != null && !cryptorClass.isEmpty()) { + try { + Class clazz = Thread.currentThread().getContextClassLoader().loadClass(cryptorClass); + this.cryptor = (Cryptor) clazz.getDeclaredConstructor().newInstance(); + RedkaleClassLoader.putReflectionDeclaredConstructors(clazz, cryptorClass); + if (resourceFactory != null && this.cryptor != null) resourceFactory.inject(this.cryptor); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } + } + if (application != null && application.isCompileMode()) return; + //瀛樺湪WebSocketServlet锛屽垯姝ebSocketNode蹇呴』鏄湰鍦版ā寮廠ervice + this.node.localEngine = new WebSocketEngine("WebSocketEngine-" + addr.getHostString() + ":" + addr.getPort() + "-[" + resourceName() + "]", + this.single, context, liveinterval, wsmaxconns, wsthreads, wsmaxbody, mergemsg, this.cryptor, this.node, this.sendConvert, logger); + this.node.init(conf); + this.node.localEngine.init(conf); + + } + + @Override + final void postDestroy(Application application, HttpContext context, AnyValue conf) { + this.node.postDestroy(conf); + super.destroy(context, conf); + if (application != null && application.isCompileMode()) return; + this.node.localEngine.destroy(conf); + } + + @Override + public String resourceName() { + return this.getClass().getSimpleName().replace("_Dyn", "").toLowerCase().replaceAll("websocket.*$", "").replaceAll("servlet.*$", ""); + } + + @Override + public final void execute(final HttpRequest request, final HttpResponse response) throws IOException { + final boolean debug = logger.isLoggable(Level.FINEST); + if (!request.isWebSocket()) { + if (debug) logger.finest("WebSocket connect abort, (Not GET Method) or (Connection != Upgrade) or (Upgrade != websocket). request=" + request); + response.finish(true); + return; + } + final String key = request.getHeader("Sec-WebSocket-Key"); + if (key == null) { + if (debug) logger.finest("WebSocket connect abort, Not found Sec-WebSocket-Key header. request=" + request); + response.finish(true); + return; + } + if (this.node.localEngine.isLocalConnLimited()) { + if (debug) logger.finest("WebSocket connections limit, wsmaxconns=" + this.node.localEngine.getLocalWsmaxconns()); + response.finish(true); + return; + } + final WebSocket webSocket = this.createWebSocket(); + webSocket._engine = this.node.localEngine; + webSocket._channel = response.getChannel(); + webSocket._messageTextType = this.messageTextType; + webSocket._textConvert = textConvert; + webSocket._binaryConvert = binaryConvert; + webSocket._sendConvert = sendConvert; + webSocket._remoteAddress = request.getRemoteAddress(); + webSocket._remoteAddr = request.getRemoteAddr(); + webSocket._sncpAddress = this.node.localSncpAddress; + if (this.permessageDeflate && request.getHeader("Sec-WebSocket-Extensions", "").contains("permessage-deflate")) { + webSocket.deflater = new Deflater(Deflater.DEFAULT_COMPRESSION, true); + webSocket.inflater = new Inflater(true); + } + initRestWebSocket(webSocket); + CompletableFuture sessionFuture = webSocket.onOpen(request); + if (sessionFuture == null) { + if (debug) logger.finest("WebSocket connect abort, Not found sessionid. request=" + request); + response.finish(true); + return; + } + sessionFuture.whenComplete((sessionid, ex) -> { + if ((sessionid == null && webSocket.delayPackets == null) || ex != null) { + if (debug || ex != null) logger.log(ex == null ? Level.FINEST : Level.FINE, "WebSocket connect abort, Not found sessionid or occur error. request=" + request, ex); + response.finish(true); + return; + } + //onOpen鎴愬姛鎴栬呭瓨鍦╠elayPackets + webSocket._sessionid = sessionid; + request.setKeepAlive(true); + byte[] bytes = (key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11").getBytes(); + synchronized (digest) { + bytes = digest.digest(bytes); + } + response.setStatus(101); + response.setHeader("Connection", "Upgrade"); + response.addHeader("Upgrade", "websocket"); + response.addHeader("Sec-WebSocket-Accept", Base64.getEncoder().encodeToString(bytes)); + if (webSocket.deflater != null) response.addHeader("Sec-WebSocket-Extensions", "permessage-deflate"); + + response.sendBody((ByteBuffer) null, new CompletionHandler() { + + @Override + public void completed(Integer result, Void attachment) { + webSocket._readHandler = new WebSocketReadHandler(response.getContext(), webSocket, restMessageConsumer); + webSocket._writeHandler = new WebSocketWriteHandler(response.getContext(), webSocket); + Runnable createUseridHandler = () -> { + CompletableFuture userFuture = webSocket.createUserid(); + if (userFuture == null) { + if (debug) logger.finest("WebSocket connect abort, Create userid abort. request = " + request); + response.finish(true); + return; + } + userFuture.whenComplete((userid, ex2) -> { + if ((userid == null && webSocket.delayPackets == null) || ex2 != null) { + if (debug || ex2 != null) logger.log(ex2 == null ? Level.FINEST : Level.FINE, "WebSocket connect abort, Create userid abort. request = " + request, ex2); + response.finish(true); + return; + } + Runnable runHandler = () -> { + webSocket._userid = userid; + if (single && !anyuser) { + WebSocketServlet.this.node.existsWebSocket(userid).whenComplete((rs, nex) -> { + if (rs) { + CompletableFuture rcFuture = webSocket.onSingleRepeatConnect(); + Consumer task = (oldkilled) -> { + if (oldkilled) { + WebSocketServlet.this.node.localEngine.addLocal(webSocket); + response.removeChannel(); + webSocket._readHandler.startRead(); +// WebSocketRunner runner = new WebSocketRunner(context, webSocket, restMessageConsumer); +// webSocket._runner = runner; +// runner.run(); //context.runAsync(runner); + response.finish(true); + } else { //鍏抽棴鏂拌繛鎺 + response.finish(true); + } + }; + if (rcFuture == null) { + task.accept(false); + } else { + rcFuture.whenComplete((r, e) -> { + if (e != null) { + response.finish(true); + } else { + task.accept(r); + } + }); + } + } else { + WebSocketServlet.this.node.localEngine.addLocal(webSocket); + response.removeChannel(); + webSocket._readHandler.startRead(); +// WebSocketRunner runner = new WebSocketRunner(context, webSocket, restMessageConsumer); +// webSocket._runner = runner; +// runner.run(); //context.runAsync(runner); + response.finish(true); + } + }); + } else { + WebSocketServlet.this.node.localEngine.addLocal(webSocket); + response.removeChannel(); + webSocket._readHandler.startRead(); +// WebSocketRunner runner = new WebSocketRunner(context, webSocket, restMessageConsumer); +// webSocket._runner = runner; +// runner.run(); //context.runAsync(runner); + response.finish(true); + } + }; + if (webSocket.delayPackets != null) { //瀛樺湪寰呭彂閫佺殑娑堟伅 + List delayPackets = webSocket.delayPackets; + webSocket.delayPackets = null; + CompletableFuture cf = webSocket._writeHandler.send(delayPackets.toArray(new WebSocketPacket[delayPackets.size()])); + cf.whenComplete((Integer v, Throwable t) -> { + if (userid == null || t != null) { + if (t != null) logger.log(Level.FINEST, "WebSocket connect abort, Response send delayPackets abort. request = " + request, t); + response.finish(true); + } else { + runHandler.run(); + } + }); + } else { + runHandler.run(); + } + }); + }; + if (webSocket.delayPackets != null) { //瀛樺湪寰呭彂閫佺殑娑堟伅 + List delayPackets = webSocket.delayPackets; + webSocket.delayPackets = null; + CompletableFuture cf = webSocket._writeHandler.send(delayPackets.toArray(new WebSocketPacket[delayPackets.size()])); + cf.whenComplete((Integer v, Throwable t) -> { + if (sessionid == null || t != null) { + if (t != null) logger.log(Level.FINEST, "WebSocket connect abort, Response send delayPackets abort. request = " + request, t); + response.finish(true); + } else { + createUseridHandler.run(); + } + }); + } else { + createUseridHandler.run(); + } + } + + @Override + public void failed(Throwable exc, Void attachment) { + logger.log(Level.FINEST, "WebSocket connect abort, Response send abort. request = " + request, exc); + response.finish(true); + } + }); + }); + } + + protected abstract WebSocket createWebSocket(); + + protected WebSocketNode createWebSocketNode() { + return null; + } + + protected void initRestWebSocket(WebSocket websocket) { //璁剧疆WebSocket涓殑@Resource璧勬簮 + } + + protected BiConsumer createRestOnMessageConsumer() { + return null; + } + + private static MessageDigest getMessageDigest() { + try { + return MessageDigest.getInstance("SHA-1"); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + +} diff --git a/src/main/java/org/redkale/net/http/WebSocketUserAddress.java b/src/main/java/org/redkale/net/http/WebSocketUserAddress.java index 8fbe8cbe1..7055d5154 100644 --- a/src/main/java/org/redkale/net/http/WebSocketUserAddress.java +++ b/src/main/java/org/redkale/net/http/WebSocketUserAddress.java @@ -1,120 +1,120 @@ -/* - * 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 java.io.Serializable; -import java.net.InetSocketAddress; -import java.util.Collection; -import org.redkale.convert.json.JsonConvert; - -/** - * userid 涓 sncpaddress缁勫悎瀵硅薄 - * - * - * @author zhangjx - */ -public interface WebSocketUserAddress extends Serializable { - - Serializable userid(); - - WebSocketAddress address(); - - Collection addresses(); - - public static WebSocketUserAddress create(WebSocketUserAddress userAddress) { - return new SimpleWebSocketUserAddress(userAddress); - } - - public static WebSocketUserAddress createTopic(Serializable userid, String mqtopic, InetSocketAddress sncpAddress) { - return new SimpleWebSocketUserAddress(userid, mqtopic, sncpAddress); - } - - public static WebSocketUserAddress create(Serializable userid, WebSocketAddress address) { - return new SimpleWebSocketUserAddress(userid, address); - } - - public static WebSocketUserAddress create(Serializable userid, Collection addresses) { - return new SimpleWebSocketUserAddress(userid, addresses); - } - - public static class SimpleWebSocketUserAddress implements WebSocketUserAddress { - - private Serializable userid; - - private WebSocketAddress address; - - private Collection addresses; - - public SimpleWebSocketUserAddress() { - } - - public SimpleWebSocketUserAddress(Serializable userid, String mqtopic, InetSocketAddress sncpAddress) { - this.userid = userid; - this.address = new WebSocketAddress(mqtopic, sncpAddress); - } - - public SimpleWebSocketUserAddress(Serializable userid, WebSocketAddress address) { - this.userid = userid; - this.address = address; - } - - public SimpleWebSocketUserAddress(Serializable userid, Collection addresses) { - this.userid = userid; - this.addresses = addresses; - } - - public SimpleWebSocketUserAddress(WebSocketUserAddress userAddress) { - if (userAddress == null) return; - this.userid = userAddress.userid(); - this.address = userAddress.address(); - this.addresses = userAddress.addresses(); - } - - @Override - public Serializable userid() { - return userid; - } - - @Override - public WebSocketAddress address() { - return address; - } - - @Override - public Collection addresses() { - return addresses; - } - - public Serializable getUserid() { - return userid; - } - - public void setUserid(Serializable userid) { - this.userid = userid; - } - - public WebSocketAddress getAddress() { - return address; - } - - public void setAddress(WebSocketAddress address) { - this.address = address; - } - - public Collection getAddresses() { - return addresses; - } - - public void setAddresses(Collection addresses) { - this.addresses = addresses; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - } -} +/* + * 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 java.io.Serializable; +import java.net.InetSocketAddress; +import java.util.Collection; +import org.redkale.convert.json.JsonConvert; + +/** + * userid 涓 sncpaddress缁勫悎瀵硅薄 + * + * + * @author zhangjx + */ +public interface WebSocketUserAddress extends Serializable { + + Serializable userid(); + + WebSocketAddress address(); + + Collection addresses(); + + public static WebSocketUserAddress create(WebSocketUserAddress userAddress) { + return new SimpleWebSocketUserAddress(userAddress); + } + + public static WebSocketUserAddress createTopic(Serializable userid, String mqtopic, InetSocketAddress sncpAddress) { + return new SimpleWebSocketUserAddress(userid, mqtopic, sncpAddress); + } + + public static WebSocketUserAddress create(Serializable userid, WebSocketAddress address) { + return new SimpleWebSocketUserAddress(userid, address); + } + + public static WebSocketUserAddress create(Serializable userid, Collection addresses) { + return new SimpleWebSocketUserAddress(userid, addresses); + } + + public static class SimpleWebSocketUserAddress implements WebSocketUserAddress { + + private Serializable userid; + + private WebSocketAddress address; + + private Collection addresses; + + public SimpleWebSocketUserAddress() { + } + + public SimpleWebSocketUserAddress(Serializable userid, String mqtopic, InetSocketAddress sncpAddress) { + this.userid = userid; + this.address = new WebSocketAddress(mqtopic, sncpAddress); + } + + public SimpleWebSocketUserAddress(Serializable userid, WebSocketAddress address) { + this.userid = userid; + this.address = address; + } + + public SimpleWebSocketUserAddress(Serializable userid, Collection addresses) { + this.userid = userid; + this.addresses = addresses; + } + + public SimpleWebSocketUserAddress(WebSocketUserAddress userAddress) { + if (userAddress == null) return; + this.userid = userAddress.userid(); + this.address = userAddress.address(); + this.addresses = userAddress.addresses(); + } + + @Override + public Serializable userid() { + return userid; + } + + @Override + public WebSocketAddress address() { + return address; + } + + @Override + public Collection addresses() { + return addresses; + } + + public Serializable getUserid() { + return userid; + } + + public void setUserid(Serializable userid) { + this.userid = userid; + } + + public WebSocketAddress getAddress() { + return address; + } + + public void setAddress(WebSocketAddress address) { + this.address = address; + } + + public Collection getAddresses() { + return addresses; + } + + public void setAddresses(Collection addresses) { + this.addresses = addresses; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + } +} diff --git a/src/main/java/org/redkale/net/http/WebSocketWriteHandler.java b/src/main/java/org/redkale/net/http/WebSocketWriteHandler.java index cef3f1e89..198f14e45 100644 --- a/src/main/java/org/redkale/net/http/WebSocketWriteHandler.java +++ b/src/main/java/org/redkale/net/http/WebSocketWriteHandler.java @@ -1,132 +1,132 @@ -/* - * 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 java.util.*; -import java.util.logging.*; -import java.util.concurrent.*; -import java.util.concurrent.atomic.AtomicBoolean; -import java.nio.channels.CompletionHandler; -import org.redkale.util.ByteArray; -import static org.redkale.net.http.WebSocket.*; - -/** - * - * @author zhangjx - */ -public class WebSocketWriteHandler implements CompletionHandler { - - protected final HttpContext context; - - protected final WebSocket webSocket; - - protected final AtomicBoolean writePending = new AtomicBoolean(); - - protected final ByteArray writeArray = new ByteArray(); - - protected final List> respList = new ArrayList(); - - protected final ConcurrentLinkedDeque> requestQueue = new ConcurrentLinkedDeque(); - - public WebSocketWriteHandler(HttpContext context, WebSocket webSocket) { - this.context = context; - this.webSocket = webSocket; - } - - public CompletableFuture send(WebSocketPacket... packets) { - WebSocketFuture future = new WebSocketFuture<>(packets); - if (writePending.compareAndSet(false, true)) { - respList.clear(); - respList.add(future); - writeArray.clear(); - for (WebSocketPacket p : packets) { - writeEncode(p); - } - webSocket._channel.write(writeArray, this); - } else { - requestQueue.offer(future); - } - return future; - } - - @Override - public void completed(Integer result, Void attachment) { - webSocket.lastSendTime = System.currentTimeMillis(); - for (WebSocketFuture future : respList) { - future.complete(0); - } - respList.clear(); - writeArray.clear(); - WebSocketFuture req; - while ((req = requestQueue.poll()) != null) { - respList.add(req); - for (WebSocketPacket p : req.packets) { - writeEncode(p); - } - } - if (writeArray.isEmpty()) { - if (!writePending.compareAndSet(true, false)) { - completed(0, attachment); - } - } else { - webSocket._channel.write(writeArray, this); - } - } - - @Override - public void failed(Throwable exc, Void attachment) { - WebSocketFuture req; - try { - while ((req = requestQueue.poll()) != null) { - req.completeExceptionally(exc); - } - for (WebSocketFuture future : respList) { - future.completeExceptionally(exc); - } - respList.clear(); - } catch (Exception e) { - } - webSocket.kill(RETCODE_SENDEXCEPTION, "websocket send message failed on CompletionHandler"); - if (exc != null && context.getLogger().isLoggable(Level.FINER)) { - context.getLogger().log(Level.FINER, "WebSocket sendMessage on CompletionHandler failed, force to close channel, live " + (System.currentTimeMillis() - webSocket.getCreatetime()) / 1000 + " seconds", exc); - } - } - - //娑堟伅缂栫爜 - protected void writeEncode(final WebSocketPacket packet) { - final ByteArray array = writeArray; - final byte opcode = (byte) (packet.type.getValue() | 0x80); - final byte[] content = packet.getPayload(); - final int len = content.length; - if (len <= 0x7D) { //125 - array.put(opcode); - array.put((byte) len); - } else if (len <= 0xFFFF) { // 65535 - array.put(opcode); - array.put((byte) 0x7E); //126 - array.putChar((char) len); - } else { - array.put(opcode); - array.put((byte) 0x7F); //127 - array.putLong(len); - } - array.put(content); - } - - protected static class WebSocketFuture extends CompletableFuture { - - protected WebSocketPacket[] packets; - - public WebSocketFuture() { - super(); - } - - public WebSocketFuture(WebSocketPacket... packets) { - super(); - this.packets = packets; - } - } -} +/* + * 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 java.util.*; +import java.util.logging.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicBoolean; +import java.nio.channels.CompletionHandler; +import org.redkale.util.ByteArray; +import static org.redkale.net.http.WebSocket.*; + +/** + * + * @author zhangjx + */ +public class WebSocketWriteHandler implements CompletionHandler { + + protected final HttpContext context; + + protected final WebSocket webSocket; + + protected final AtomicBoolean writePending = new AtomicBoolean(); + + protected final ByteArray writeArray = new ByteArray(); + + protected final List> respList = new ArrayList(); + + protected final ConcurrentLinkedDeque> requestQueue = new ConcurrentLinkedDeque(); + + public WebSocketWriteHandler(HttpContext context, WebSocket webSocket) { + this.context = context; + this.webSocket = webSocket; + } + + public CompletableFuture send(WebSocketPacket... packets) { + WebSocketFuture future = new WebSocketFuture<>(packets); + if (writePending.compareAndSet(false, true)) { + respList.clear(); + respList.add(future); + writeArray.clear(); + for (WebSocketPacket p : packets) { + writeEncode(p); + } + webSocket._channel.write(writeArray, this); + } else { + requestQueue.offer(future); + } + return future; + } + + @Override + public void completed(Integer result, Void attachment) { + webSocket.lastSendTime = System.currentTimeMillis(); + for (WebSocketFuture future : respList) { + future.complete(0); + } + respList.clear(); + writeArray.clear(); + WebSocketFuture req; + while ((req = requestQueue.poll()) != null) { + respList.add(req); + for (WebSocketPacket p : req.packets) { + writeEncode(p); + } + } + if (writeArray.isEmpty()) { + if (!writePending.compareAndSet(true, false)) { + completed(0, attachment); + } + } else { + webSocket._channel.write(writeArray, this); + } + } + + @Override + public void failed(Throwable exc, Void attachment) { + WebSocketFuture req; + try { + while ((req = requestQueue.poll()) != null) { + req.completeExceptionally(exc); + } + for (WebSocketFuture future : respList) { + future.completeExceptionally(exc); + } + respList.clear(); + } catch (Exception e) { + } + webSocket.kill(RETCODE_SENDEXCEPTION, "websocket send message failed on CompletionHandler"); + if (exc != null && context.getLogger().isLoggable(Level.FINER)) { + context.getLogger().log(Level.FINER, "WebSocket sendMessage on CompletionHandler failed, force to close channel, live " + (System.currentTimeMillis() - webSocket.getCreatetime()) / 1000 + " seconds", exc); + } + } + + //娑堟伅缂栫爜 + protected void writeEncode(final WebSocketPacket packet) { + final ByteArray array = writeArray; + final byte opcode = (byte) (packet.type.getValue() | 0x80); + final byte[] content = packet.getPayload(); + final int len = content.length; + if (len <= 0x7D) { //125 + array.put(opcode); + array.put((byte) len); + } else if (len <= 0xFFFF) { // 65535 + array.put(opcode); + array.put((byte) 0x7E); //126 + array.putChar((char) len); + } else { + array.put(opcode); + array.put((byte) 0x7F); //127 + array.putLong(len); + } + array.put(content); + } + + protected static class WebSocketFuture extends CompletableFuture { + + protected WebSocketPacket[] packets; + + public WebSocketFuture() { + super(); + } + + public WebSocketFuture(WebSocketPacket... packets) { + super(); + this.packets = packets; + } + } +} diff --git a/src/main/java/org/redkale/net/http/package-info.java b/src/main/java/org/redkale/net/http/package-info.java index d1c471d5a..3d749a21f 100644 --- a/src/main/java/org/redkale/net/http/package-info.java +++ b/src/main/java/org/redkale/net/http/package-info.java @@ -1,4 +1,4 @@ -/** - * HTTP鍗忚鍖,鎻愪緵HTTP鍗忚鏈嶅姟鍣 - */ -package org.redkale.net.http; +/** + * HTTP鍗忚鍖,鎻愪緵HTTP鍗忚鏈嶅姟鍣 + */ +package org.redkale.net.http; diff --git a/src/main/java/org/redkale/net/package-info.java b/src/main/java/org/redkale/net/package-info.java index 51589834c..5f10d5ca0 100644 --- a/src/main/java/org/redkale/net/package-info.java +++ b/src/main/java/org/redkale/net/package-info.java @@ -1,4 +1,4 @@ -/** - * 缃戠粶TCP/UDP鍩虹鏈嶅姟鍖 - */ -package org.redkale.net; +/** + * 缃戠粶TCP/UDP鍩虹鏈嶅姟鍖 + */ +package org.redkale.net; diff --git a/src/main/java/org/redkale/net/sncp/SncpAsyncHandler.java b/src/main/java/org/redkale/net/sncp/SncpAsyncHandler.java index 0a6164ca0..a79823a45 100644 --- a/src/main/java/org/redkale/net/sncp/SncpAsyncHandler.java +++ b/src/main/java/org/redkale/net/sncp/SncpAsyncHandler.java @@ -1,323 +1,323 @@ -/* - * 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.sncp; - -import org.redkale.asm.MethodDebugVisitor; -import java.nio.channels.CompletionHandler; -import java.util.concurrent.CompletableFuture; -import java.util.logging.Logger; -import java.util.logging.Level; -import org.redkale.asm.*; -import static org.redkale.asm.Opcodes.*; -import org.redkale.convert.bson.*; -import org.redkale.net.sncp.SncpDynServlet.SncpServletAction; -import org.redkale.util.*; - -/** - * 寮傛鍥炶皟鍑芥暟
- * - * public class _DyncSncpAsyncHandler extends XXXAsyncHandler implements SncpAsyncHandler - * - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param 缁撴灉瀵硅薄鐨勬硾鍨 - * @param 闄勪欢瀵硅薄鐨勬硾鍨 - */ -public interface SncpAsyncHandler extends CompletionHandler { - - public Object[] sncp_getParams(); - - public void sncp_setParams(Object... params); - - public void sncp_setFuture(CompletableFuture future); - - public CompletableFuture sncp_getFuture(); - - static class Factory { - - /** - *

-         *
-         * 鑰冭檻鐐癸細
-         *      1銆丆ompletionHandler瀛愮被鏄帴鍙o紝涓旇繕鏈夊叾浠栧涓柟娉
-         *      2銆丆ompletionHandler瀛愮被鏄被锛 闇瑕佺户鎵匡紝涓斿繀椤绘湁绌哄弬鏁版瀯閫犲嚱鏁
-         *      3銆丆ompletionHandler瀛愮被鏃犺鏄帴鍙h繕鏄被锛岄兘鍙兘瀛樺湪鍏朵粬娉涘瀷
-         *
-         *  public class XXXAsyncHandler_DynSncpAsyncHandler extends XXXAsyncHandler implements SncpAsyncHandler {
-         *
-         *      private SncpAsyncHandler sncphandler;
-         *
-         *      private CompletableFuture sncpfuture;
-         *
-         *      @ConstructorParameters({"sncphandler"})
-         *      public XXXAsyncHandler_DynSncpAsyncHandler(SncpAsyncHandler sncphandler) {
-         *          super();
-         *          this.sncphandler = sncphandler;
-         *      }
-         *
-         *      @Override
-         *      public void completed(Object result, Object attachment) {
-         *          sncphandler.completed(result, attachment);
-         *      }
-         *
-         *      @Override
-         *      public void failed(Throwable exc, Object attachment) {
-         *          sncphandler.failed(exc, attachment);
-         *      }
-         *
-         *      @Override
-         *      public Object[] sncp_getParams() {
-         *          return sncphandler.sncp_getParams();
-         *      }
-         *
-         *      @Override
-         *      public void sncp_setParams(Object... params) {
-         *          sncphandler.sncp_setParams(params);
-         *      }
-         *
-         *      @Override
-         *      public void sncp_setFuture(CompletableFuture future) {
-         *          this.sncpfuture = future;
-         *      }
-         *
-         *      @Override
-         *      public CompletableFuture sncp_getFuture() {
-         *          return this.sncpfuture;
-         *      }
-         *  }
-         *
-         * 
- * - * @param handlerClass CompletionHandler绫诲瀷鎴栧瓙绫 - * - * @return Creator - */ - public static Creator createCreator(Class handlerClass) { - //------------------------------------------------------------- - final boolean handlerinterface = handlerClass.isInterface(); - final String handlerClassName = handlerClass.getName().replace('.', '/'); - final String sncpHandlerName = SncpAsyncHandler.class.getName().replace('.', '/'); - final String cpDesc = Type.getDescriptor(ConstructorParameters.class); - final String sncpHandlerDesc = Type.getDescriptor(SncpAsyncHandler.class); - final String sncpFutureDesc = Type.getDescriptor(CompletableFuture.class); - final String newDynName = "org/redkaledyn/sncp/handler/_Dyn" + SncpAsyncHandler.class.getSimpleName() - + "__" + handlerClass.getName().replace('.', '/').replace('$', '_'); - try { - Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); - Class newHandlerClazz = clz == null ? Thread.currentThread().getContextClassLoader().loadClass(newDynName.replace('/', '.')) : clz; - return Creator.create(newHandlerClazz); - } catch (Throwable ex) { - } - // ------------------------------------------------------------------------------ - ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); - FieldVisitor fv; - MethodDebugVisitor mv; - AnnotationVisitor av0; - cw.visit(V11, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, null, handlerinterface ? "java/lang/Object" : handlerClassName, handlerinterface ? new String[]{handlerClassName, sncpHandlerName} : new String[]{sncpHandlerName}); - - { //handler 灞炴 - fv = cw.visitField(ACC_PRIVATE, "sncphandler", sncpHandlerDesc, null, null); - fv.visitEnd(); - } - { //future 灞炴 - fv = cw.visitField(ACC_PRIVATE, "sncpfuture", sncpFutureDesc, null, null); - fv.visitEnd(); - } - {//鏋勯犳柟娉 - mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "", "(" + sncpHandlerDesc + ")V", null, null)); - //mv.setDebug(true); - { - av0 = mv.visitAnnotation(cpDesc, true); - { - AnnotationVisitor av1 = av0.visitArray("value"); - av1.visit(null, "sncphandler"); - av1.visitEnd(); - } - av0.visitEnd(); - } - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, handlerinterface ? "java/lang/Object" : handlerClassName, "", "()V", false); - mv.visitVarInsn(ALOAD, 0); - mv.visitVarInsn(ALOAD, 1); - mv.visitFieldInsn(PUTFIELD, newDynName, "sncphandler", sncpHandlerDesc); - mv.visitInsn(RETURN); - mv.visitMaxs(2, 2); - mv.visitEnd(); - } - - for (java.lang.reflect.Method method : handlerClass.getMethods()) { // - if ("completed".equals(method.getName()) && method.getParameterCount() == 2) { - mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "completed", Type.getMethodDescriptor(method), null, null)); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, "sncphandler", sncpHandlerDesc); - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(ALOAD, 2); - mv.visitMethodInsn(INVOKEINTERFACE, sncpHandlerName, "completed", "(Ljava/lang/Object;Ljava/lang/Object;)V", true); - mv.visitInsn(RETURN); - mv.visitMaxs(3, 3); - mv.visitEnd(); - } else if ("failed".equals(method.getName()) && method.getParameterCount() == 2) { - mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "failed", Type.getMethodDescriptor(method), null, null)); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, "sncphandler", sncpHandlerDesc); - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(ALOAD, 2); - mv.visitMethodInsn(INVOKEINTERFACE, sncpHandlerName, "failed", "(Ljava/lang/Throwable;Ljava/lang/Object;)V", true); - mv.visitInsn(RETURN); - mv.visitMaxs(3, 3); - mv.visitEnd(); - } else if (handlerinterface || java.lang.reflect.Modifier.isAbstract(method.getModifiers())) { - mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, method.getName(), Type.getMethodDescriptor(method), null, null)); - Class returnType = method.getReturnType(); - if (returnType == void.class) { - mv.visitInsn(RETURN); - mv.visitMaxs(0, 1); - } else if (returnType.isPrimitive()) { - mv.visitInsn(ICONST_0); - if (returnType == long.class) { - mv.visitInsn(LRETURN); - mv.visitMaxs(2, 1); - } else if (returnType == float.class) { - mv.visitInsn(FRETURN); - mv.visitMaxs(2, 1); - } else if (returnType == double.class) { - mv.visitInsn(DRETURN); - mv.visitMaxs(2, 1); - } else { - mv.visitInsn(IRETURN); - mv.visitMaxs(1, 1); - } - } else { - mv.visitInsn(ACONST_NULL); - mv.visitInsn(ARETURN); - mv.visitMaxs(1, 1); - } - mv.visitEnd(); - } - } - { // sncp_getParams - mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "sncp_getParams", "()[Ljava/lang/Object;", null, null)); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, "sncphandler", sncpHandlerDesc); - mv.visitMethodInsn(INVOKEINTERFACE, sncpHandlerName, "sncp_getParams", "()[Ljava/lang/Object;", true); - mv.visitInsn(ARETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - { // sncp_setParams - mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC + ACC_VARARGS, "sncp_setParams", "([Ljava/lang/Object;)V", null, null)); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, "sncphandler", sncpHandlerDesc); - mv.visitVarInsn(ALOAD, 1); - mv.visitMethodInsn(INVOKEINTERFACE, sncpHandlerName, "sncp_setParams", "([Ljava/lang/Object;)V", true); - mv.visitInsn(RETURN); - mv.visitMaxs(2, 2); - mv.visitEnd(); - } - { // sncp_setFuture - mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "sncp_setFuture", "(" + sncpFutureDesc + ")V", null, null)); - mv.visitVarInsn(ALOAD, 0); - mv.visitVarInsn(ALOAD, 1); - mv.visitFieldInsn(PUTFIELD, newDynName, "sncpfuture", sncpFutureDesc); - mv.visitInsn(RETURN); - mv.visitMaxs(2, 2); - mv.visitEnd(); - } - { // sncp_getFuture - mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "sncp_getFuture", "()" + sncpFutureDesc, null, null)); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, "sncpfuture", sncpFutureDesc); - mv.visitInsn(ARETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - cw.visitEnd(); - byte[] bytes = cw.toByteArray(); - Class newClazz = (Class) new ClassLoader(handlerClass.getClassLoader()) { - public final Class loadClass(String name, byte[] b) { - return defineClass(name, b, 0, b.length); - } - }.loadClass(newDynName.replace('/', '.'), bytes); - RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, newClazz); - return Creator.create(newClazz); - } - - } - - public static class DefaultSncpAsyncHandler implements SncpAsyncHandler { - - //涓轰簡鍦ㄥ洖璋冨嚱鏁颁腑璋冪敤_callParameter鏂规硶 - protected Object[] params; - - protected SncpServletAction action; - - protected BsonReader in; - - protected BsonWriter out; - - protected SncpRequest request; - - protected SncpResponse response; - - protected CompletableFuture future; - - protected Logger logger; - - public DefaultSncpAsyncHandler(Logger logger, SncpServletAction action, BsonReader in, BsonWriter out, SncpRequest request, SncpResponse response) { - this.logger = logger; - 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; - this.request.sncp_setParams(this.action, this.logger, params); - } - - @Override - public void sncp_setFuture(CompletableFuture future) { - this.future = future; - } - - @Override - public CompletableFuture sncp_getFuture() { - return this.future; - } - - } -} +/* + * 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.sncp; + +import org.redkale.asm.MethodDebugVisitor; +import java.nio.channels.CompletionHandler; +import java.util.concurrent.CompletableFuture; +import java.util.logging.Logger; +import java.util.logging.Level; +import org.redkale.asm.*; +import static org.redkale.asm.Opcodes.*; +import org.redkale.convert.bson.*; +import org.redkale.net.sncp.SncpDynServlet.SncpServletAction; +import org.redkale.util.*; + +/** + * 寮傛鍥炶皟鍑芥暟
+ * + * public class _DyncSncpAsyncHandler extends XXXAsyncHandler implements SncpAsyncHandler + * + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param 缁撴灉瀵硅薄鐨勬硾鍨 + * @param 闄勪欢瀵硅薄鐨勬硾鍨 + */ +public interface SncpAsyncHandler extends CompletionHandler { + + public Object[] sncp_getParams(); + + public void sncp_setParams(Object... params); + + public void sncp_setFuture(CompletableFuture future); + + public CompletableFuture sncp_getFuture(); + + static class Factory { + + /** + *

+         *
+         * 鑰冭檻鐐癸細
+         *      1銆丆ompletionHandler瀛愮被鏄帴鍙o紝涓旇繕鏈夊叾浠栧涓柟娉
+         *      2銆丆ompletionHandler瀛愮被鏄被锛 闇瑕佺户鎵匡紝涓斿繀椤绘湁绌哄弬鏁版瀯閫犲嚱鏁
+         *      3銆丆ompletionHandler瀛愮被鏃犺鏄帴鍙h繕鏄被锛岄兘鍙兘瀛樺湪鍏朵粬娉涘瀷
+         *
+         *  public class XXXAsyncHandler_DynSncpAsyncHandler extends XXXAsyncHandler implements SncpAsyncHandler {
+         *
+         *      private SncpAsyncHandler sncphandler;
+         *
+         *      private CompletableFuture sncpfuture;
+         *
+         *      @ConstructorParameters({"sncphandler"})
+         *      public XXXAsyncHandler_DynSncpAsyncHandler(SncpAsyncHandler sncphandler) {
+         *          super();
+         *          this.sncphandler = sncphandler;
+         *      }
+         *
+         *      @Override
+         *      public void completed(Object result, Object attachment) {
+         *          sncphandler.completed(result, attachment);
+         *      }
+         *
+         *      @Override
+         *      public void failed(Throwable exc, Object attachment) {
+         *          sncphandler.failed(exc, attachment);
+         *      }
+         *
+         *      @Override
+         *      public Object[] sncp_getParams() {
+         *          return sncphandler.sncp_getParams();
+         *      }
+         *
+         *      @Override
+         *      public void sncp_setParams(Object... params) {
+         *          sncphandler.sncp_setParams(params);
+         *      }
+         *
+         *      @Override
+         *      public void sncp_setFuture(CompletableFuture future) {
+         *          this.sncpfuture = future;
+         *      }
+         *
+         *      @Override
+         *      public CompletableFuture sncp_getFuture() {
+         *          return this.sncpfuture;
+         *      }
+         *  }
+         *
+         * 
+ * + * @param handlerClass CompletionHandler绫诲瀷鎴栧瓙绫 + * + * @return Creator + */ + public static Creator createCreator(Class handlerClass) { + //------------------------------------------------------------- + final boolean handlerinterface = handlerClass.isInterface(); + final String handlerClassName = handlerClass.getName().replace('.', '/'); + final String sncpHandlerName = SncpAsyncHandler.class.getName().replace('.', '/'); + final String cpDesc = Type.getDescriptor(ConstructorParameters.class); + final String sncpHandlerDesc = Type.getDescriptor(SncpAsyncHandler.class); + final String sncpFutureDesc = Type.getDescriptor(CompletableFuture.class); + final String newDynName = "org/redkaledyn/sncp/handler/_Dyn" + SncpAsyncHandler.class.getSimpleName() + + "__" + handlerClass.getName().replace('.', '/').replace('$', '_'); + try { + Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); + Class newHandlerClazz = clz == null ? Thread.currentThread().getContextClassLoader().loadClass(newDynName.replace('/', '.')) : clz; + return Creator.create(newHandlerClazz); + } catch (Throwable ex) { + } + // ------------------------------------------------------------------------------ + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); + FieldVisitor fv; + MethodDebugVisitor mv; + AnnotationVisitor av0; + cw.visit(V11, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, null, handlerinterface ? "java/lang/Object" : handlerClassName, handlerinterface ? new String[]{handlerClassName, sncpHandlerName} : new String[]{sncpHandlerName}); + + { //handler 灞炴 + fv = cw.visitField(ACC_PRIVATE, "sncphandler", sncpHandlerDesc, null, null); + fv.visitEnd(); + } + { //future 灞炴 + fv = cw.visitField(ACC_PRIVATE, "sncpfuture", sncpFutureDesc, null, null); + fv.visitEnd(); + } + {//鏋勯犳柟娉 + mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "", "(" + sncpHandlerDesc + ")V", null, null)); + //mv.setDebug(true); + { + av0 = mv.visitAnnotation(cpDesc, true); + { + AnnotationVisitor av1 = av0.visitArray("value"); + av1.visit(null, "sncphandler"); + av1.visitEnd(); + } + av0.visitEnd(); + } + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, handlerinterface ? "java/lang/Object" : handlerClassName, "", "()V", false); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 1); + mv.visitFieldInsn(PUTFIELD, newDynName, "sncphandler", sncpHandlerDesc); + mv.visitInsn(RETURN); + mv.visitMaxs(2, 2); + mv.visitEnd(); + } + + for (java.lang.reflect.Method method : handlerClass.getMethods()) { // + if ("completed".equals(method.getName()) && method.getParameterCount() == 2) { + mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "completed", Type.getMethodDescriptor(method), null, null)); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, "sncphandler", sncpHandlerDesc); + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 2); + mv.visitMethodInsn(INVOKEINTERFACE, sncpHandlerName, "completed", "(Ljava/lang/Object;Ljava/lang/Object;)V", true); + mv.visitInsn(RETURN); + mv.visitMaxs(3, 3); + mv.visitEnd(); + } else if ("failed".equals(method.getName()) && method.getParameterCount() == 2) { + mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "failed", Type.getMethodDescriptor(method), null, null)); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, "sncphandler", sncpHandlerDesc); + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 2); + mv.visitMethodInsn(INVOKEINTERFACE, sncpHandlerName, "failed", "(Ljava/lang/Throwable;Ljava/lang/Object;)V", true); + mv.visitInsn(RETURN); + mv.visitMaxs(3, 3); + mv.visitEnd(); + } else if (handlerinterface || java.lang.reflect.Modifier.isAbstract(method.getModifiers())) { + mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, method.getName(), Type.getMethodDescriptor(method), null, null)); + Class returnType = method.getReturnType(); + if (returnType == void.class) { + mv.visitInsn(RETURN); + mv.visitMaxs(0, 1); + } else if (returnType.isPrimitive()) { + mv.visitInsn(ICONST_0); + if (returnType == long.class) { + mv.visitInsn(LRETURN); + mv.visitMaxs(2, 1); + } else if (returnType == float.class) { + mv.visitInsn(FRETURN); + mv.visitMaxs(2, 1); + } else if (returnType == double.class) { + mv.visitInsn(DRETURN); + mv.visitMaxs(2, 1); + } else { + mv.visitInsn(IRETURN); + mv.visitMaxs(1, 1); + } + } else { + mv.visitInsn(ACONST_NULL); + mv.visitInsn(ARETURN); + mv.visitMaxs(1, 1); + } + mv.visitEnd(); + } + } + { // sncp_getParams + mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "sncp_getParams", "()[Ljava/lang/Object;", null, null)); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, "sncphandler", sncpHandlerDesc); + mv.visitMethodInsn(INVOKEINTERFACE, sncpHandlerName, "sncp_getParams", "()[Ljava/lang/Object;", true); + mv.visitInsn(ARETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + { // sncp_setParams + mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC + ACC_VARARGS, "sncp_setParams", "([Ljava/lang/Object;)V", null, null)); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, "sncphandler", sncpHandlerDesc); + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEINTERFACE, sncpHandlerName, "sncp_setParams", "([Ljava/lang/Object;)V", true); + mv.visitInsn(RETURN); + mv.visitMaxs(2, 2); + mv.visitEnd(); + } + { // sncp_setFuture + mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "sncp_setFuture", "(" + sncpFutureDesc + ")V", null, null)); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 1); + mv.visitFieldInsn(PUTFIELD, newDynName, "sncpfuture", sncpFutureDesc); + mv.visitInsn(RETURN); + mv.visitMaxs(2, 2); + mv.visitEnd(); + } + { // sncp_getFuture + mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "sncp_getFuture", "()" + sncpFutureDesc, null, null)); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, "sncpfuture", sncpFutureDesc); + mv.visitInsn(ARETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + cw.visitEnd(); + byte[] bytes = cw.toByteArray(); + Class newClazz = (Class) new ClassLoader(handlerClass.getClassLoader()) { + public final Class loadClass(String name, byte[] b) { + return defineClass(name, b, 0, b.length); + } + }.loadClass(newDynName.replace('/', '.'), bytes); + RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, newClazz); + return Creator.create(newClazz); + } + + } + + public static class DefaultSncpAsyncHandler implements SncpAsyncHandler { + + //涓轰簡鍦ㄥ洖璋冨嚱鏁颁腑璋冪敤_callParameter鏂规硶 + protected Object[] params; + + protected SncpServletAction action; + + protected BsonReader in; + + protected BsonWriter out; + + protected SncpRequest request; + + protected SncpResponse response; + + protected CompletableFuture future; + + protected Logger logger; + + public DefaultSncpAsyncHandler(Logger logger, SncpServletAction action, BsonReader in, BsonWriter out, SncpRequest request, SncpResponse response) { + this.logger = logger; + 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; + this.request.sncp_setParams(this.action, this.logger, params); + } + + @Override + public void sncp_setFuture(CompletableFuture future) { + this.future = future; + } + + @Override + public CompletableFuture sncp_getFuture() { + return this.future; + } + + } +} diff --git a/src/main/java/org/redkale/net/sncp/SncpContext.java b/src/main/java/org/redkale/net/sncp/SncpContext.java index d23fee579..5a58b914e 100644 --- a/src/main/java/org/redkale/net/sncp/SncpContext.java +++ b/src/main/java/org/redkale/net/sncp/SncpContext.java @@ -1,25 +1,25 @@ -/* - * 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.sncp; - -import org.redkale.net.*; - -/** - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public class SncpContext extends Context { - - public SncpContext(SncpContextConfig config) { - super(config); - } - - public static class SncpContextConfig extends ContextConfig { - - } -} +/* + * 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.sncp; + +import org.redkale.net.*; + +/** + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public class SncpContext extends Context { + + public SncpContext(SncpContextConfig config) { + super(config); + } + + public static class SncpContextConfig extends ContextConfig { + + } +} diff --git a/src/main/java/org/redkale/net/sncp/SncpDyn.java b/src/main/java/org/redkale/net/sncp/SncpDyn.java index de4046f45..d64de39f5 100644 --- a/src/main/java/org/redkale/net/sncp/SncpDyn.java +++ b/src/main/java/org/redkale/net/sncp/SncpDyn.java @@ -1,29 +1,29 @@ -/* - * 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.sncp; - -import java.lang.annotation.*; -import static java.lang.annotation.ElementType.*; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * 淇グ鐢盨NCP鍗忚鍔ㄦ佺敓鎴愮殑class銆佸拰method - * 鏈湴妯″紡锛氬姩鎬佺敓鎴愮殑_DynLocalXXXXService绫讳細鎵撲笂@SncpDyn(remote = false) 鐨勬敞瑙 - * 杩滅▼妯″紡锛氬姩鎬佺敓鎴愮殑_DynRemoteXXXService绫讳細鎵撲笂@SncpDyn(remote = true) 鐨勬敞瑙 - * - *

璇︽儏瑙: https://redkale.org - * @author zhangjx - */ -@Inherited -@Documented -@Target({METHOD, TYPE}) -@Retention(RUNTIME) -public @interface SncpDyn { - - boolean remote(); - - int index() default 0; //鎺掑垪椤哄簭锛 涓昏鐢ㄤ簬Method -} +/* + * 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.sncp; + +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * 淇グ鐢盨NCP鍗忚鍔ㄦ佺敓鎴愮殑class銆佸拰method + * 鏈湴妯″紡锛氬姩鎬佺敓鎴愮殑_DynLocalXXXXService绫讳細鎵撲笂@SncpDyn(remote = false) 鐨勬敞瑙 + * 杩滅▼妯″紡锛氬姩鎬佺敓鎴愮殑_DynRemoteXXXService绫讳細鎵撲笂@SncpDyn(remote = true) 鐨勬敞瑙 + * + *

璇︽儏瑙: https://redkale.org + * @author zhangjx + */ +@Inherited +@Documented +@Target({METHOD, TYPE}) +@Retention(RUNTIME) +public @interface SncpDyn { + + boolean remote(); + + int index() default 0; //鎺掑垪椤哄簭锛 涓昏鐢ㄤ簬Method +} diff --git a/src/main/java/org/redkale/net/sncp/SncpFilter.java b/src/main/java/org/redkale/net/sncp/SncpFilter.java index 5de8f9ae4..4ad0479c5 100644 --- a/src/main/java/org/redkale/net/sncp/SncpFilter.java +++ b/src/main/java/org/redkale/net/sncp/SncpFilter.java @@ -1,16 +1,16 @@ -/* - * 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.sncp; - -import org.redkale.net.Filter; - -/** - * - * @author zhangjx - */ -public abstract class SncpFilter extends Filter { - -} +/* + * 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.sncp; + +import org.redkale.net.Filter; + +/** + * + * @author zhangjx + */ +public abstract class SncpFilter extends Filter { + +} diff --git a/src/main/java/org/redkale/net/sncp/SncpPrepareServlet.java b/src/main/java/org/redkale/net/sncp/SncpPrepareServlet.java index a02448fbb..40b351d2c 100644 --- a/src/main/java/org/redkale/net/sncp/SncpPrepareServlet.java +++ b/src/main/java/org/redkale/net/sncp/SncpPrepareServlet.java @@ -1,81 +1,81 @@ -/* - * 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.sncp; - -import org.redkale.net.PrepareServlet; -import org.redkale.util.AnyValue; -import java.io.IOException; -import org.redkale.service.Service; -import org.redkale.util.*; - -/** - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public class SncpPrepareServlet extends PrepareServlet { - - private final Object sncplock = new Object(); - - @Override - public void addServlet(SncpServlet servlet, Object attachment, AnyValue conf, DLong... mappings) { - synchronized (sncplock) { - for (SncpServlet s : getServlets()) { - if (s.service == servlet.service) throw new RuntimeException(s.service + " repeat addSncpServlet"); - } - setServletConf(servlet, conf); - putMapping(servlet.getServiceid(), servlet); - putServlet(servlet); - } - } - - public SncpServlet removeSncpServlet(Service service) { - SncpServlet rs = null; - synchronized (sncplock) { - for (SncpServlet servlet : getServlets()) { - if (servlet.service == service) { - rs = servlet; - break; - } - } - if (rs != null) { - removeMapping(rs); - removeServlet(rs); - } - } - return rs; - } - - @Override - public void init(SncpContext context, AnyValue config) { - if (application != null && application.isCompileMode()) return; - super.init(context, config); //蹇呴』瑕佹墽琛 - getServlets().forEach(s -> s.init(context, getServletConf(s))); - } - - @Override - public void destroy(SncpContext context, AnyValue config) { - super.destroy(context, config); //蹇呴』瑕佹墽琛 - getServlets().forEach(s -> s.destroy(context, getServletConf(s))); - } - - @Override - public void execute(SncpRequest request, SncpResponse response) throws IOException { - if (request.isPing()) { - response.finish(false, Sncp.PONG_BUFFER.duplicate()); - return; - } - SncpServlet servlet = (SncpServlet) mappingServlet(request.getServiceid()); - if (servlet == null) { - response.finish(SncpResponse.RETCODE_ILLSERVICEID, null); //鏃犳晥serviceid - } else { - servlet.execute(request, response); - } - } - -} +/* + * 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.sncp; + +import org.redkale.net.PrepareServlet; +import org.redkale.util.AnyValue; +import java.io.IOException; +import org.redkale.service.Service; +import org.redkale.util.*; + +/** + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public class SncpPrepareServlet extends PrepareServlet { + + private final Object sncplock = new Object(); + + @Override + public void addServlet(SncpServlet servlet, Object attachment, AnyValue conf, DLong... mappings) { + synchronized (sncplock) { + for (SncpServlet s : getServlets()) { + if (s.service == servlet.service) throw new RuntimeException(s.service + " repeat addSncpServlet"); + } + setServletConf(servlet, conf); + putMapping(servlet.getServiceid(), servlet); + putServlet(servlet); + } + } + + public SncpServlet removeSncpServlet(Service service) { + SncpServlet rs = null; + synchronized (sncplock) { + for (SncpServlet servlet : getServlets()) { + if (servlet.service == service) { + rs = servlet; + break; + } + } + if (rs != null) { + removeMapping(rs); + removeServlet(rs); + } + } + return rs; + } + + @Override + public void init(SncpContext context, AnyValue config) { + if (application != null && application.isCompileMode()) return; + super.init(context, config); //蹇呴』瑕佹墽琛 + getServlets().forEach(s -> s.init(context, getServletConf(s))); + } + + @Override + public void destroy(SncpContext context, AnyValue config) { + super.destroy(context, config); //蹇呴』瑕佹墽琛 + getServlets().forEach(s -> s.destroy(context, getServletConf(s))); + } + + @Override + public void execute(SncpRequest request, SncpResponse response) throws IOException { + if (request.isPing()) { + response.finish(false, Sncp.PONG_BUFFER.duplicate()); + return; + } + SncpServlet servlet = (SncpServlet) mappingServlet(request.getServiceid()); + if (servlet == null) { + response.finish(SncpResponse.RETCODE_ILLSERVICEID, null); //鏃犳晥serviceid + } else { + servlet.execute(request, response); + } + } + +} diff --git a/src/main/java/org/redkale/net/sncp/SncpRequest.java b/src/main/java/org/redkale/net/sncp/SncpRequest.java index 62df68b2d..f5933104c 100644 --- a/src/main/java/org/redkale/net/sncp/SncpRequest.java +++ b/src/main/java/org/redkale/net/sncp/SncpRequest.java @@ -1,175 +1,175 @@ -/* - * 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.sncp; - -import java.net.*; -import java.nio.*; -import java.util.logging.Level; -import java.util.logging.Logger; -import org.redkale.convert.bson.*; -import org.redkale.net.*; -import org.redkale.util.*; - -/** - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public class SncpRequest extends Request { - - public static final int HEADER_SIZE = 60; - - public static final byte[] DEFAULT_HEADER = new byte[HEADER_SIZE]; - - protected static final int READ_STATE_ROUTE = 1; - - protected static final int READ_STATE_HEADER = 2; - - protected static final int READ_STATE_BODY = 3; - - protected static final int READ_STATE_END = 4; - - protected final BsonConvert convert; - - private long seqid; - - protected int readState = READ_STATE_ROUTE; - - private int serviceversion; - - private DLong serviceid; - - private DLong actionid; - - private int bodylength; - - private int bodyoffset; - - private boolean ping; - - private byte[] body; - - private byte[] addrbytes = new byte[6]; - - protected SncpRequest(SncpContext context) { - super(context); - this.convert = context.getBsonConvert(); - } - - @Override - protected int readHeader(ByteBuffer buffer, Request last) { - if (buffer.remaining() == Sncp.PING_BUFFER.remaining()) { - if (buffer.hasRemaining()) buffer.get(new byte[buffer.remaining()]); - this.ping = true; //Sncp.PING_BUFFER - this.readState = READ_STATE_END; - return 0; - } - //---------------------head---------------------------------- - if (this.readState == READ_STATE_ROUTE) { - if (buffer.remaining() < HEADER_SIZE) return 1; //灏忎簬60 - this.seqid = buffer.getLong(); //8 - if (buffer.getChar() != HEADER_SIZE) { //2 - if (context.getLogger().isLoggable(Level.FINEST)) context.getLogger().finest("sncp buffer header.length not " + HEADER_SIZE); - return -1; - } - this.serviceid = DLong.read(buffer); //16 - this.serviceversion = buffer.getInt(); //4 - this.actionid = DLong.read(buffer); //16 - buffer.get(addrbytes); //ipaddr //6 - this.bodylength = buffer.getInt(); //4 - - if (buffer.getInt() != 0) { //4 - if (context.getLogger().isLoggable(Level.FINEST)) context.getLogger().finest("sncp buffer header.retcode not 0"); - return -1; - } - this.body = new byte[this.bodylength]; - this.readState = READ_STATE_BODY; - } - //---------------------body---------------------------------- - if (this.readState == READ_STATE_BODY) { - int len = Math.min(this.bodylength, buffer.remaining()); - buffer.get(body, 0, len); - this.bodyoffset = len; - int rs = bodylength - len; - if (rs == 0) this.readState = READ_STATE_END; - return rs; - } - return 0; - } - -// @Override -// protected int readBody(ByteBuffer buffer, int length) { -// final int framelen = buffer.remaining(); -// int len = Math.min(framelen, length); -// buffer.get(this.body, this.bodyoffset, len); -// this.bodyoffset += len; -// return len; -// } - @Override - protected void prepare() { - this.keepAlive = true; - } - - //琚玈ncpAsyncHandler.sncp_setParams璋冪敤 - protected void sncp_setParams(SncpDynServlet.SncpServletAction action, Logger logger, Object... params) { - } - - @Override - public String toString() { - return SncpRequest.class.getSimpleName() + "{seqid=" + this.seqid - + ",serviceversion=" + this.serviceversion + ",serviceid=" + this.serviceid - + ",actionid=" + this.actionid + ",bodylength=" + this.bodylength - + ",bodyoffset=" + this.bodyoffset + ",remoteAddress=" + getRemoteAddress() + "}"; - } - - @Override - protected void recycle() { - this.seqid = 0; - this.readState = READ_STATE_ROUTE; - this.serviceid = null; - this.serviceversion = 0; - this.actionid = null; - this.bodylength = 0; - this.bodyoffset = 0; - this.body = null; - this.ping = false; - this.addrbytes[0] = 0; - super.recycle(); - } - - protected boolean isPing() { - return ping; - } - - public byte[] getBody() { - return body; - } - - public long getSeqid() { - return seqid; - } - - public int getServiceversion() { - return serviceversion; - } - - public DLong getServiceid() { - return serviceid; - } - - public DLong getActionid() { - return actionid; - } - - public InetSocketAddress getRemoteAddress() { - if (addrbytes[0] == 0) return null; - return new InetSocketAddress((0xff & addrbytes[0]) + "." + (0xff & addrbytes[1]) + "." + (0xff & addrbytes[2]) + "." + (0xff & addrbytes[3]), - ((0xff00 & (addrbytes[4] << 8)) | (0xff & addrbytes[5]))); - } - -} +/* + * 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.sncp; + +import java.net.*; +import java.nio.*; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.redkale.convert.bson.*; +import org.redkale.net.*; +import org.redkale.util.*; + +/** + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public class SncpRequest extends Request { + + public static final int HEADER_SIZE = 60; + + public static final byte[] DEFAULT_HEADER = new byte[HEADER_SIZE]; + + protected static final int READ_STATE_ROUTE = 1; + + protected static final int READ_STATE_HEADER = 2; + + protected static final int READ_STATE_BODY = 3; + + protected static final int READ_STATE_END = 4; + + protected final BsonConvert convert; + + private long seqid; + + protected int readState = READ_STATE_ROUTE; + + private int serviceversion; + + private DLong serviceid; + + private DLong actionid; + + private int bodylength; + + private int bodyoffset; + + private boolean ping; + + private byte[] body; + + private byte[] addrbytes = new byte[6]; + + protected SncpRequest(SncpContext context) { + super(context); + this.convert = context.getBsonConvert(); + } + + @Override + protected int readHeader(ByteBuffer buffer, Request last) { + if (buffer.remaining() == Sncp.PING_BUFFER.remaining()) { + if (buffer.hasRemaining()) buffer.get(new byte[buffer.remaining()]); + this.ping = true; //Sncp.PING_BUFFER + this.readState = READ_STATE_END; + return 0; + } + //---------------------head---------------------------------- + if (this.readState == READ_STATE_ROUTE) { + if (buffer.remaining() < HEADER_SIZE) return 1; //灏忎簬60 + this.seqid = buffer.getLong(); //8 + if (buffer.getChar() != HEADER_SIZE) { //2 + if (context.getLogger().isLoggable(Level.FINEST)) context.getLogger().finest("sncp buffer header.length not " + HEADER_SIZE); + return -1; + } + this.serviceid = DLong.read(buffer); //16 + this.serviceversion = buffer.getInt(); //4 + this.actionid = DLong.read(buffer); //16 + buffer.get(addrbytes); //ipaddr //6 + this.bodylength = buffer.getInt(); //4 + + if (buffer.getInt() != 0) { //4 + if (context.getLogger().isLoggable(Level.FINEST)) context.getLogger().finest("sncp buffer header.retcode not 0"); + return -1; + } + this.body = new byte[this.bodylength]; + this.readState = READ_STATE_BODY; + } + //---------------------body---------------------------------- + if (this.readState == READ_STATE_BODY) { + int len = Math.min(this.bodylength, buffer.remaining()); + buffer.get(body, 0, len); + this.bodyoffset = len; + int rs = bodylength - len; + if (rs == 0) this.readState = READ_STATE_END; + return rs; + } + return 0; + } + +// @Override +// protected int readBody(ByteBuffer buffer, int length) { +// final int framelen = buffer.remaining(); +// int len = Math.min(framelen, length); +// buffer.get(this.body, this.bodyoffset, len); +// this.bodyoffset += len; +// return len; +// } + @Override + protected void prepare() { + this.keepAlive = true; + } + + //琚玈ncpAsyncHandler.sncp_setParams璋冪敤 + protected void sncp_setParams(SncpDynServlet.SncpServletAction action, Logger logger, Object... params) { + } + + @Override + public String toString() { + return SncpRequest.class.getSimpleName() + "{seqid=" + this.seqid + + ",serviceversion=" + this.serviceversion + ",serviceid=" + this.serviceid + + ",actionid=" + this.actionid + ",bodylength=" + this.bodylength + + ",bodyoffset=" + this.bodyoffset + ",remoteAddress=" + getRemoteAddress() + "}"; + } + + @Override + protected void recycle() { + this.seqid = 0; + this.readState = READ_STATE_ROUTE; + this.serviceid = null; + this.serviceversion = 0; + this.actionid = null; + this.bodylength = 0; + this.bodyoffset = 0; + this.body = null; + this.ping = false; + this.addrbytes[0] = 0; + super.recycle(); + } + + protected boolean isPing() { + return ping; + } + + public byte[] getBody() { + return body; + } + + public long getSeqid() { + return seqid; + } + + public int getServiceversion() { + return serviceversion; + } + + public DLong getServiceid() { + return serviceid; + } + + public DLong getActionid() { + return actionid; + } + + public InetSocketAddress getRemoteAddress() { + if (addrbytes[0] == 0) return null; + return new InetSocketAddress((0xff & addrbytes[0]) + "." + (0xff & addrbytes[1]) + "." + (0xff & addrbytes[2]) + "." + (0xff & addrbytes[3]), + ((0xff00 & (addrbytes[4] << 8)) | (0xff & addrbytes[5]))); + } + +} diff --git a/src/main/java/org/redkale/net/sncp/SncpResponse.java b/src/main/java/org/redkale/net/sncp/SncpResponse.java index b6067be15..ea3959b37 100644 --- a/src/main/java/org/redkale/net/sncp/SncpResponse.java +++ b/src/main/java/org/redkale/net/sncp/SncpResponse.java @@ -1,116 +1,116 @@ -/* - * 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.sncp; - -import static org.redkale.net.sncp.SncpRequest.HEADER_SIZE; -import java.nio.*; -import org.redkale.convert.bson.*; -import org.redkale.net.*; -import org.redkale.util.*; - -/** - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public class SncpResponse extends Response { - - public static final int RETCODE_ILLSERVICEID = (1 << 1); //鏃犳晥serviceid - - public static final int RETCODE_ILLSERVICEVER = (1 << 2); //鏃犳晥serviceversion - - public static final int RETCODE_ILLACTIONID = (1 << 3); //鏃犳晥actionid - - public static final int RETCODE_THROWEXCEPTION = (1 << 4); //鍐呴儴寮傚父 - - private final byte[] addrBytes; - - private final int addrPort; - - public static String getRetCodeInfo(int retcode) { - if (retcode == RETCODE_ILLSERVICEID) return "The serviceid is invalid"; - if (retcode == RETCODE_ILLSERVICEVER) return "The serviceversion is invalid"; - if (retcode == RETCODE_ILLACTIONID) return "The actionid is invalid"; - if (retcode == RETCODE_THROWEXCEPTION) return "Inner exception"; - return null; - } - - protected SncpResponse(SncpContext context, SncpRequest request) { - super(context, request); - this.addrBytes = context.getServerAddress().getAddress().getAddress(); - this.addrPort = context.getServerAddress().getPort(); - if (this.addrBytes.length != 4) throw new RuntimeException("SNCP serverAddress only support IPv4"); - } - - @Override - protected void prepare() { - super.prepare(); - } - - @Override - protected boolean recycle() { - return super.recycle(); - } - - @Override - protected void finish(boolean kill, ByteBuffer buffer) { - super.finish(kill, buffer); - } - - public void finish(final int retcode, final BsonWriter out) { - if (out == null) { - final ByteArray buffer = new ByteArray(SncpRequest.HEADER_SIZE); - fillHeader(buffer, 0, retcode); - finish(buffer); - return; - } - final int respBodyLength = out.count(); //body鎬婚暱搴 - final ByteArray array = out.toByteArray(); - fillHeader(array, respBodyLength - HEADER_SIZE, retcode); - finish(array); - } - - protected void fillHeader(ByteArray buffer, int bodyLength, int retcode) { - //---------------------head---------------------------------- - int offset = 0; - buffer.putLong(offset, request.getSeqid()); - offset += 8; - buffer.putChar(offset, (char) SncpRequest.HEADER_SIZE); - offset += 2; - DLong.write(buffer, offset, request.getServiceid()); - offset += 16; - buffer.putInt(offset, request.getServiceversion()); - offset += 4; - DLong.write(buffer, offset, request.getActionid()); - offset += 16; - buffer.put(offset, addrBytes); - offset += addrBytes.length; //4 - buffer.putChar(offset, (char) this.addrPort); - offset += 2; - buffer.putInt(offset, bodyLength); - offset += 4; - buffer.putInt(offset, retcode); - //offset += 4; - } - -// protected void fillHeader(ByteBuffer buffer, int bodyLength, int retcode) { -// //---------------------head---------------------------------- -// final int currentpos = buffer.position(); -// buffer.position(0); -// buffer.putLong(request.getSeqid()); -// buffer.putChar((char) SncpRequest.HEADER_SIZE); -// DLong.write(buffer, request.getServiceid()); -// buffer.putInt(request.getServiceversion()); -// DLong.write(buffer, request.getActionid()); -// buffer.put(addrBytes); -// buffer.putChar((char) this.addrPort); -// buffer.putInt(bodyLength); -// buffer.putInt(retcode); -// buffer.position(currentpos); -// } -} +/* + * 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.sncp; + +import static org.redkale.net.sncp.SncpRequest.HEADER_SIZE; +import java.nio.*; +import org.redkale.convert.bson.*; +import org.redkale.net.*; +import org.redkale.util.*; + +/** + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public class SncpResponse extends Response { + + public static final int RETCODE_ILLSERVICEID = (1 << 1); //鏃犳晥serviceid + + public static final int RETCODE_ILLSERVICEVER = (1 << 2); //鏃犳晥serviceversion + + public static final int RETCODE_ILLACTIONID = (1 << 3); //鏃犳晥actionid + + public static final int RETCODE_THROWEXCEPTION = (1 << 4); //鍐呴儴寮傚父 + + private final byte[] addrBytes; + + private final int addrPort; + + public static String getRetCodeInfo(int retcode) { + if (retcode == RETCODE_ILLSERVICEID) return "The serviceid is invalid"; + if (retcode == RETCODE_ILLSERVICEVER) return "The serviceversion is invalid"; + if (retcode == RETCODE_ILLACTIONID) return "The actionid is invalid"; + if (retcode == RETCODE_THROWEXCEPTION) return "Inner exception"; + return null; + } + + protected SncpResponse(SncpContext context, SncpRequest request) { + super(context, request); + this.addrBytes = context.getServerAddress().getAddress().getAddress(); + this.addrPort = context.getServerAddress().getPort(); + if (this.addrBytes.length != 4) throw new RuntimeException("SNCP serverAddress only support IPv4"); + } + + @Override + protected void prepare() { + super.prepare(); + } + + @Override + protected boolean recycle() { + return super.recycle(); + } + + @Override + protected void finish(boolean kill, ByteBuffer buffer) { + super.finish(kill, buffer); + } + + public void finish(final int retcode, final BsonWriter out) { + if (out == null) { + final ByteArray buffer = new ByteArray(SncpRequest.HEADER_SIZE); + fillHeader(buffer, 0, retcode); + finish(buffer); + return; + } + final int respBodyLength = out.count(); //body鎬婚暱搴 + final ByteArray array = out.toByteArray(); + fillHeader(array, respBodyLength - HEADER_SIZE, retcode); + finish(array); + } + + protected void fillHeader(ByteArray buffer, int bodyLength, int retcode) { + //---------------------head---------------------------------- + int offset = 0; + buffer.putLong(offset, request.getSeqid()); + offset += 8; + buffer.putChar(offset, (char) SncpRequest.HEADER_SIZE); + offset += 2; + DLong.write(buffer, offset, request.getServiceid()); + offset += 16; + buffer.putInt(offset, request.getServiceversion()); + offset += 4; + DLong.write(buffer, offset, request.getActionid()); + offset += 16; + buffer.put(offset, addrBytes); + offset += addrBytes.length; //4 + buffer.putChar(offset, (char) this.addrPort); + offset += 2; + buffer.putInt(offset, bodyLength); + offset += 4; + buffer.putInt(offset, retcode); + //offset += 4; + } + +// protected void fillHeader(ByteBuffer buffer, int bodyLength, int retcode) { +// //---------------------head---------------------------------- +// final int currentpos = buffer.position(); +// buffer.position(0); +// buffer.putLong(request.getSeqid()); +// buffer.putChar((char) SncpRequest.HEADER_SIZE); +// DLong.write(buffer, request.getServiceid()); +// buffer.putInt(request.getServiceversion()); +// DLong.write(buffer, request.getActionid()); +// buffer.put(addrBytes); +// buffer.putChar((char) this.addrPort); +// buffer.putInt(bodyLength); +// buffer.putInt(retcode); +// buffer.position(currentpos); +// } +} diff --git a/src/main/java/org/redkale/net/sncp/SncpServlet.java b/src/main/java/org/redkale/net/sncp/SncpServlet.java index b027fed01..41e9c2283 100644 --- a/src/main/java/org/redkale/net/sncp/SncpServlet.java +++ b/src/main/java/org/redkale/net/sncp/SncpServlet.java @@ -1,72 +1,72 @@ -/* - * 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.sncp; - -import java.util.Objects; -import java.util.concurrent.*; -import org.redkale.net.*; -import org.redkale.service.Service; -import org.redkale.util.*; - -/** - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public abstract class SncpServlet extends Servlet implements Comparable { - - protected final Class type; - - protected final String serviceName; - - protected final Service service; - - protected SncpServlet(String serviceName, Class serviceOrSourceType, Service service) { - this.type = serviceOrSourceType; - this.service = service; - this.serviceName = serviceName; - } - - public Service getService() { - return service; - } - - public String getServiceName() { - return serviceName; - } - - public Class getServiceType() { - return type; - } - - public abstract DLong getServiceid(); - - protected ExecutorService getExecutor() { - Thread thread = Thread.currentThread(); - if (thread instanceof WorkThread) { - return ((WorkThread) thread).getWorkExecutor(); - } - return ForkJoinPool.commonPool(); - } - - @Override - public final boolean equals(Object obj) { - if (!(obj instanceof SncpServlet)) return false; - return Objects.equals(getServiceid(), ((SncpServlet) obj).getServiceid()); - } - - @Override - public final int hashCode() { - return Objects.hashCode(getServiceid()); - } - - @Override - public int compareTo(SncpServlet o) { - return 0; - } -} +/* + * 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.sncp; + +import java.util.Objects; +import java.util.concurrent.*; +import org.redkale.net.*; +import org.redkale.service.Service; +import org.redkale.util.*; + +/** + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public abstract class SncpServlet extends Servlet implements Comparable { + + protected final Class type; + + protected final String serviceName; + + protected final Service service; + + protected SncpServlet(String serviceName, Class serviceOrSourceType, Service service) { + this.type = serviceOrSourceType; + this.service = service; + this.serviceName = serviceName; + } + + public Service getService() { + return service; + } + + public String getServiceName() { + return serviceName; + } + + public Class getServiceType() { + return type; + } + + public abstract DLong getServiceid(); + + protected ExecutorService getExecutor() { + Thread thread = Thread.currentThread(); + if (thread instanceof WorkThread) { + return ((WorkThread) thread).getWorkExecutor(); + } + return ForkJoinPool.commonPool(); + } + + @Override + public final boolean equals(Object obj) { + if (!(obj instanceof SncpServlet)) return false; + return Objects.equals(getServiceid(), ((SncpServlet) obj).getServiceid()); + } + + @Override + public final int hashCode() { + return Objects.hashCode(getServiceid()); + } + + @Override + public int compareTo(SncpServlet o) { + return 0; + } +} diff --git a/src/main/java/org/redkale/net/sncp/package-info.java b/src/main/java/org/redkale/net/sncp/package-info.java index 2ab81a227..60085c7d0 100644 --- a/src/main/java/org/redkale/net/sncp/package-info.java +++ b/src/main/java/org/redkale/net/sncp/package-info.java @@ -1,4 +1,4 @@ -/** - * SNCP鍗忚鍖,鎻愪緵SNCP鍗忚鏈嶅姟鍣 - */ -package org.redkale.net.sncp; +/** + * SNCP鍗忚鍖,鎻愪緵SNCP鍗忚鏈嶅姟鍣 + */ +package org.redkale.net.sncp; diff --git a/src/main/java/org/redkale/service/AbstractService.java b/src/main/java/org/redkale/service/AbstractService.java index cb5ff71e7..bd0f18771 100644 --- a/src/main/java/org/redkale/service/AbstractService.java +++ b/src/main/java/org/redkale/service/AbstractService.java @@ -1,72 +1,72 @@ -/* - * 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.service; - -import java.util.concurrent.*; -import javax.annotation.Resource; -import org.redkale.boot.Application; -import org.redkale.net.*; -import org.redkale.net.sncp.Sncp; -import org.redkale.util.ThreadHashExecutor; - -/** - * - * @author zhangjx - */ -public abstract class AbstractService implements Service { - - @Resource(name = Application.RESNAME_APP_EXECUTOR) - private ExecutorService workExecutor; - - protected Class serviceType() { - return Sncp.getServiceType(this); - } - - protected void runAsync(Runnable command) { - if (workExecutor != null) { - workExecutor.execute(command); - } else { - Thread thread = Thread.currentThread(); - if (thread instanceof WorkThread) { - ((WorkThread) thread).runAsync(command); - } else { - ForkJoinPool.commonPool().execute(command); - } - } - } - - protected void runAsync(int hash, Runnable command) { - if (workExecutor != null) { - if (workExecutor instanceof ThreadHashExecutor) { - ((ThreadHashExecutor) workExecutor).execute(hash, command); - } else { - Thread thread = Thread.currentThread(); - if (thread instanceof WorkThread) { - ((WorkThread) thread).runAsync(hash, command); - } else { - workExecutor.execute(command); - } - } - } else { - Thread thread = Thread.currentThread(); - if (thread instanceof WorkThread) { - ((WorkThread) thread).runAsync(hash, command); - } else { - ForkJoinPool.commonPool().execute(command); - } - } - } - - protected ExecutorService getExecutor() { - if (workExecutor != null) return workExecutor; - Thread thread = Thread.currentThread(); - if (thread instanceof WorkThread) { - ExecutorService e = ((WorkThread) thread).getWorkExecutor(); - if (e != null) return e; - } - return ForkJoinPool.commonPool(); - } -} +/* + * 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.service; + +import java.util.concurrent.*; +import javax.annotation.Resource; +import org.redkale.boot.Application; +import org.redkale.net.*; +import org.redkale.net.sncp.Sncp; +import org.redkale.util.ThreadHashExecutor; + +/** + * + * @author zhangjx + */ +public abstract class AbstractService implements Service { + + @Resource(name = Application.RESNAME_APP_EXECUTOR) + private ExecutorService workExecutor; + + protected Class serviceType() { + return Sncp.getServiceType(this); + } + + protected void runAsync(Runnable command) { + if (workExecutor != null) { + workExecutor.execute(command); + } else { + Thread thread = Thread.currentThread(); + if (thread instanceof WorkThread) { + ((WorkThread) thread).runAsync(command); + } else { + ForkJoinPool.commonPool().execute(command); + } + } + } + + protected void runAsync(int hash, Runnable command) { + if (workExecutor != null) { + if (workExecutor instanceof ThreadHashExecutor) { + ((ThreadHashExecutor) workExecutor).execute(hash, command); + } else { + Thread thread = Thread.currentThread(); + if (thread instanceof WorkThread) { + ((WorkThread) thread).runAsync(hash, command); + } else { + workExecutor.execute(command); + } + } + } else { + Thread thread = Thread.currentThread(); + if (thread instanceof WorkThread) { + ((WorkThread) thread).runAsync(hash, command); + } else { + ForkJoinPool.commonPool().execute(command); + } + } + } + + protected ExecutorService getExecutor() { + if (workExecutor != null) return workExecutor; + Thread thread = Thread.currentThread(); + if (thread instanceof WorkThread) { + ExecutorService e = ((WorkThread) thread).getWorkExecutor(); + if (e != null) return e; + } + return ForkJoinPool.commonPool(); + } +} diff --git a/src/main/java/org/redkale/service/Local.java b/src/main/java/org/redkale/service/Local.java index da5c22c4d..67933ca40 100644 --- a/src/main/java/org/redkale/service/Local.java +++ b/src/main/java/org/redkale/service/Local.java @@ -1,39 +1,39 @@ -/* - * 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.service; - -import java.lang.annotation.*; -import static java.lang.annotation.ElementType.*; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * 鏈湴妯″紡娉ㄨВ銆
- * 澹版槑涓篖ocal鐨凷ervice鍙兘浠ユ湰鍦版ā寮忓瓨鍦紝 鍗充娇閰嶇疆鏂囦欢涓厤缃垚杩滅▼妯″紡涔熷皢琚拷鐣ャ
- * Service閲岃鏍囪涓篖ocal鐨刾ublic鏂规硶涓嶄細琚噸杞姐 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@Inherited -@Documented -@Target({TYPE, METHOD, PARAMETER}) -@Retention(RUNTIME) -public @interface Local { - - /** - * 鏍囪鍏ㄥ眬鍞竴鎬 - *

- * 鏈変簺Service鍙兘鍙兘鍚姩涓涓疄渚嬶紝 姣斿鍑屾櫒瀹氭椂娓呴櫎涓浜涙暟鎹殑Service, 鍦ㄦ暣涓郴缁熼儴缃蹭腑搴旇鍙閮ㄧ讲涓娆 - * - * @since 2.1.0 - * @return boolean - */ - //boolean unique() default false; - - String comment() default ""; //澶囨敞鎻忚堪 -} +/* + * 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.service; + +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * 鏈湴妯″紡娉ㄨВ銆
+ * 澹版槑涓篖ocal鐨凷ervice鍙兘浠ユ湰鍦版ā寮忓瓨鍦紝 鍗充娇閰嶇疆鏂囦欢涓厤缃垚杩滅▼妯″紡涔熷皢琚拷鐣ャ
+ * Service閲岃鏍囪涓篖ocal鐨刾ublic鏂规硶涓嶄細琚噸杞姐 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@Inherited +@Documented +@Target({TYPE, METHOD, PARAMETER}) +@Retention(RUNTIME) +public @interface Local { + + /** + * 鏍囪鍏ㄥ眬鍞竴鎬 + *

+ * 鏈変簺Service鍙兘鍙兘鍚姩涓涓疄渚嬶紝 姣斿鍑屾櫒瀹氭椂娓呴櫎涓浜涙暟鎹殑Service, 鍦ㄦ暣涓郴缁熼儴缃蹭腑搴旇鍙閮ㄧ讲涓娆 + * + * @since 2.1.0 + * @return boolean + */ + //boolean unique() default false; + + String comment() default ""; //澶囨敞鎻忚堪 +} diff --git a/src/main/java/org/redkale/service/Persist.java b/src/main/java/org/redkale/service/Persist.java index 9a72e657b..bd1e11d0b 100644 --- a/src/main/java/org/redkale/service/Persist.java +++ b/src/main/java/org/redkale/service/Persist.java @@ -1,32 +1,32 @@ -/* - * 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.service; - -import java.lang.annotation.*; -import static java.lang.annotation.ElementType.*; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * Service绫讳腑涓存椂缂撳瓨瀛楁
- * - * 娉ㄦ剰: 琚爣璁板瓧娈电殑鏁版嵁蹇呴』鏄彲搴忓垪鍖栧拰鍙嶅簭鍒楀寲鐨, 涓斿瓧娈典笉鑳芥槸static鐨勶紝 濡傛灉瀛楁绫诲瀷涓嶆槸Map鎴朇ollection绫诲瀷鍒欎笉鑳戒慨楗颁负final - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@Target({FIELD}) -@Retention(RUNTIME) -public @interface Persist { - - /** - * 涓存椂缂撳瓨鐨勮秴鏃剁鏁帮紝瓒呰繃鎸囧畾绉掓暟鐨勭紦瀛樻暟鎹皢浼氳搴熷純, 0琛ㄧず涓嶈秴鏃讹紝 榛樿瓒呮椂鍊间负60绉 - * - * @return int - */ - int timeout() default 60; -} +/* + * 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.service; + +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * Service绫讳腑涓存椂缂撳瓨瀛楁
+ * + * 娉ㄦ剰: 琚爣璁板瓧娈电殑鏁版嵁蹇呴』鏄彲搴忓垪鍖栧拰鍙嶅簭鍒楀寲鐨, 涓斿瓧娈典笉鑳芥槸static鐨勶紝 濡傛灉瀛楁绫诲瀷涓嶆槸Map鎴朇ollection绫诲瀷鍒欎笉鑳戒慨楗颁负final + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@Target({FIELD}) +@Retention(RUNTIME) +public @interface Persist { + + /** + * 涓存椂缂撳瓨鐨勮秴鏃剁鏁帮紝瓒呰繃鎸囧畾绉掓暟鐨勭紦瀛樻暟鎹皢浼氳搴熷純, 0琛ㄧず涓嶈秴鏃讹紝 榛樿瓒呮椂鍊间负60绉 + * + * @return int + */ + int timeout() default 60; +} diff --git a/src/main/java/org/redkale/service/RetLabel.java b/src/main/java/org/redkale/service/RetLabel.java index cea8407c8..4ab271b9a 100644 --- a/src/main/java/org/redkale/service/RetLabel.java +++ b/src/main/java/org/redkale/service/RetLabel.java @@ -1,114 +1,114 @@ -/* - * 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.service; - -import org.redkale.util.RedkaleClassLoader; - -import java.io.*; -import java.lang.annotation.*; -import static java.lang.annotation.ElementType.*; -import static java.lang.annotation.RetentionPolicy.RUNTIME; -import java.lang.reflect.*; -import java.nio.charset.StandardCharsets; -import java.util.*; -import java.util.function.BiFunction; -import static org.redkale.boot.Application.*; - -/** - * 鐢ㄤ簬瀹氫箟閿欒鐮佺殑娉ㄨВ
- * 缁撴灉鐮佸畾涔夎寖鍥:
- * // 10000001 - 19999999 棰勭暀缁橰edkale鐨勬牳蹇冨寘浣跨敤
- * // 20000001 - 29999999 棰勭暀缁橰edkale鐨勬墿灞曞寘浣跨敤
- * // 30000001 - 99999999 棰勭暀缁橠ev寮鍙戠郴缁熻嚜韬娇鐢
- *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@Inherited -@Documented -@Target({FIELD}) -@Retention(RUNTIME) -@Repeatable(RetLabel.RetLabels.class) -public @interface RetLabel { - - String value(); - - String locale() default ""; - - @Inherited - @Documented - @Target({FIELD}) - @Retention(RUNTIME) - @interface RetLabels { - - RetLabel[] value(); - } - - public static interface RetInfoTransfer extends BiFunction { - - } - - public static abstract class RetLoader { - - public static Map> loadMap(Class clazz) { - final Map> rets = new LinkedHashMap<>(); - ServiceLoader loader = ServiceLoader.load(RetInfoTransfer.class); - RedkaleClassLoader.putServiceLoader(RetInfoTransfer.class); - Iterator it = loader.iterator(); - RetInfoTransfer func = it.hasNext() ? it.next() : null; - if (func != null) RedkaleClassLoader.putReflectionPublicConstructors(func.getClass(), func.getClass().getName()); - RedkaleClassLoader.putReflectionPublicFields(clazz.getName()); - for (Field field : clazz.getFields()) { - if (!Modifier.isStatic(field.getModifiers())) continue; - if (field.getType() != int.class) continue; - RetLabel[] infos = field.getAnnotationsByType(RetLabel.class); - if (infos == null || infos.length == 0) continue; - int value; - try { - value = field.getInt(null); - } catch (Exception ex) { - ex.printStackTrace(); - continue; - } - for (RetLabel info : infos) { - rets.computeIfAbsent(info.locale(), (k) -> new LinkedHashMap<>()).put(value, func == null ? info.value() : func.apply(value, info.value())); - } - } - try { - File propPath = new File(System.getProperty(RESNAME_APP_CONF, new File(System.getProperty(RESNAME_APP_HOME, ""), "conf").getPath())); - if (propPath.isDirectory() && propPath.canRead()) { - final String prefix = clazz.getSimpleName().toLowerCase(); - for (File propFile : propPath.listFiles(f -> f.getName().startsWith(prefix) && f.getName().endsWith(".properties"))) { - if (propFile.isFile() && propFile.canRead()) { - String locale = propFile.getName().substring(prefix.length()).replaceAll("\\.\\d+", ""); - locale = locale.substring(0, locale.indexOf(".properties")); - Map defrets = rets.get(locale); - if (defrets != null) { - InputStreamReader in = new InputStreamReader(new FileInputStream(propFile), StandardCharsets.UTF_8); - Properties prop = new Properties(); - prop.load(in); - in.close(); - prop.forEach((k, v) -> { - int retcode = Integer.parseInt(k.toString()); - if (defrets.containsKey(retcode)) defrets.put(retcode, v.toString()); - }); - } - } - } - } - } catch (Exception e) { - e.printStackTrace(); - } - return rets; - } - -// @Deprecated -// public static Map load(Class clazz) { -// return loadMap(clazz).computeIfAbsent("", (k) -> new LinkedHashMap<>()); -// } - } -} +/* + * 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.service; + +import org.redkale.util.RedkaleClassLoader; + +import java.io.*; +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import java.lang.reflect.*; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.function.BiFunction; +import static org.redkale.boot.Application.*; + +/** + * 鐢ㄤ簬瀹氫箟閿欒鐮佺殑娉ㄨВ
+ * 缁撴灉鐮佸畾涔夎寖鍥:
+ * // 10000001 - 19999999 棰勭暀缁橰edkale鐨勬牳蹇冨寘浣跨敤
+ * // 20000001 - 29999999 棰勭暀缁橰edkale鐨勬墿灞曞寘浣跨敤
+ * // 30000001 - 99999999 棰勭暀缁橠ev寮鍙戠郴缁熻嚜韬娇鐢
+ *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@Inherited +@Documented +@Target({FIELD}) +@Retention(RUNTIME) +@Repeatable(RetLabel.RetLabels.class) +public @interface RetLabel { + + String value(); + + String locale() default ""; + + @Inherited + @Documented + @Target({FIELD}) + @Retention(RUNTIME) + @interface RetLabels { + + RetLabel[] value(); + } + + public static interface RetInfoTransfer extends BiFunction { + + } + + public static abstract class RetLoader { + + public static Map> loadMap(Class clazz) { + final Map> rets = new LinkedHashMap<>(); + ServiceLoader loader = ServiceLoader.load(RetInfoTransfer.class); + RedkaleClassLoader.putServiceLoader(RetInfoTransfer.class); + Iterator it = loader.iterator(); + RetInfoTransfer func = it.hasNext() ? it.next() : null; + if (func != null) RedkaleClassLoader.putReflectionPublicConstructors(func.getClass(), func.getClass().getName()); + RedkaleClassLoader.putReflectionPublicFields(clazz.getName()); + for (Field field : clazz.getFields()) { + if (!Modifier.isStatic(field.getModifiers())) continue; + if (field.getType() != int.class) continue; + RetLabel[] infos = field.getAnnotationsByType(RetLabel.class); + if (infos == null || infos.length == 0) continue; + int value; + try { + value = field.getInt(null); + } catch (Exception ex) { + ex.printStackTrace(); + continue; + } + for (RetLabel info : infos) { + rets.computeIfAbsent(info.locale(), (k) -> new LinkedHashMap<>()).put(value, func == null ? info.value() : func.apply(value, info.value())); + } + } + try { + File propPath = new File(System.getProperty(RESNAME_APP_CONF, new File(System.getProperty(RESNAME_APP_HOME, ""), "conf").getPath())); + if (propPath.isDirectory() && propPath.canRead()) { + final String prefix = clazz.getSimpleName().toLowerCase(); + for (File propFile : propPath.listFiles(f -> f.getName().startsWith(prefix) && f.getName().endsWith(".properties"))) { + if (propFile.isFile() && propFile.canRead()) { + String locale = propFile.getName().substring(prefix.length()).replaceAll("\\.\\d+", ""); + locale = locale.substring(0, locale.indexOf(".properties")); + Map defrets = rets.get(locale); + if (defrets != null) { + InputStreamReader in = new InputStreamReader(new FileInputStream(propFile), StandardCharsets.UTF_8); + Properties prop = new Properties(); + prop.load(in); + in.close(); + prop.forEach((k, v) -> { + int retcode = Integer.parseInt(k.toString()); + if (defrets.containsKey(retcode)) defrets.put(retcode, v.toString()); + }); + } + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return rets; + } + +// @Deprecated +// public static Map load(Class clazz) { +// return loadMap(clazz).computeIfAbsent("", (k) -> new LinkedHashMap<>()); +// } + } +} diff --git a/src/main/java/org/redkale/service/RetResult.java b/src/main/java/org/redkale/service/RetResult.java index ef9f0c12f..7382cc47f 100644 --- a/src/main/java/org/redkale/service/RetResult.java +++ b/src/main/java/org/redkale/service/RetResult.java @@ -1,344 +1,344 @@ -/* - * 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.service; - -import java.io.Serializable; -import java.lang.reflect.Type; -import java.util.*; -import java.util.concurrent.*; -import java.util.function.Function; -import javax.persistence.Column; -import org.redkale.convert.*; -import org.redkale.convert.json.*; -import org.redkale.util.*; - -/** - * 閫氱敤鐨勭粨鏋滃璞★紝鍦ㄥ父瑙佺殑HTTP+JSON鎺ュ彛涓繑鍥炵殑缁撴灉闇瑕佸惈缁撴灉鐮侊紝閿欒淇℃伅锛屽拰瀹炰綋瀵硅薄銆
- * 缁撴灉鐮佸畾涔夐氬父鍓嶅洓浣嶄负妯″潡锛屽悗鍥涗綅涓烘搷浣溿
- * 缁撴灉鐮佸畾涔夎寖鍥:
- * // 10000001 - 19999999 棰勭暀缁橰edkale鐨勬牳蹇冨寘浣跨敤
- * // 20000001 - 29999999 棰勭暀缁橰edkale鐨勬墿灞曞寘浣跨敤
- * // 30000001 - 99999999 棰勭暀缁橠ev寮鍙戠郴缁熻嚜韬娇鐢
- *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param 缁撴灉瀵硅薄鐨勬硾鍨 - */ -public class RetResult implements Serializable { - - public static final Type TYPE_RET_INTEGER = new TypeToken>() { - }.getType(); - - public static final Type TYPE_RET_LONG = new TypeToken>() { - }.getType(); - - public static final Type TYPE_RET_STRING = new TypeToken>() { - }.getType(); - - //success index = 1 - @ConvertColumn(index = 2) - @Column(nullable = false) - protected int retcode; - - @ConvertColumn(index = 3) - protected String retinfo; - - @ConvertColumn(index = 4) - protected T result; - - @ConvertColumn(index = 5) - @Deprecated //@since 2.5.0 - protected Map attach; - - @ConvertDisabled - protected Convert convert; - - public RetResult() { - } - - public RetResult(T result) { - this.result = result; - } - - public RetResult(Convert convert, T result) { - this.convert = convert; - this.result = result; - } - - public RetResult(int retcode) { - this.retcode = retcode; - } - - public RetResult(int retcode, String retinfo) { - this.retcode = retcode; - this.retinfo = retinfo; - } - - public RetResult(int retcode, String retinfo, T result) { - this.retcode = retcode; - this.retinfo = retinfo; - this.result = result; - } - - public Convert convert() { - return convert; - } - - public Convert clearConvert() { - Convert c = this.convert; - this.convert = null; - return c; - } - - public RetResult convert(Convert convert) { - this.convert = convert; - return this; - } - - public CompletableFuture> toFuture() { - return CompletableFuture.completedFuture(this); - } - - public CompletableFuture toAnyFuture() { - return CompletableFuture.completedFuture(this); - } - - public static RetResult success() { - return new RetResult(); - } - - public static RetResult success(T result) { - return new RetResult().result(result); - } - - public static CompletableFuture> successFuture() { - return CompletableFuture.completedFuture(new RetResult()); - } - - public static CompletableFuture> successFuture(T result) { - return CompletableFuture.completedFuture(new RetResult(result)); - } - - public static RetResult get(CompletableFuture> future, long timeout, TimeUnit unit) { - try { - return future.get(timeout, unit); - } catch (ExecutionException ex) { - throw new RuntimeException(ex.getCause()); - } catch (Exception ex) { - throw new RuntimeException(ex); - } - } - - public static RetResult> map(String... items) { - return new RetResult(Utility.ofMap(items)); - } - - public static RetResult> map(Object... items) { - return new RetResult(Utility.ofMap(items)); - } - - /** - * 娓呯┖result - * - * @param V - * - * @return RetResult - */ - public RetResult clearResult() { - this.result = null; - return (RetResult) this; - } - - /** - * 灏哛etResult<X> 杞崲鎴愪竴涓柊鐨 RetResult<Y> - * - * @param 鐩爣鏁版嵁绫诲瀷 - * @param mapper 杞崲鍑芥暟 - * - * @return RetResult - * - * @since 2.1.0 - */ - public RetResult mapTo(Function mapper) { - return new RetResult<>(mapper.apply(this.result)).convert(this.convert).retcode(this.retcode).retinfo(this.retinfo).attach(this.attach); - } - - /** - * 鍚 setRetcode - * - * @param retcode retcode - * - * @return RetResult - */ - public RetResult retcode(int retcode) { - this.retcode = retcode; - return this; - } - - /** - * 鍚 setRetinfo - * - * @param retinfo retinfo - * - * @return RetResult - */ - public RetResult retinfo(String retinfo) { - this.retinfo = retinfo; - return this; - } - - /** - * 鍚 setResult - * - * @param result result - * - * @return RetResult - */ - public RetResult result(T result) { - this.result = result; - return this; - } - - /** - * 鍚 setAttach - * - * @param attach attach - * - * @return RetResult - */ - @Deprecated - public RetResult attach(Map attach) { - this.attach = attach; - return this; - } - - /** - * attach娣诲姞鍏冪礌 - * - * @param key String - * @param value String - * - * @return RetResult - */ - @Deprecated - public RetResult attach(String key, Object value) { - if (this.attach == null) this.attach = new HashMap<>(); - boolean canstr = value != null && (value instanceof CharSequence || value instanceof Number || value.getClass().isPrimitive()); - this.attach.put(key, value == null ? null : (canstr ? String.valueOf(value) : JsonConvert.root().convertTo(value))); - return this; - } - - /** - * 娓呯┖attach - * - * - * @return RetResult - */ - @Deprecated - public RetResult clearAttach() { - this.attach = null; - return this; - } - - /** - * 缁撴灉鐮 0琛ㄧず鎴愬姛銆 闈0琛ㄧず閿欒 - * - * @return 缁撴灉鐮 - */ - public int getRetcode() { - return retcode; - } - - public void setRetcode(int retcode) { - this.retcode = retcode; - } - - /** - * 缁撴灉淇℃伅锛岄氬父retcode != 0鏃跺间负閿欒淇℃伅 - * - * @return 缁撴灉淇℃伅 - */ - public String getRetinfo() { - return retinfo; - } - - /** - * 璁剧疆缁撴灉淇℃伅 - * - * @param retinfo 缁撴灉淇℃伅 - */ - public void setRetinfo(String retinfo) { - this.retinfo = retinfo; - } - - /** - * 缁撴灉闄勪欢 - * - * @return 缁撴灉闄勪欢 - */ - @Deprecated - public Map getAttach() { - return attach; - } - - /** - * 璁剧疆缁撴灉闄勪欢 - * - * @param attach Map - */ - @Deprecated - public void setAttach(Map attach) { - this.attach = attach; - } - - /** - * 鑾峰彇闄勪欢鍏冪礌鍊 - * - * @param name 鍏冪礌鍚 - * @param defValue 榛樿鍊 - * - * @return 缁撴灉鍊 - */ - @Deprecated - public String getAttach(String name, String defValue) { - return attach == null ? defValue : attach.getOrDefault(name, defValue); - } - - /** - * 缁撴灉瀵硅薄锛 閫氬父鍙湁鍦╮etcode = 0鏃跺兼墠鏈夋晥 - * - * @return 缁撴灉瀵硅薄 - */ - public T getResult() { - return result; - } - - /** - * 璁剧疆缁撴灉瀵硅薄 - * - * @param result T - */ - public void setResult(T result) { - this.result = result; - } - - /** - * 鍒ゆ柇缁撴灉鏄惁鎴愬姛杩斿洖锛 retcode = 0 瑙嗕负鎴愬姛锛 鍚﹀垯瑙嗕负閿欒鐮 - * - * @return 鏄惁鎴愬姛 - */ - @ConvertColumn(index = 1) - public boolean isSuccess() { - return retcode == 0; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - -} +/* + * 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.service; + +import java.io.Serializable; +import java.lang.reflect.Type; +import java.util.*; +import java.util.concurrent.*; +import java.util.function.Function; +import javax.persistence.Column; +import org.redkale.convert.*; +import org.redkale.convert.json.*; +import org.redkale.util.*; + +/** + * 閫氱敤鐨勭粨鏋滃璞★紝鍦ㄥ父瑙佺殑HTTP+JSON鎺ュ彛涓繑鍥炵殑缁撴灉闇瑕佸惈缁撴灉鐮侊紝閿欒淇℃伅锛屽拰瀹炰綋瀵硅薄銆
+ * 缁撴灉鐮佸畾涔夐氬父鍓嶅洓浣嶄负妯″潡锛屽悗鍥涗綅涓烘搷浣溿
+ * 缁撴灉鐮佸畾涔夎寖鍥:
+ * // 10000001 - 19999999 棰勭暀缁橰edkale鐨勬牳蹇冨寘浣跨敤
+ * // 20000001 - 29999999 棰勭暀缁橰edkale鐨勬墿灞曞寘浣跨敤
+ * // 30000001 - 99999999 棰勭暀缁橠ev寮鍙戠郴缁熻嚜韬娇鐢
+ *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param 缁撴灉瀵硅薄鐨勬硾鍨 + */ +public class RetResult implements Serializable { + + public static final Type TYPE_RET_INTEGER = new TypeToken>() { + }.getType(); + + public static final Type TYPE_RET_LONG = new TypeToken>() { + }.getType(); + + public static final Type TYPE_RET_STRING = new TypeToken>() { + }.getType(); + + //success index = 1 + @ConvertColumn(index = 2) + @Column(nullable = false) + protected int retcode; + + @ConvertColumn(index = 3) + protected String retinfo; + + @ConvertColumn(index = 4) + protected T result; + + @ConvertColumn(index = 5) + @Deprecated //@since 2.5.0 + protected Map attach; + + @ConvertDisabled + protected Convert convert; + + public RetResult() { + } + + public RetResult(T result) { + this.result = result; + } + + public RetResult(Convert convert, T result) { + this.convert = convert; + this.result = result; + } + + public RetResult(int retcode) { + this.retcode = retcode; + } + + public RetResult(int retcode, String retinfo) { + this.retcode = retcode; + this.retinfo = retinfo; + } + + public RetResult(int retcode, String retinfo, T result) { + this.retcode = retcode; + this.retinfo = retinfo; + this.result = result; + } + + public Convert convert() { + return convert; + } + + public Convert clearConvert() { + Convert c = this.convert; + this.convert = null; + return c; + } + + public RetResult convert(Convert convert) { + this.convert = convert; + return this; + } + + public CompletableFuture> toFuture() { + return CompletableFuture.completedFuture(this); + } + + public CompletableFuture toAnyFuture() { + return CompletableFuture.completedFuture(this); + } + + public static RetResult success() { + return new RetResult(); + } + + public static RetResult success(T result) { + return new RetResult().result(result); + } + + public static CompletableFuture> successFuture() { + return CompletableFuture.completedFuture(new RetResult()); + } + + public static CompletableFuture> successFuture(T result) { + return CompletableFuture.completedFuture(new RetResult(result)); + } + + public static RetResult get(CompletableFuture> future, long timeout, TimeUnit unit) { + try { + return future.get(timeout, unit); + } catch (ExecutionException ex) { + throw new RuntimeException(ex.getCause()); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + + public static RetResult> map(String... items) { + return new RetResult(Utility.ofMap(items)); + } + + public static RetResult> map(Object... items) { + return new RetResult(Utility.ofMap(items)); + } + + /** + * 娓呯┖result + * + * @param V + * + * @return RetResult + */ + public RetResult clearResult() { + this.result = null; + return (RetResult) this; + } + + /** + * 灏哛etResult<X> 杞崲鎴愪竴涓柊鐨 RetResult<Y> + * + * @param 鐩爣鏁版嵁绫诲瀷 + * @param mapper 杞崲鍑芥暟 + * + * @return RetResult + * + * @since 2.1.0 + */ + public RetResult mapTo(Function mapper) { + return new RetResult<>(mapper.apply(this.result)).convert(this.convert).retcode(this.retcode).retinfo(this.retinfo).attach(this.attach); + } + + /** + * 鍚 setRetcode + * + * @param retcode retcode + * + * @return RetResult + */ + public RetResult retcode(int retcode) { + this.retcode = retcode; + return this; + } + + /** + * 鍚 setRetinfo + * + * @param retinfo retinfo + * + * @return RetResult + */ + public RetResult retinfo(String retinfo) { + this.retinfo = retinfo; + return this; + } + + /** + * 鍚 setResult + * + * @param result result + * + * @return RetResult + */ + public RetResult result(T result) { + this.result = result; + return this; + } + + /** + * 鍚 setAttach + * + * @param attach attach + * + * @return RetResult + */ + @Deprecated + public RetResult attach(Map attach) { + this.attach = attach; + return this; + } + + /** + * attach娣诲姞鍏冪礌 + * + * @param key String + * @param value String + * + * @return RetResult + */ + @Deprecated + public RetResult attach(String key, Object value) { + if (this.attach == null) this.attach = new HashMap<>(); + boolean canstr = value != null && (value instanceof CharSequence || value instanceof Number || value.getClass().isPrimitive()); + this.attach.put(key, value == null ? null : (canstr ? String.valueOf(value) : JsonConvert.root().convertTo(value))); + return this; + } + + /** + * 娓呯┖attach + * + * + * @return RetResult + */ + @Deprecated + public RetResult clearAttach() { + this.attach = null; + return this; + } + + /** + * 缁撴灉鐮 0琛ㄧず鎴愬姛銆 闈0琛ㄧず閿欒 + * + * @return 缁撴灉鐮 + */ + public int getRetcode() { + return retcode; + } + + public void setRetcode(int retcode) { + this.retcode = retcode; + } + + /** + * 缁撴灉淇℃伅锛岄氬父retcode != 0鏃跺间负閿欒淇℃伅 + * + * @return 缁撴灉淇℃伅 + */ + public String getRetinfo() { + return retinfo; + } + + /** + * 璁剧疆缁撴灉淇℃伅 + * + * @param retinfo 缁撴灉淇℃伅 + */ + public void setRetinfo(String retinfo) { + this.retinfo = retinfo; + } + + /** + * 缁撴灉闄勪欢 + * + * @return 缁撴灉闄勪欢 + */ + @Deprecated + public Map getAttach() { + return attach; + } + + /** + * 璁剧疆缁撴灉闄勪欢 + * + * @param attach Map + */ + @Deprecated + public void setAttach(Map attach) { + this.attach = attach; + } + + /** + * 鑾峰彇闄勪欢鍏冪礌鍊 + * + * @param name 鍏冪礌鍚 + * @param defValue 榛樿鍊 + * + * @return 缁撴灉鍊 + */ + @Deprecated + public String getAttach(String name, String defValue) { + return attach == null ? defValue : attach.getOrDefault(name, defValue); + } + + /** + * 缁撴灉瀵硅薄锛 閫氬父鍙湁鍦╮etcode = 0鏃跺兼墠鏈夋晥 + * + * @return 缁撴灉瀵硅薄 + */ + public T getResult() { + return result; + } + + /** + * 璁剧疆缁撴灉瀵硅薄 + * + * @param result T + */ + public void setResult(T result) { + this.result = result; + } + + /** + * 鍒ゆ柇缁撴灉鏄惁鎴愬姛杩斿洖锛 retcode = 0 瑙嗕负鎴愬姛锛 鍚﹀垯瑙嗕负閿欒鐮 + * + * @return 鏄惁鎴愬姛 + */ + @ConvertColumn(index = 1) + public boolean isSuccess() { + return retcode == 0; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + +} diff --git a/src/main/java/org/redkale/service/RpcAttachment.java b/src/main/java/org/redkale/service/RpcAttachment.java index 96f86ae74..d807f1163 100644 --- a/src/main/java/org/redkale/service/RpcAttachment.java +++ b/src/main/java/org/redkale/service/RpcAttachment.java @@ -1,26 +1,26 @@ -/* - * 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.service; - -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.RUNTIME; -import java.lang.annotation.*; - -/** - * SNCP鍗忚涓敤浜嶤ompletionHandler鍥炶皟鍑芥暟涓殑attach瀛楁銆 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@Inherited -@Documented -@Target({PARAMETER}) -@Retention(RUNTIME) -public @interface RpcAttachment { - -} +/* + * 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.service; + +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import java.lang.annotation.*; + +/** + * SNCP鍗忚涓敤浜嶤ompletionHandler鍥炶皟鍑芥暟涓殑attach瀛楁銆 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@Inherited +@Documented +@Target({PARAMETER}) +@Retention(RUNTIME) +public @interface RpcAttachment { + +} diff --git a/src/main/java/org/redkale/service/RpcCall.java b/src/main/java/org/redkale/service/RpcCall.java index 18a7d3beb..b2aa7a6d4 100644 --- a/src/main/java/org/redkale/service/RpcCall.java +++ b/src/main/java/org/redkale/service/RpcCall.java @@ -1,25 +1,25 @@ -/* - * 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.service; - -import java.lang.annotation.*; -import static java.lang.annotation.RetentionPolicy.RUNTIME; -import org.redkale.util.*; - -/** - * 鍙傛暟鍥炲啓, 褰揝ervice鐨勬柟娉曢渶瑕佹洿鏀瑰弬鏁板璞″唴閮ㄧ殑鏁版嵁鏃讹紝闇瑕佷娇鐢≧pcCall - * - *

璇︽儏瑙: https://redkale.org - * @author zhangjx - */ -@Inherited -@Documented -@Target({ElementType.PARAMETER}) -@Retention(RUNTIME) -public @interface RpcCall { - - Class value(); -} +/* + * 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.service; + +import java.lang.annotation.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import org.redkale.util.*; + +/** + * 鍙傛暟鍥炲啓, 褰揝ervice鐨勬柟娉曢渶瑕佹洿鏀瑰弬鏁板璞″唴閮ㄧ殑鏁版嵁鏃讹紝闇瑕佷娇鐢≧pcCall + * + *

璇︽儏瑙: https://redkale.org + * @author zhangjx + */ +@Inherited +@Documented +@Target({ElementType.PARAMETER}) +@Retention(RUNTIME) +public @interface RpcCall { + + Class value(); +} diff --git a/src/main/java/org/redkale/service/RpcCallArrayAttribute.java b/src/main/java/org/redkale/service/RpcCallArrayAttribute.java index d1c2ea5eb..633a473bc 100644 --- a/src/main/java/org/redkale/service/RpcCallArrayAttribute.java +++ b/src/main/java/org/redkale/service/RpcCallArrayAttribute.java @@ -1,63 +1,63 @@ -/* - * 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.service; - -import java.io.Serializable; -import java.lang.reflect.Array; -import org.redkale.util.Attribute; - -/** - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * - * @since 2.1.0 - * @param 瀵硅薄绫诲瀷 - * @param 瀛楁绫诲瀷 - */ -@SuppressWarnings("unchecked") -public class RpcCallArrayAttribute implements Attribute { - - public static final RpcCallArrayAttribute instance = new RpcCallArrayAttribute(); - - @Override - public Class type() { - return (Class) Object.class; - } - - @Override - public Class declaringClass() { - return (Class) (Class) Object[].class; - } - - @Override - public String field() { - return ""; - } - - @Override - public F get(final T[] objs) { - if (objs == null || objs.length == 0) return null; - final Attribute attr = RpcCallAttribute.load(objs[0].getClass()); - final Object keys = Array.newInstance(attr.type(), objs.length); - for (int i = 0; i < objs.length; i++) { - Array.set(keys, i, attr.get(objs[i])); - } - return (F) keys; - } - - @Override - public void set(final T[] objs, final F keys) { - if (objs == null || objs.length == 0) return; - final Attribute attr = RpcCallAttribute.load(objs[0].getClass()); - for (int i = 0; i < objs.length; i++) { - attr.set(objs[i], (Serializable) Array.get(keys, i)); - } - } - -} +/* + * 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.service; + +import java.io.Serializable; +import java.lang.reflect.Array; +import org.redkale.util.Attribute; + +/** + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.1.0 + * @param 瀵硅薄绫诲瀷 + * @param 瀛楁绫诲瀷 + */ +@SuppressWarnings("unchecked") +public class RpcCallArrayAttribute implements Attribute { + + public static final RpcCallArrayAttribute instance = new RpcCallArrayAttribute(); + + @Override + public Class type() { + return (Class) Object.class; + } + + @Override + public Class declaringClass() { + return (Class) (Class) Object[].class; + } + + @Override + public String field() { + return ""; + } + + @Override + public F get(final T[] objs) { + if (objs == null || objs.length == 0) return null; + final Attribute attr = RpcCallAttribute.load(objs[0].getClass()); + final Object keys = Array.newInstance(attr.type(), objs.length); + for (int i = 0; i < objs.length; i++) { + Array.set(keys, i, attr.get(objs[i])); + } + return (F) keys; + } + + @Override + public void set(final T[] objs, final F keys) { + if (objs == null || objs.length == 0) return; + final Attribute attr = RpcCallAttribute.load(objs[0].getClass()); + for (int i = 0; i < objs.length; i++) { + attr.set(objs[i], (Serializable) Array.get(keys, i)); + } + } + +} diff --git a/src/main/java/org/redkale/service/RpcCallAttribute.java b/src/main/java/org/redkale/service/RpcCallAttribute.java index 592342e5e..e8e760e14 100644 --- a/src/main/java/org/redkale/service/RpcCallAttribute.java +++ b/src/main/java/org/redkale/service/RpcCallAttribute.java @@ -1,77 +1,77 @@ -/* - * 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.service; - -import java.io.Serializable; -import java.lang.reflect.*; -import java.util.concurrent.ConcurrentHashMap; -import org.redkale.util.Attribute; - -/** - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * - * @since 2.1.0 - */ -public class RpcCallAttribute implements Attribute { - - public static final RpcCallAttribute instance = new RpcCallAttribute(); - - private static final ConcurrentHashMap attributes = new ConcurrentHashMap<>(); - - static Attribute load(final Class clazz) { - Attribute rs = attributes.get(clazz); - if (rs != null) return rs; - synchronized (attributes) { - rs = attributes.get(clazz); - if (rs == null) { - Class cltmp = clazz; - do { - for (Field field : cltmp.getDeclaredFields()) { - try { - rs = Attribute.create(cltmp, field); - attributes.put(clazz, rs); - return rs; - } catch (RuntimeException e) { - } - } - } while ((cltmp = cltmp.getSuperclass()) != Object.class); - } - return rs; - } - } - - @Override - public Class type() { - return Serializable.class; - } - - @Override - public Class declaringClass() { - return Object.class; - } - - @Override - public String field() { - return ""; - } - - @Override - public Serializable get(final Object obj) { - if (obj == null) return null; - return load(obj.getClass()).get(obj); - } - - @Override - public void set(final Object obj, final Serializable key) { - if (obj == null) return; - load(obj.getClass()).set(obj, key); - } - -} +/* + * 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.service; + +import java.io.Serializable; +import java.lang.reflect.*; +import java.util.concurrent.ConcurrentHashMap; +import org.redkale.util.Attribute; + +/** + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.1.0 + */ +public class RpcCallAttribute implements Attribute { + + public static final RpcCallAttribute instance = new RpcCallAttribute(); + + private static final ConcurrentHashMap attributes = new ConcurrentHashMap<>(); + + static Attribute load(final Class clazz) { + Attribute rs = attributes.get(clazz); + if (rs != null) return rs; + synchronized (attributes) { + rs = attributes.get(clazz); + if (rs == null) { + Class cltmp = clazz; + do { + for (Field field : cltmp.getDeclaredFields()) { + try { + rs = Attribute.create(cltmp, field); + attributes.put(clazz, rs); + return rs; + } catch (RuntimeException e) { + } + } + } while ((cltmp = cltmp.getSuperclass()) != Object.class); + } + return rs; + } + } + + @Override + public Class type() { + return Serializable.class; + } + + @Override + public Class declaringClass() { + return Object.class; + } + + @Override + public String field() { + return ""; + } + + @Override + public Serializable get(final Object obj) { + if (obj == null) return null; + return load(obj.getClass()).get(obj); + } + + @Override + public void set(final Object obj, final Serializable key) { + if (obj == null) return; + load(obj.getClass()).set(obj, key); + } + +} diff --git a/src/main/java/org/redkale/service/RpcRemote.java b/src/main/java/org/redkale/service/RpcRemote.java index 042bd1455..0f1f500bd 100644 --- a/src/main/java/org/redkale/service/RpcRemote.java +++ b/src/main/java/org/redkale/service/RpcRemote.java @@ -1,24 +1,24 @@ -/* - * 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.service; - -import java.lang.annotation.*; -import static java.lang.annotation.ElementType.*; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * 鐢ㄤ簬鍦 Service 涓垱寤鸿嚜韬繙绋嬫ā寮忕殑瀵硅薄 - * - *

璇︽儏瑙: https://redkale.org - * @author zhangjx - */ -@Inherited -@Documented -@Target({FIELD}) -@Retention(RUNTIME) -public @interface RpcRemote { - -} +/* + * 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.service; + +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * 鐢ㄤ簬鍦 Service 涓垱寤鸿嚜韬繙绋嬫ā寮忕殑瀵硅薄 + * + *

璇︽儏瑙: https://redkale.org + * @author zhangjx + */ +@Inherited +@Documented +@Target({FIELD}) +@Retention(RUNTIME) +public @interface RpcRemote { + +} diff --git a/src/main/java/org/redkale/service/RpcRemoteException.java b/src/main/java/org/redkale/service/RpcRemoteException.java index e4757a502..61ee4a4a2 100644 --- a/src/main/java/org/redkale/service/RpcRemoteException.java +++ b/src/main/java/org/redkale/service/RpcRemoteException.java @@ -1,33 +1,33 @@ -/* - * 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.service; - -/** - * 渚汻PC鍗忚浣跨敤 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public class RpcRemoteException extends RuntimeException { - - public RpcRemoteException() { - super(); - } - - public RpcRemoteException(String s) { - super(s); - } - - public RpcRemoteException(String message, Throwable cause) { - super(message, cause); - } - - public RpcRemoteException(Throwable cause) { - super(cause); - } -} +/* + * 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.service; + +/** + * 渚汻PC鍗忚浣跨敤 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public class RpcRemoteException extends RuntimeException { + + public RpcRemoteException() { + super(); + } + + public RpcRemoteException(String s) { + super(s); + } + + public RpcRemoteException(String message, Throwable cause) { + super(message, cause); + } + + public RpcRemoteException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/org/redkale/service/RpcSourceAddress.java b/src/main/java/org/redkale/service/RpcSourceAddress.java index 5713fa3d8..8fa45861b 100644 --- a/src/main/java/org/redkale/service/RpcSourceAddress.java +++ b/src/main/java/org/redkale/service/RpcSourceAddress.java @@ -1,25 +1,25 @@ -/* - * 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.service; - -import java.lang.annotation.*; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * SNCP鍗忚涓爣璁颁负鏉ユ簮鍦板潃鍙傛暟, 璇ユ敞瑙e彧鑳芥爣璁板湪绫诲瀷涓篠ocketAddress鎴朓netSocketAddress鐨勫弬鏁颁笂銆 - * - * - * 璇︽儏瑙: https://redkale.org - * @author zhangjx - */ -@Inherited -@Documented -@Target({PARAMETER}) -@Retention(RUNTIME) -public @interface RpcSourceAddress { - -} +/* + * 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.service; + +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * SNCP鍗忚涓爣璁颁负鏉ユ簮鍦板潃鍙傛暟, 璇ユ敞瑙e彧鑳芥爣璁板湪绫诲瀷涓篠ocketAddress鎴朓netSocketAddress鐨勫弬鏁颁笂銆 + * + * + * 璇︽儏瑙: https://redkale.org + * @author zhangjx + */ +@Inherited +@Documented +@Target({PARAMETER}) +@Retention(RUNTIME) +public @interface RpcSourceAddress { + +} diff --git a/src/main/java/org/redkale/service/RpcTargetAddress.java b/src/main/java/org/redkale/service/RpcTargetAddress.java index c32ffaa43..75abcb5de 100644 --- a/src/main/java/org/redkale/service/RpcTargetAddress.java +++ b/src/main/java/org/redkale/service/RpcTargetAddress.java @@ -1,25 +1,25 @@ -/* - * 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.service; - -import java.lang.annotation.*; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * SNCP鍗忚涓爣璁颁负鐩爣鍦板潃鍙傛暟, 璇ユ敞瑙e彧鑳芥爣璁板湪绫诲瀷涓篠ocketAddress鎴朓netSocketAddress鐨勫弬鏁颁笂銆 - * - * - * 璇︽儏瑙: https://redkale.org - * @author zhangjx - */ -@Inherited -@Documented -@Target({PARAMETER}) -@Retention(RUNTIME) -public @interface RpcTargetAddress { - -} +/* + * 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.service; + +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * SNCP鍗忚涓爣璁颁负鐩爣鍦板潃鍙傛暟, 璇ユ敞瑙e彧鑳芥爣璁板湪绫诲瀷涓篠ocketAddress鎴朓netSocketAddress鐨勫弬鏁颁笂銆 + * + * + * 璇︽儏瑙: https://redkale.org + * @author zhangjx + */ +@Inherited +@Documented +@Target({PARAMETER}) +@Retention(RUNTIME) +public @interface RpcTargetAddress { + +} diff --git a/src/main/java/org/redkale/service/RpcTargetTopic.java b/src/main/java/org/redkale/service/RpcTargetTopic.java index a2fc66c45..b94cf8a25 100644 --- a/src/main/java/org/redkale/service/RpcTargetTopic.java +++ b/src/main/java/org/redkale/service/RpcTargetTopic.java @@ -1,28 +1,28 @@ -/* - * 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.service; - -import java.lang.annotation.*; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * SNCP鍗忚涓爣璁颁负鐩爣topic鍙傛暟, 璇ユ敞瑙e彧鑳芥爣璁板湪绫诲瀷涓篠tring鐨勫弬鏁颁笂銆 - * - * - * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * - * @since 2.1.0 - */ -@Inherited -@Documented -@Target({PARAMETER}) -@Retention(RUNTIME) -public @interface RpcTargetTopic { - -} +/* + * 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.service; + +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * SNCP鍗忚涓爣璁颁负鐩爣topic鍙傛暟, 璇ユ敞瑙e彧鑳芥爣璁板湪绫诲瀷涓篠tring鐨勫弬鏁颁笂銆 + * + * + * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.1.0 + */ +@Inherited +@Documented +@Target({PARAMETER}) +@Retention(RUNTIME) +public @interface RpcTargetTopic { + +} diff --git a/src/main/java/org/redkale/service/Service.java b/src/main/java/org/redkale/service/Service.java index cdd5150ec..69e65cf33 100644 --- a/src/main/java/org/redkale/service/Service.java +++ b/src/main/java/org/redkale/service/Service.java @@ -1,60 +1,60 @@ -/* - * 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.service; - -import org.redkale.util.*; - -/** - * 鎵鏈塖ervice鐨勫疄鐜扮被涓嶅緱澹版槑涓篺inal锛 鍏佽杩滅▼妯″紡鐨刾ublic鏂规硶閮戒笉鑳藉0鏄庝负final銆
- * 娉ㄦ剰: "$"鏄竴涓緢鐗规畩鐨凷ervice.name鍊 銆 琚爣璁颁负@Resource(name = "$") 鐨凷ervice鐨勮祫婧愬悕涓庢墍灞炵埗Service鐨勮祫婧愬悕涓鑷淬
- * - *

- * Service鐨勮祫婧愮被鍨
- * 涓氬姟閫昏緫鐨凷ervice閫氬父鏈変袱绉嶇紪鍐欐柟寮忥細
- *    1銆佸彧鍐欎竴涓猄ervice瀹炵幇绫汇
- *    2銆佸厛瀹氫箟涓氬姟鐨凷ervice鎺ュ彛鎴栨娊璞$被锛屽啀缂栧啓鍏蜂綋瀹炵幇绫汇
- * 绗簩绉嶆柟寮忛渶瑕佸湪鍏蜂綋瀹炵幇绫讳笂浣跨敤@ResourceType鎸囨槑璧勬簮娉ㄥ叆鐨勭被鍨嬨
- * 
- * - *
- * 寮傛鏂规硶锛
- * Service缂栧啓寮傛鏂规硶锛
- *    1銆佸紓姝ユ柟娉曟湁涓斾粎鏈変竴涓被鍨嬩负CompletionHandler鐨勫弬鏁帮紝 杩斿洖绫诲瀷蹇呴』鏄痸oid銆傝嫢鍙傛暟绫诲瀷涓篊ompletionHandler瀛愮被锛屽繀椤讳繚璇佸叾瀛愮被鍙缁ф壙涓攃ompleted銆乫ailed鍙閲嶈浇涓斿寘鍚┖鍙傛暟鐨勬瀯閫犲嚱鏁般
- *    2銆佸紓姝ユ柟娉曡繑鍥炵被鍨嬫槸CompletableFuture銆
- * 渚嬪:
- *      public void insertRecord(CompletionHandler<Integer, Record> handler, String name, @RpcAttachment Record record);
- *
- * 
- * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public interface Service { - - /** - * 璇ユ柟娉曞繀椤绘槸鍙互閲嶅璋冪敤锛 褰搑eload鏃堕渶瑕侀噸澶嶈皟鐢╥nit鏂规硶 - * 杩滅▼妯″紡涓嬭鏂规硶浼氶噸杞芥垚绌烘柟娉 - * - * @param config 閰嶇疆鍙傛暟 - */ - default void init(AnyValue config) { - - } - - /** - * 杩涚▼閫鍑烘椂锛岃皟鐢⊿ervice閿姣 - * 杩滅▼妯″紡涓嬭鏂规硶浼氶噸杞芥垚绌烘柟娉 - * 娉ㄦ剰锛 鍦ㄦ鏂规硶鍐呬笉鑳借皟鐢∕essageClient.sendMessage 鏂规硶锛屽洜涓篈pplication鍏抽棴鏃朵細鍏坉estroy鎺塎essageClient - * - * @param config 閰嶇疆鍙傛暟 - */ - default void destroy(AnyValue config) { - - } - -} +/* + * 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.service; + +import org.redkale.util.*; + +/** + * 鎵鏈塖ervice鐨勫疄鐜扮被涓嶅緱澹版槑涓篺inal锛 鍏佽杩滅▼妯″紡鐨刾ublic鏂规硶閮戒笉鑳藉0鏄庝负final銆
+ * 娉ㄦ剰: "$"鏄竴涓緢鐗规畩鐨凷ervice.name鍊 銆 琚爣璁颁负@Resource(name = "$") 鐨凷ervice鐨勮祫婧愬悕涓庢墍灞炵埗Service鐨勮祫婧愬悕涓鑷淬
+ * + *

+ * Service鐨勮祫婧愮被鍨
+ * 涓氬姟閫昏緫鐨凷ervice閫氬父鏈変袱绉嶇紪鍐欐柟寮忥細
+ *    1銆佸彧鍐欎竴涓猄ervice瀹炵幇绫汇
+ *    2銆佸厛瀹氫箟涓氬姟鐨凷ervice鎺ュ彛鎴栨娊璞$被锛屽啀缂栧啓鍏蜂綋瀹炵幇绫汇
+ * 绗簩绉嶆柟寮忛渶瑕佸湪鍏蜂綋瀹炵幇绫讳笂浣跨敤@ResourceType鎸囨槑璧勬簮娉ㄥ叆鐨勭被鍨嬨
+ * 
+ * + *
+ * 寮傛鏂规硶锛
+ * Service缂栧啓寮傛鏂规硶锛
+ *    1銆佸紓姝ユ柟娉曟湁涓斾粎鏈変竴涓被鍨嬩负CompletionHandler鐨勫弬鏁帮紝 杩斿洖绫诲瀷蹇呴』鏄痸oid銆傝嫢鍙傛暟绫诲瀷涓篊ompletionHandler瀛愮被锛屽繀椤讳繚璇佸叾瀛愮被鍙缁ф壙涓攃ompleted銆乫ailed鍙閲嶈浇涓斿寘鍚┖鍙傛暟鐨勬瀯閫犲嚱鏁般
+ *    2銆佸紓姝ユ柟娉曡繑鍥炵被鍨嬫槸CompletableFuture銆
+ * 渚嬪:
+ *      public void insertRecord(CompletionHandler<Integer, Record> handler, String name, @RpcAttachment Record record);
+ *
+ * 
+ * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public interface Service { + + /** + * 璇ユ柟娉曞繀椤绘槸鍙互閲嶅璋冪敤锛 褰搑eload鏃堕渶瑕侀噸澶嶈皟鐢╥nit鏂规硶 + * 杩滅▼妯″紡涓嬭鏂规硶浼氶噸杞芥垚绌烘柟娉 + * + * @param config 閰嶇疆鍙傛暟 + */ + default void init(AnyValue config) { + + } + + /** + * 杩涚▼閫鍑烘椂锛岃皟鐢⊿ervice閿姣 + * 杩滅▼妯″紡涓嬭鏂规硶浼氶噸杞芥垚绌烘柟娉 + * 娉ㄦ剰锛 鍦ㄦ鏂规硶鍐呬笉鑳借皟鐢∕essageClient.sendMessage 鏂规硶锛屽洜涓篈pplication鍏抽棴鏃朵細鍏坉estroy鎺塎essageClient + * + * @param config 閰嶇疆鍙傛暟 + */ + default void destroy(AnyValue config) { + + } + +} diff --git a/src/main/java/org/redkale/service/WebSocketNodeService.java b/src/main/java/org/redkale/service/WebSocketNodeService.java index 4e5539d55..21bbad7ae 100644 --- a/src/main/java/org/redkale/service/WebSocketNodeService.java +++ b/src/main/java/org/redkale/service/WebSocketNodeService.java @@ -1,166 +1,166 @@ -/* - * 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.service; - -import static org.redkale.net.http.WebSocket.*; -import java.io.*; -import java.net.*; -import java.util.*; -import java.util.concurrent.*; -import java.util.logging.Level; -import org.redkale.net.http.*; -import org.redkale.util.*; - -/** - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@AutoLoad(false) -@ResourceType(WebSocketNode.class) -public class WebSocketNodeService extends WebSocketNode implements Service { - - @Override - public void init(AnyValue conf) { - super.init(conf); - } - - @Override - public void destroy(AnyValue conf) { - super.destroy(conf); - } - - public final void setName(String name) { - this.name = name; - } - - @Override - public CompletableFuture> getWebSocketAddresses(@RpcTargetTopic String topic, final @RpcTargetAddress InetSocketAddress targetAddress, final Serializable groupid) { - if ((topic == null || !topic.equals(this.wsNodeAddress.getTopic())) && (localSncpAddress == null || !localSncpAddress.equals(targetAddress))) return remoteWebSocketAddresses(topic, targetAddress, groupid); - if (this.localEngine == null) return CompletableFuture.completedFuture(new ArrayList<>()); - final List rs = new ArrayList<>(); - this.localEngine.getLocalWebSockets(groupid).forEach(x -> rs.add(x.getRemoteAddr())); - return CompletableFuture.completedFuture(rs); - } - - @Override - public CompletableFuture sendMessage(@RpcTargetTopic String topic, @RpcTargetAddress InetSocketAddress targetAddress, Object message, boolean last, Serializable... userids) { - if (this.localEngine == null) return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); - return this.localEngine.sendLocalMessage(message, last, userids); - } - - @Override - public CompletableFuture broadcastMessage(@RpcTargetTopic String topic, @RpcTargetAddress InetSocketAddress targetAddress, final WebSocketRange wsrange, Object message, boolean last) { - if (this.localEngine == null) return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); - return this.localEngine.broadcastLocalMessage(wsrange, message, last); - } - - @Override - public CompletableFuture sendAction(@RpcTargetTopic String topic, @RpcTargetAddress InetSocketAddress targetAddress, final WebSocketAction action, Serializable... userids) { - if (this.localEngine == null) return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); - return this.localEngine.sendLocalAction(action, userids); - } - - @Override - public CompletableFuture broadcastAction(@RpcTargetTopic String topic, @RpcTargetAddress InetSocketAddress targetAddress, final WebSocketAction action) { - if (this.localEngine == null) return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); - return this.localEngine.broadcastLocalAction(action); - } - - @Override - public CompletableFuture getUserSize(@RpcTargetTopic String topic, @RpcTargetAddress InetSocketAddress targetAddress) { - if (this.localEngine == null) return CompletableFuture.completedFuture(0); - return CompletableFuture.completedFuture(this.localEngine.getLocalUserSize()); - } - - /** - * 褰撶敤鎴疯繛鎺ュ埌鑺傜偣锛岄渶瑕佹洿鏂板埌CacheSource - * - * @param userid Serializable - * @param wsaddr WebSocketAddress - * - * @return 鏃犺繑鍥炲 - */ - @Override - public CompletableFuture connect(Serializable userid, WebSocketAddress wsaddr) { - tryAcquireSemaphore(); - CompletableFuture future = source.appendSetItemAsync(WS_SOURCE_KEY_USERID_PREFIX + userid, WebSocketAddress.class, wsaddr); - if (semaphore != null) future.whenComplete((r, e) -> releaseSemaphore()); - if (logger.isLoggable(Level.FINEST)) logger.finest(WebSocketNodeService.class.getSimpleName() + ".event: " + userid + " connect from " + wsaddr); - return future; - } - - /** - * 褰撶敤鎴蜂粠涓涓妭鐐规柇鎺変簡鎵鏈夌殑杩炴帴锛岄渶瑕佷粠CacheSource涓垹闄 - * - * @param userid Serializable - * @param wsaddr WebSocketAddress - * - * @return 鏃犺繑鍥炲 - */ - @Override - public CompletableFuture disconnect(Serializable userid, WebSocketAddress wsaddr) { - tryAcquireSemaphore(); - CompletableFuture future = source.removeSetItemAsync(WS_SOURCE_KEY_USERID_PREFIX + userid, WebSocketAddress.class, wsaddr); - if (semaphore != null) future.whenComplete((r, e) -> releaseSemaphore()); - if (logger.isLoggable(Level.FINEST)) logger.finest(WebSocketNodeService.class.getSimpleName() + ".event: " + userid + " disconnect from " + wsaddr); - return future.thenApply(v -> null); - } - - /** - * 鏇存敼鐢ㄦ埛ID锛岄渶瑕佹洿鏂板埌CacheSource - * - * @param olduserid Serializable - * @param newuserid Serializable - * @param wsaddr WebSocketAddress - * - * @return 鏃犺繑鍥炲 - */ - @Override - public CompletableFuture changeUserid(Serializable olduserid, Serializable newuserid, WebSocketAddress wsaddr) { - tryAcquireSemaphore(); - CompletableFuture future = source.appendSetItemAsync(WS_SOURCE_KEY_USERID_PREFIX + newuserid, WebSocketAddress.class, wsaddr); - future = future.thenAccept((a) -> source.removeSetItemAsync(WS_SOURCE_KEY_USERID_PREFIX + olduserid, WebSocketAddress.class, wsaddr)); - if (semaphore != null) future.whenComplete((r, e) -> releaseSemaphore()); - if (logger.isLoggable(Level.FINEST)) logger.finest(WebSocketNodeService.class.getSimpleName() + ".event: " + olduserid + " changeUserid to " + newuserid + " from " + wsaddr); - return future; - } - - /** - * 鍒ゆ柇鐢ㄦ埛鏄惁鏈塛ebSocket - * - * @param userid Serializable - * @param topic RpcTargetTopic - * @param targetAddress InetSocketAddress - * - * @return 鏃犺繑鍥炲 - */ - @Override - public CompletableFuture existsWebSocket(Serializable userid, @RpcTargetTopic String topic, @RpcTargetAddress InetSocketAddress targetAddress) { - if (logger.isLoggable(Level.FINEST)) logger.finest(WebSocketNodeService.class.getSimpleName() + ".event: " + userid + " existsWebSocket from " + targetAddress); - if (localEngine == null) return CompletableFuture.completedFuture(false); - return CompletableFuture.completedFuture(localEngine.existsLocalWebSocket(userid)); - } - - /** - * 寮哄埗鍏抽棴鐢ㄦ埛鐨刉ebSocket - * - * @param userid Serializable - * @param topic RpcTargetTopic - * @param targetAddress InetSocketAddress - * - * @return 鏃犺繑鍥炲 - */ - @Override - public CompletableFuture forceCloseWebSocket(Serializable userid, @RpcTargetTopic String topic, @RpcTargetAddress InetSocketAddress targetAddress) { - //涓嶈兘浠巗ncpNodeAddresses涓Щ闄わ紝鍥犱负engine.forceCloseWebSocket 浼氳皟鐢ㄥ埌disconnect - if (logger.isLoggable(Level.FINEST)) logger.finest(WebSocketNodeService.class.getSimpleName() + ".event: " + userid + " forceCloseWebSocket from " + targetAddress); - if (localEngine == null) return CompletableFuture.completedFuture(0); - return CompletableFuture.completedFuture(localEngine.forceCloseLocalWebSocket(userid)); - } -} +/* + * 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.service; + +import static org.redkale.net.http.WebSocket.*; +import java.io.*; +import java.net.*; +import java.util.*; +import java.util.concurrent.*; +import java.util.logging.Level; +import org.redkale.net.http.*; +import org.redkale.util.*; + +/** + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@AutoLoad(false) +@ResourceType(WebSocketNode.class) +public class WebSocketNodeService extends WebSocketNode implements Service { + + @Override + public void init(AnyValue conf) { + super.init(conf); + } + + @Override + public void destroy(AnyValue conf) { + super.destroy(conf); + } + + public final void setName(String name) { + this.name = name; + } + + @Override + public CompletableFuture> getWebSocketAddresses(@RpcTargetTopic String topic, final @RpcTargetAddress InetSocketAddress targetAddress, final Serializable groupid) { + if ((topic == null || !topic.equals(this.wsNodeAddress.getTopic())) && (localSncpAddress == null || !localSncpAddress.equals(targetAddress))) return remoteWebSocketAddresses(topic, targetAddress, groupid); + if (this.localEngine == null) return CompletableFuture.completedFuture(new ArrayList<>()); + final List rs = new ArrayList<>(); + this.localEngine.getLocalWebSockets(groupid).forEach(x -> rs.add(x.getRemoteAddr())); + return CompletableFuture.completedFuture(rs); + } + + @Override + public CompletableFuture sendMessage(@RpcTargetTopic String topic, @RpcTargetAddress InetSocketAddress targetAddress, Object message, boolean last, Serializable... userids) { + if (this.localEngine == null) return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); + return this.localEngine.sendLocalMessage(message, last, userids); + } + + @Override + public CompletableFuture broadcastMessage(@RpcTargetTopic String topic, @RpcTargetAddress InetSocketAddress targetAddress, final WebSocketRange wsrange, Object message, boolean last) { + if (this.localEngine == null) return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); + return this.localEngine.broadcastLocalMessage(wsrange, message, last); + } + + @Override + public CompletableFuture sendAction(@RpcTargetTopic String topic, @RpcTargetAddress InetSocketAddress targetAddress, final WebSocketAction action, Serializable... userids) { + if (this.localEngine == null) return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); + return this.localEngine.sendLocalAction(action, userids); + } + + @Override + public CompletableFuture broadcastAction(@RpcTargetTopic String topic, @RpcTargetAddress InetSocketAddress targetAddress, final WebSocketAction action) { + if (this.localEngine == null) return CompletableFuture.completedFuture(RETCODE_GROUP_EMPTY); + return this.localEngine.broadcastLocalAction(action); + } + + @Override + public CompletableFuture getUserSize(@RpcTargetTopic String topic, @RpcTargetAddress InetSocketAddress targetAddress) { + if (this.localEngine == null) return CompletableFuture.completedFuture(0); + return CompletableFuture.completedFuture(this.localEngine.getLocalUserSize()); + } + + /** + * 褰撶敤鎴疯繛鎺ュ埌鑺傜偣锛岄渶瑕佹洿鏂板埌CacheSource + * + * @param userid Serializable + * @param wsaddr WebSocketAddress + * + * @return 鏃犺繑鍥炲 + */ + @Override + public CompletableFuture connect(Serializable userid, WebSocketAddress wsaddr) { + tryAcquireSemaphore(); + CompletableFuture future = source.appendSetItemAsync(WS_SOURCE_KEY_USERID_PREFIX + userid, WebSocketAddress.class, wsaddr); + if (semaphore != null) future.whenComplete((r, e) -> releaseSemaphore()); + if (logger.isLoggable(Level.FINEST)) logger.finest(WebSocketNodeService.class.getSimpleName() + ".event: " + userid + " connect from " + wsaddr); + return future; + } + + /** + * 褰撶敤鎴蜂粠涓涓妭鐐规柇鎺変簡鎵鏈夌殑杩炴帴锛岄渶瑕佷粠CacheSource涓垹闄 + * + * @param userid Serializable + * @param wsaddr WebSocketAddress + * + * @return 鏃犺繑鍥炲 + */ + @Override + public CompletableFuture disconnect(Serializable userid, WebSocketAddress wsaddr) { + tryAcquireSemaphore(); + CompletableFuture future = source.removeSetItemAsync(WS_SOURCE_KEY_USERID_PREFIX + userid, WebSocketAddress.class, wsaddr); + if (semaphore != null) future.whenComplete((r, e) -> releaseSemaphore()); + if (logger.isLoggable(Level.FINEST)) logger.finest(WebSocketNodeService.class.getSimpleName() + ".event: " + userid + " disconnect from " + wsaddr); + return future.thenApply(v -> null); + } + + /** + * 鏇存敼鐢ㄦ埛ID锛岄渶瑕佹洿鏂板埌CacheSource + * + * @param olduserid Serializable + * @param newuserid Serializable + * @param wsaddr WebSocketAddress + * + * @return 鏃犺繑鍥炲 + */ + @Override + public CompletableFuture changeUserid(Serializable olduserid, Serializable newuserid, WebSocketAddress wsaddr) { + tryAcquireSemaphore(); + CompletableFuture future = source.appendSetItemAsync(WS_SOURCE_KEY_USERID_PREFIX + newuserid, WebSocketAddress.class, wsaddr); + future = future.thenAccept((a) -> source.removeSetItemAsync(WS_SOURCE_KEY_USERID_PREFIX + olduserid, WebSocketAddress.class, wsaddr)); + if (semaphore != null) future.whenComplete((r, e) -> releaseSemaphore()); + if (logger.isLoggable(Level.FINEST)) logger.finest(WebSocketNodeService.class.getSimpleName() + ".event: " + olduserid + " changeUserid to " + newuserid + " from " + wsaddr); + return future; + } + + /** + * 鍒ゆ柇鐢ㄦ埛鏄惁鏈塛ebSocket + * + * @param userid Serializable + * @param topic RpcTargetTopic + * @param targetAddress InetSocketAddress + * + * @return 鏃犺繑鍥炲 + */ + @Override + public CompletableFuture existsWebSocket(Serializable userid, @RpcTargetTopic String topic, @RpcTargetAddress InetSocketAddress targetAddress) { + if (logger.isLoggable(Level.FINEST)) logger.finest(WebSocketNodeService.class.getSimpleName() + ".event: " + userid + " existsWebSocket from " + targetAddress); + if (localEngine == null) return CompletableFuture.completedFuture(false); + return CompletableFuture.completedFuture(localEngine.existsLocalWebSocket(userid)); + } + + /** + * 寮哄埗鍏抽棴鐢ㄦ埛鐨刉ebSocket + * + * @param userid Serializable + * @param topic RpcTargetTopic + * @param targetAddress InetSocketAddress + * + * @return 鏃犺繑鍥炲 + */ + @Override + public CompletableFuture forceCloseWebSocket(Serializable userid, @RpcTargetTopic String topic, @RpcTargetAddress InetSocketAddress targetAddress) { + //涓嶈兘浠巗ncpNodeAddresses涓Щ闄わ紝鍥犱负engine.forceCloseWebSocket 浼氳皟鐢ㄥ埌disconnect + if (logger.isLoggable(Level.FINEST)) logger.finest(WebSocketNodeService.class.getSimpleName() + ".event: " + userid + " forceCloseWebSocket from " + targetAddress); + if (localEngine == null) return CompletableFuture.completedFuture(0); + return CompletableFuture.completedFuture(localEngine.forceCloseLocalWebSocket(userid)); + } +} diff --git a/src/main/java/org/redkale/service/package-info.java b/src/main/java/org/redkale/service/package-info.java index 37b2e9cf7..0bf67060d 100644 --- a/src/main/java/org/redkale/service/package-info.java +++ b/src/main/java/org/redkale/service/package-info.java @@ -1,4 +1,4 @@ -/** - * Service鎺ュ彛鍜屾ā寮忛厤缃寘 - */ -package org.redkale.service; +/** + * Service鎺ュ彛鍜屾ā寮忛厤缃寘 + */ +package org.redkale.service; diff --git a/src/main/java/org/redkale/source/CacheMemorySource.java b/src/main/java/org/redkale/source/CacheMemorySource.java index b616bdb81..7bee93cc3 100644 --- a/src/main/java/org/redkale/source/CacheMemorySource.java +++ b/src/main/java/org/redkale/source/CacheMemorySource.java @@ -1,1431 +1,1431 @@ -/* - * 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.source; - -import java.io.*; -import java.lang.reflect.Type; -import java.util.*; -import java.util.concurrent.*; -import java.util.concurrent.atomic.AtomicLong; -import java.util.function.*; -import java.util.logging.*; -import javax.annotation.Resource; -import org.redkale.convert.*; -import org.redkale.convert.json.*; -import org.redkale.service.*; -import org.redkale.util.*; - -/** - * CacheSource鐨勯粯璁ゅ疄鐜--鍐呭瓨缂撳瓨 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@Local -@AutoLoad(false) -@SuppressWarnings("unchecked") -@ResourceType(CacheSource.class) -public final class CacheMemorySource extends AbstractService implements CacheSource, Service, AutoCloseable, Resourcable { - - @Resource - private JsonConvert defaultConvert; - - @Resource(name = "$_convert") - private JsonConvert convert; - - private String name; - - private ScheduledThreadPoolExecutor scheduler; - - private Consumer expireHandler; - - private final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); - - protected final ConcurrentHashMap> container = new ConcurrentHashMap<>(); - - protected final BiConsumer futureCompleteConsumer = (r, t) -> { - if (t != null) logger.log(Level.SEVERE, "CompletableFuture complete error", (Throwable) t); - }; - - public CacheMemorySource(String resourceName) { - this.name = resourceName; - } - - @Override - public final String getType() { - return "memory"; - } - - @Override - public String toString() { - return "CacheMemorySource(type=memory, name='" + resourceName() + "')"; - } - - @Override //ServiceLoader鏃跺垽鏂厤缃槸鍚︾鍚堝綋鍓嶅疄鐜扮被 - public boolean acceptsConf(AnyValue config) { - return false; - } - - @Override - @SuppressWarnings("unchecked") - public void init(AnyValue conf) { - if (this.convert == null) this.convert = this.defaultConvert; - if (this.convert == null) this.convert = JsonConvert.root(); - final CacheMemorySource self = this; - AnyValue prop = conf == null ? null : conf.getAnyValue("properties"); - String expireHandlerClass = prop == null ? null : prop.getValue("expirehandler"); - if (expireHandlerClass != null) { - try { - Class clazz = Thread.currentThread().getContextClassLoader().loadClass(expireHandlerClass); - this.expireHandler = (Consumer) clazz.getDeclaredConstructor().newInstance(); - RedkaleClassLoader.putReflectionDeclaredConstructors(clazz, expireHandlerClass); - } catch (Throwable e) { - logger.log(Level.SEVERE, self.getClass().getSimpleName() + " new expirehandler class (" + expireHandlerClass + ") instance error", e); - } - } - if (scheduler == null) { - this.scheduler = new ScheduledThreadPoolExecutor(1, (Runnable r) -> { - final Thread t = new Thread(r, "Redkale-" + self.getClass().getSimpleName() + "-Expirer-Thread"); - t.setDaemon(true); - return t; - }); - final List keys = new ArrayList<>(); - scheduler.scheduleWithFixedDelay(() -> { - try { - keys.clear(); - int now = (int) (System.currentTimeMillis() / 1000); - container.forEach((k, x) -> { - if (x.expireSeconds > 0 && (now > (x.lastAccessed + x.expireSeconds))) { - keys.add(x.key); - } - }); - for (String key : keys) { - CacheEntry entry = container.remove(key); - if (expireHandler != null && entry != null) expireHandler.accept(entry); - } - } catch (Throwable t) { - logger.log(Level.SEVERE, "CacheMemorySource schedule(interval=" + 10 + "s) error", t); - } - }, 10, 10, TimeUnit.SECONDS); - if (logger.isLoggable(Level.FINEST)) logger.finest(self.getClass().getSimpleName() + ":" + self.resourceName() + " start schedule expire executor"); - } - } - - @Override - public void close() throws Exception { //缁橝pplication 鍏抽棴鏃惰皟鐢 - destroy(null); - } - - @Override - public String resourceName() { - return name; - } - - @Override - public void destroy(AnyValue conf) { - if (scheduler != null) scheduler.shutdownNow(); - } - - //----------- hxxx -------------- - @Override - public int hremove(final String key, String... fields) { - int count = 0; - CacheEntry entry = container.get(key); - if (entry == null || entry.mapValue == null) return 0; - for (String field : fields) { - if (entry.mapValue.remove(field) != null) count++; - } - return count; - } - - @Override - public List hkeys(final String key) { - List list = new ArrayList<>(); - CacheEntry entry = container.get(key); - if (entry == null || entry.mapValue == null) return list; - list.addAll(entry.mapValue.keySet()); - return list; - } - - @Override - public int hsize(final String key) { - CacheEntry entry = container.get(key); - if (entry == null || entry.mapValue == null) return 0; - return entry.mapValue.keySet().size(); - } - - @Override - public long hincr(final String key, String field) { - return hincr(key, field, 1); - } - - @Override - public long hincr(final String key, String field, long num) { - CacheEntry entry = container.get(key); - if (entry == null) { - synchronized (container) { - entry = container.get(key); - if (entry == null) { - ConcurrentHashMap map = new ConcurrentHashMap(); - map.put(field, new AtomicLong()); - entry = new CacheEntry(CacheEntryType.MAP, key, new AtomicLong(), null, null, map); - container.put(key, entry); - } - } - } - Serializable val = (Serializable) entry.mapValue.computeIfAbsent(field, f -> new AtomicLong()); - if (!(val instanceof AtomicLong)) { - synchronized (entry.mapValue) { - if (!(val instanceof AtomicLong)) { - if (val == null) { - val = new AtomicLong(); - } else { - val = new AtomicLong(((Number) val).longValue()); - } - entry.mapValue.put(field, val); - } - } - } - return ((AtomicLong) entry.mapValue.get(field)).addAndGet(num); - } - - @Override - public long hdecr(final String key, String field) { - return hincr(key, field, -1); - } - - @Override - public long hdecr(final String key, String field, long num) { - return hincr(key, field, -num); - } - - @Override - public boolean hexists(final String key, String field) { - if (key == null) return false; - CacheEntry entry = container.get(key); - if (entry == null || entry.isExpired() || entry.mapValue == null) return false; - return entry.mapValue.contains(field); - } - - @Override - public void hset(final String key, final String field, final Convert convert, final T value) { - hset(CacheEntryType.MAP, key, field, value); - } - - @Override - public void hset(final String key, final String field, final Type type, final T value) { - hset(CacheEntryType.MAP, key, field, value); - } - - @Override - public void hset(final String key, final String field, final Convert convert, final Type type, final T value) { - hset(CacheEntryType.MAP, key, field, value); - } - - @Override - public void hsetString(final String key, final String field, final String value) { - hset(CacheEntryType.MAP, key, field, value); - } - - @Override - public void hsetLong(final String key, final String field, final long value) { - hset(CacheEntryType.MAP, key, field, value); - } - - @Override - public void hmset(final String key, final Serializable... values) { - for (int i = 0; i < values.length; i += 2) { - hset(CacheEntryType.MAP, key, (String) values[i], values[i + 1]); - } - } - - @Override - public List hmget(final String key, final Type type, final String... fields) { - if (key == null) return null; - CacheEntry entry = container.get(key); - if (entry == null || entry.isExpired() || entry.mapValue == null) return null; - List rs = new ArrayList<>(fields.length); - for (int i = 0; i < fields.length; i++) { - Serializable val = (Serializable) entry.mapValue.get(fields[i]); - if (type == String.class) { - rs.add(val == null ? null : (T) String.valueOf(val)); - } else { - rs.add((T) val); - } - } - return rs; - } - - @Override - public Map hmap(final String key, final Type type, int offset, int limit) { - return hmap(key, type, offset, limit, null); - } - - @Override - public Map hmap(final String key, final Type type, int offset, int limit, String pattern) { - if (key == null) return new HashMap(); - CacheEntry entry = container.get(key); - if (entry == null || entry.isExpired() || entry.mapValue == null) return new HashMap(); - return new HashMap(entry.mapValue); - } - - @Override - public T hget(final String key, final String field, final Type type) { - if (key == null) return null; - CacheEntry entry = container.get(key); - if (entry == null || entry.isExpired() || entry.mapValue == null) return null; - return (T) entry.mapValue.get(field); - } - - @Override - public String hgetString(final String key, final String field) { - if (key == null) return null; - CacheEntry entry = container.get(key); - if (entry == null || entry.isExpired() || entry.mapValue == null) return null; - return (String) entry.mapValue.get(field); - } - - @Override - public long hgetLong(final String key, final String field, long defValue) { - if (key == null) return defValue; - CacheEntry entry = container.get(key); - if (entry == null || entry.isExpired() || entry.mapValue == null) return defValue; - return ((Number) entry.mapValue.getOrDefault(field, defValue)).longValue(); - } - //----------- hxxx -------------- - - @Override - public boolean exists(String key) { - if (key == null) return false; - CacheEntry entry = container.get(key); - if (entry == null) return false; - return !entry.isExpired(); - } - - @Override - public CompletableFuture existsAsync(final String key) { - return CompletableFuture.supplyAsync(() -> exists(key), getExecutor()); - } - - @Override - public T get(final String key, final Type type) { - if (key == null) return null; - CacheEntry entry = container.get(key); - if (entry == null || entry.isExpired()) return null; - if (entry.isListCacheType()) return (T) (entry.listValue == null ? null : new ArrayList(entry.listValue)); - if (entry.isSetCacheType()) return (T) (entry.csetValue == null ? null : new HashSet(entry.csetValue)); - return (T) entry.objectValue; - } - - @Override - public String getString(String key) { - if (key == null) return null; - CacheEntry entry = container.get(key); - if (entry == null || entry.isExpired()) return null; - return (String) entry.objectValue; - } - - @Override - public long getLong(String key, long defValue) { - if (key == null) return defValue; - CacheEntry entry = container.get(key); - if (entry == null || entry.isExpired()) return defValue; - return entry.objectValue == null ? defValue : (entry.objectValue instanceof AtomicLong ? ((AtomicLong) entry.objectValue).get() : (Long) entry.objectValue); - } - //----------- hxxx -------------- - - @Override - public CompletableFuture hremoveAsync(final String key, String... fields) { - return CompletableFuture.supplyAsync(() -> hremove(key, fields), getExecutor()); - } - - @Override - public CompletableFuture> hkeysAsync(final String key) { - return CompletableFuture.supplyAsync(() -> hkeys(key), getExecutor()); - } - - @Override - public CompletableFuture hsizeAsync(final String key) { - return CompletableFuture.supplyAsync(() -> hsize(key), getExecutor()); - } - - @Override - public CompletableFuture hincrAsync(final String key, String field) { - return CompletableFuture.supplyAsync(() -> hincr(key, field), getExecutor()); - } - - @Override - public CompletableFuture hincrAsync(final String key, String field, long num) { - return CompletableFuture.supplyAsync(() -> hincr(key, field, num), getExecutor()); - } - - @Override - public CompletableFuture hdecrAsync(final String key, String field) { - return CompletableFuture.supplyAsync(() -> hdecr(key, field), getExecutor()); - } - - @Override - public CompletableFuture hdecrAsync(final String key, String field, long num) { - return CompletableFuture.supplyAsync(() -> hdecr(key, field, num), getExecutor()); - } - - @Override - public CompletableFuture hexistsAsync(final String key, String field) { - return CompletableFuture.supplyAsync(() -> hexists(key, field), getExecutor()); - } - - @Override - public CompletableFuture hsetAsync(final String key, final String field, final Convert convert, final T value) { - return CompletableFuture.runAsync(() -> hset(key, field, convert, value), getExecutor()).whenComplete(futureCompleteConsumer); - } - - @Override - public CompletableFuture hsetAsync(final String key, final String field, final Type type, final T value) { - return CompletableFuture.runAsync(() -> hset(key, field, type, value), getExecutor()).whenComplete(futureCompleteConsumer); - } - - @Override - public CompletableFuture hsetAsync(final String key, final String field, final Convert convert, final Type type, final T value) { - return CompletableFuture.runAsync(() -> hset(key, field, convert, type, value), getExecutor()).whenComplete(futureCompleteConsumer); - } - - @Override - public CompletableFuture hsetStringAsync(final String key, final String field, final String value) { - return CompletableFuture.runAsync(() -> hsetString(key, field, value), getExecutor()).whenComplete(futureCompleteConsumer); - } - - @Override - public CompletableFuture hsetLongAsync(final String key, final String field, final long value) { - return CompletableFuture.runAsync(() -> hsetLong(key, field, value), getExecutor()).whenComplete(futureCompleteConsumer); - } - - @Override - public CompletableFuture hmsetAsync(final String key, final Serializable... values) { - return CompletableFuture.runAsync(() -> hmset(key, values), getExecutor()).whenComplete(futureCompleteConsumer); - } - - @Override - public CompletableFuture> hmgetAsync(final String key, final Type type, final String... fields) { - return CompletableFuture.supplyAsync(() -> hmget(key, type, fields), getExecutor()); - } - - @Override - public CompletableFuture> hmapAsync(final String key, final Type type, int offset, int limit) { - return CompletableFuture.supplyAsync(() -> hmap(key, type, offset, limit), getExecutor()); - } - - @Override - public CompletableFuture> hmapAsync(final String key, final Type type, int offset, int limit, String pattern) { - return CompletableFuture.supplyAsync(() -> hmap(key, type, offset, limit, pattern), getExecutor()); - } - - @Override - public CompletableFuture hgetAsync(final String key, final String field, final Type type) { - return CompletableFuture.supplyAsync(() -> hget(key, field, type), getExecutor()); - } - - @Override - public CompletableFuture hgetStringAsync(final String key, final String field) { - return CompletableFuture.supplyAsync(() -> hgetString(key, field), getExecutor()); - } - - @Override - public CompletableFuture hgetLongAsync(final String key, final String field, long defValue) { - return CompletableFuture.supplyAsync(() -> hgetLong(key, field, defValue), getExecutor()); - } - - //----------- hxxx -------------- - @Override - public CompletableFuture getAsync(final String key, final Type type) { - return CompletableFuture.supplyAsync(() -> (T) get(key, type), getExecutor()); - } - - @Override - public CompletableFuture getStringAsync(final String key) { - return CompletableFuture.supplyAsync(() -> getString(key), getExecutor()); - } - - @Override - public CompletableFuture getLongAsync(final String key, long defValue) { - return CompletableFuture.supplyAsync(() -> getLong(key, defValue), getExecutor()); - } - - @Override - public T getAndRefresh(final String key, final int expireSeconds, final Type type) { - if (key == null) return null; - CacheEntry entry = container.get(key); - if (entry == null || entry.isExpired()) return null; - entry.lastAccessed = (int) (System.currentTimeMillis() / 1000); - entry.expireSeconds = expireSeconds; - if (entry.isListCacheType()) return (T) (entry.listValue == null ? null : new ArrayList(entry.listValue)); - if (entry.isSetCacheType()) return (T) (entry.csetValue == null ? null : new HashSet(entry.csetValue)); - return (T) entry.objectValue; - } - - @Override - @SuppressWarnings("unchecked") - public String getStringAndRefresh(String key, final int expireSeconds) { - if (key == null) return null; - CacheEntry entry = container.get(key); - if (entry == null || entry.isExpired()) return null; - entry.lastAccessed = (int) (System.currentTimeMillis() / 1000); - entry.expireSeconds = expireSeconds; - return (String) entry.objectValue; - } - - @Override - public long getLongAndRefresh(String key, final int expireSeconds, long defValue) { - if (key == null) return defValue; - CacheEntry entry = container.get(key); - if (entry == null || entry.isExpired()) return defValue; - entry.lastAccessed = (int) (System.currentTimeMillis() / 1000); - entry.expireSeconds = expireSeconds; - return entry.objectValue == null ? defValue : (entry.objectValue instanceof AtomicLong ? ((AtomicLong) entry.objectValue).get() : (Long) entry.objectValue); - - } - - @Override - public CompletableFuture getAndRefreshAsync(final String key, final int expireSeconds, final Type type) { - return CompletableFuture.supplyAsync(() -> getAndRefresh(key, expireSeconds, type), getExecutor()); - } - - @Override - public CompletableFuture getStringAndRefreshAsync(final String key, final int expireSeconds) { - return CompletableFuture.supplyAsync(() -> getStringAndRefresh(key, expireSeconds), getExecutor()); - } - - @Override - public CompletableFuture getLongAndRefreshAsync(final String key, final int expireSeconds, long defValue) { - return CompletableFuture.supplyAsync(() -> getLongAndRefresh(key, expireSeconds, defValue), getExecutor()); - } - - @Override - public void refresh(String key, final int expireSeconds) { - if (key == null) return; - CacheEntry entry = container.get(key); - if (entry == null) return; - entry.lastAccessed = (int) (System.currentTimeMillis() / 1000); - entry.expireSeconds = expireSeconds; - } - - @Override - public CompletableFuture refreshAsync(final String key, final int expireSeconds) { - return CompletableFuture.runAsync(() -> refresh(key, expireSeconds), getExecutor()).whenComplete(futureCompleteConsumer); - } - - protected void set(CacheEntryType cacheType, String key, Object value) { - if (key == null) return; - CacheEntry entry = container.get(key); - if (entry == null) { - entry = new CacheEntry(cacheType, key, value, null, null, null); - container.putIfAbsent(key, entry); - } else { - entry.expireSeconds = 0; - entry.objectValue = value; - entry.lastAccessed = (int) (System.currentTimeMillis() / 1000); - } - } - - protected void hset(CacheEntryType cacheType, String key, String field, Object value) { - if (key == null) return; - CacheEntry entry = container.get(key); - if (entry == null) { - entry = new CacheEntry(CacheEntryType.MAP, key, value, null, null, new ConcurrentHashMap<>()); - container.putIfAbsent(key, entry); - entry.mapValue.put(field, value); - } else { - entry.expireSeconds = 0; - entry.mapValue.put(field, value); - entry.lastAccessed = (int) (System.currentTimeMillis() / 1000); - } - } - - @Override - public void set(String key, Convert convert, T value) { - set(CacheEntryType.OBJECT, key, value); - } - - @Override - public void set(String key, Type type, T value) { - set(CacheEntryType.OBJECT, key, value); - } - - @Override - public void set(String key, Convert convert, Type type, T value) { - set(CacheEntryType.OBJECT, key, value); - } - - @Override - public void setString(String key, String value) { - set(CacheEntryType.STRING, key, value); - } - - @Override - public void setLong(String key, long value) { - set(CacheEntryType.LONG, key, value); - } - - @Override - public CompletableFuture setAsync(String key, Convert convert, T value) { - return CompletableFuture.runAsync(() -> set(key, convert, value), getExecutor()).whenComplete(futureCompleteConsumer); - } - - @Override - public CompletableFuture setAsync(String key, Type type, T value) { - return CompletableFuture.runAsync(() -> set(key, type, value), getExecutor()).whenComplete(futureCompleteConsumer); - } - - @Override - public CompletableFuture setAsync(String key, Convert convert, Type type, T value) { - return CompletableFuture.runAsync(() -> set(key, convert, type, value), getExecutor()).whenComplete(futureCompleteConsumer); - } - - @Override - public CompletableFuture setStringAsync(String key, String value) { - return CompletableFuture.runAsync(() -> setString(key, value), getExecutor()).whenComplete(futureCompleteConsumer); - } - - @Override - public CompletableFuture setLongAsync(String key, long value) { - return CompletableFuture.runAsync(() -> setLong(key, value), getExecutor()).whenComplete(futureCompleteConsumer); - } - - protected void set(CacheEntryType cacheType, int expireSeconds, String key, Object value) { - if (key == null) return; - CacheEntry entry = container.get(key); - if (entry == null) { - entry = new CacheEntry(cacheType, expireSeconds, key, value, null, null, null); - container.putIfAbsent(key, entry); - } else { - if (expireSeconds > 0) entry.expireSeconds = expireSeconds; - entry.lastAccessed = (int) (System.currentTimeMillis() / 1000); - entry.objectValue = value; - } - } - - @Override - public void set(final int expireSeconds, String key, Convert convert, T value) { - set(CacheEntryType.OBJECT, expireSeconds, key, value); - } - - @Override - public void set(final int expireSeconds, String key, Type type, T value) { - set(CacheEntryType.OBJECT, expireSeconds, key, value); - } - - @Override - public void set(final int expireSeconds, String key, Convert convert, Type type, T value) { - set(CacheEntryType.OBJECT, expireSeconds, key, value); - } - - @Override - public void setString(int expireSeconds, String key, String value) { - set(CacheEntryType.STRING, expireSeconds, key, value); - } - - @Override - public void setLong(int expireSeconds, String key, long value) { - set(CacheEntryType.LONG, expireSeconds, key, value); - } - - @Override - public CompletableFuture setAsync(int expireSeconds, String key, Convert convert, T value) { - return CompletableFuture.runAsync(() -> set(expireSeconds, key, convert, value), getExecutor()).whenComplete(futureCompleteConsumer); - } - - @Override - public CompletableFuture setAsync(int expireSeconds, String key, Type type, T value) { - return CompletableFuture.runAsync(() -> set(expireSeconds, key, type, value), getExecutor()).whenComplete(futureCompleteConsumer); - } - - @Override - public CompletableFuture setAsync(int expireSeconds, String key, Convert convert, Type type, T value) { - return CompletableFuture.runAsync(() -> set(expireSeconds, key, convert, type, value), getExecutor()).whenComplete(futureCompleteConsumer); - } - - @Override - public CompletableFuture setStringAsync(int expireSeconds, String key, String value) { - return CompletableFuture.runAsync(() -> setString(expireSeconds, key, value), getExecutor()).whenComplete(futureCompleteConsumer); - } - - @Override - public CompletableFuture setLongAsync(int expireSeconds, String key, long value) { - return CompletableFuture.runAsync(() -> setLong(expireSeconds, key, value), getExecutor()).whenComplete(futureCompleteConsumer); - } - - @Override - public void setExpireSeconds(String key, int expireSeconds) { - if (key == null) return; - CacheEntry entry = container.get(key); - if (entry == null) return; - entry.expireSeconds = expireSeconds; - } - - @Override - public CompletableFuture setExpireSecondsAsync(final String key, final int expireSeconds) { - return CompletableFuture.runAsync(() -> setExpireSeconds(key, expireSeconds), getExecutor()).whenComplete(futureCompleteConsumer); - } - - @Override - public int remove(String key) { - if (key == null) return 0; - return container.remove(key) == null ? 0 : 1; - } - - @Override - public long incr(final String key) { - return incr(key, 1); - } - - @Override - public CompletableFuture incrAsync(final String key) { - return CompletableFuture.supplyAsync(() -> incr(key), getExecutor()).whenComplete(futureCompleteConsumer); - } - - @Override - public long incr(final String key, long num) { - CacheEntry entry = container.get(key); - if (entry == null) { - synchronized (container) { - entry = container.get(key); - if (entry == null) { - entry = new CacheEntry(CacheEntryType.ATOMIC, key, new AtomicLong(), null, null, null); - container.put(key, entry); - } - } - } - return ((AtomicLong) entry.objectValue).addAndGet(num); - } - - @Override - public CompletableFuture incrAsync(final String key, long num) { - return CompletableFuture.supplyAsync(() -> incr(key, num), getExecutor()).whenComplete(futureCompleteConsumer); - } - - @Override - public long decr(final String key) { - return incr(key, -1); - } - - @Override - public CompletableFuture decrAsync(final String key) { - return CompletableFuture.supplyAsync(() -> decr(key), getExecutor()).whenComplete(futureCompleteConsumer); - } - - @Override - public long decr(final String key, long num) { - return incr(key, -num); - } - - @Override - public CompletableFuture decrAsync(final String key, long num) { - return CompletableFuture.supplyAsync(() -> decr(key, num), getExecutor()).whenComplete(futureCompleteConsumer); - } - - @Override - public CompletableFuture removeAsync(final String key) { - return CompletableFuture.supplyAsync(() -> remove(key), getExecutor()).whenComplete(futureCompleteConsumer); - } - - @Override - public Collection getCollection(final String key, final Type componentType) { - return (Collection) get(key, componentType); - } - - @Override - public Map> getCollectionMap(final boolean set, final Type componentType, final String... keys) { - Map> map = new HashMap<>(); - for (String key : keys) { - Collection s = (Collection) get(key, componentType); - if (s != null) map.put(key, s); - } - return map; - } - - @Override - public Collection getStringCollection(final String key) { - return (Collection) get(key, String.class); - } - - @Override - public Map> getStringCollectionMap(final boolean set, final String... keys) { - Map> map = new HashMap<>(); - for (String key : keys) { - Collection s = (Collection) get(key, String.class); - if (s != null) map.put(key, s); - } - return map; - } - - @Override - public Map getLongMap(final String... keys) { - Map map = new LinkedHashMap<>(); - for (String key : keys) { - Number n = (Number) get(key, long.class); - map.put(key, n == null ? null : n.longValue()); - } - return map; - } - - @Override - public Long[] getLongArray(final String... keys) { - Long[] rs = new Long[keys.length]; - int index = -1; - for (String key : keys) { - Number n = (Number) get(key, long.class); - rs[++index] = n == null ? null : n.longValue(); - } - return rs; - } - - @Override - public CompletableFuture> getLongMapAsync(final String... keys) { - return CompletableFuture.supplyAsync(() -> getLongMap(keys), getExecutor()); - } - - @Override - public CompletableFuture getLongArrayAsync(final String... keys) { - return CompletableFuture.supplyAsync(() -> getLongArray(keys), getExecutor()); - } - - @Override - public Map getStringMap(final String... keys) { - Map map = new LinkedHashMap<>(); - for (String key : keys) { - Object n = get(key, String.class); - map.put(key, n == null ? null : n.toString()); - } - return map; - } - - @Override - public String[] getStringArray(final String... keys) { - String[] rs = new String[keys.length]; - int index = -1; - for (String key : keys) { - Object n = get(key, String.class); - rs[++index] = n == null ? null : n.toString(); - } - return rs; - } - - @Override - public CompletableFuture> getStringMapAsync(final String... keys) { - return CompletableFuture.supplyAsync(() -> getStringMap(keys), getExecutor()); - } - - @Override - public CompletableFuture getStringArrayAsync(final String... keys) { - return CompletableFuture.supplyAsync(() -> getStringArray(keys), getExecutor()); - } - - @Override - public Map getMap(final Type componentType, final String... keys) { - Map map = new LinkedHashMap<>(); - for (String key : keys) { - map.put(key, (T) get(key, componentType)); - } - return map; - } - - @Override - public CompletableFuture> getMapAsync(final Type componentType, final String... keys) { - return CompletableFuture.supplyAsync(() -> getMap(componentType, keys), getExecutor()); - } - - @Override - public Collection getLongCollection(final String key) { - return (Collection) get(key, long.class); - } - - @Override - public Map> getLongCollectionMap(final boolean set, final String... keys) { - Map> map = new HashMap<>(); - for (String key : keys) { - Collection s = (Collection) get(key, long.class); - if (s != null) map.put(key, s); - } - return map; - } - - @Override - public CompletableFuture>> getCollectionMapAsync(boolean set, Type componentType, String... keys) { - return CompletableFuture.supplyAsync(() -> getCollectionMap(set, componentType, keys), getExecutor()); - } - - @Override - public CompletableFuture> getStringCollectionAsync(final String key) { - return CompletableFuture.supplyAsync(() -> getStringCollection(key), getExecutor()); - } - - @Override - public CompletableFuture>> getStringCollectionMapAsync(final boolean set, final String... keys) { - return CompletableFuture.supplyAsync(() -> getStringCollectionMap(set, keys), getExecutor()); - } - - @Override - public CompletableFuture> getLongCollectionAsync(final String key) { - return CompletableFuture.supplyAsync(() -> getLongCollection(key), getExecutor()); - } - - @Override - public CompletableFuture>> getLongCollectionMapAsync(final boolean set, final String... keys) { - return CompletableFuture.supplyAsync(() -> getLongCollectionMap(set, keys), getExecutor()); - } - - @Override - public CompletableFuture> getCollectionAsync(String key, Type componentType) { - return CompletableFuture.supplyAsync(() -> getCollection(key, componentType), getExecutor()); - } - - @Override - public int getCollectionSize(final String key) { - Collection collection = (Collection) get(key, Object.class); - return collection == null ? 0 : collection.size(); - } - - @Override - public CompletableFuture getCollectionSizeAsync(final String key) { - return CompletableFuture.supplyAsync(() -> getCollectionSize(key), getExecutor()); - } - - @Override - public Collection getCollectionAndRefresh(final String key, final int expireSeconds, final Type componentType) { - return (Collection) getAndRefresh(key, expireSeconds, componentType); - } - - @Override - public Collection getStringCollectionAndRefresh(final String key, final int expireSeconds) { - return (Collection) getAndRefresh(key, expireSeconds, String.class); - } - - @Override - public boolean existsSetItem(final String key, final Type type, final T value) { - Collection list = getCollection(key, type); - return list != null && list.contains(value); - } - - @Override - public CompletableFuture existsSetItemAsync(final String key, final Type type, final T value) { - return CompletableFuture.supplyAsync(() -> existsSetItem(key, type, value), getExecutor()); - } - - @Override - public boolean existsStringSetItem(final String key, final String value) { - Collection list = getStringCollection(key); - return list != null && list.contains(value); - } - - @Override - public CompletableFuture existsStringSetItemAsync(final String key, final String value) { - return CompletableFuture.supplyAsync(() -> existsStringSetItem(key, value), getExecutor()); - } - - @Override - public boolean existsLongSetItem(final String key, final long value) { - Collection list = getLongCollection(key); - return list != null && list.contains(value); - } - - @Override - public CompletableFuture existsLongSetItemAsync(final String key, final long value) { - return CompletableFuture.supplyAsync(() -> existsLongSetItem(key, value), getExecutor()); - } - - @Override - public Collection getLongCollectionAndRefresh(String key, int expireSeconds) { - return (Collection) getAndRefresh(key, expireSeconds, long.class); - } - - @Override - public CompletableFuture> getCollectionAndRefreshAsync(final String key, final int expireSeconds, final Type componentType) { - return CompletableFuture.supplyAsync(() -> getCollectionAndRefresh(key, expireSeconds, componentType), getExecutor()); - } - - @Override - public CompletableFuture> getStringCollectionAndRefreshAsync(final String key, final int expireSeconds) { - return CompletableFuture.supplyAsync(() -> getStringCollectionAndRefresh(key, expireSeconds), getExecutor()); - } - - @Override - public CompletableFuture> getLongCollectionAndRefreshAsync(final String key, final int expireSeconds) { - return CompletableFuture.supplyAsync(() -> getLongCollectionAndRefresh(key, expireSeconds), getExecutor()); - } - - protected void appendListItem(CacheEntryType cacheType, String key, Object value) { - if (key == null) return; - CacheEntry entry = container.get(key); - if (entry == null || !entry.isListCacheType() || entry.listValue == null) { - ConcurrentLinkedQueue list = new ConcurrentLinkedQueue(); - entry = new CacheEntry(cacheType, key, null, null, list, null); - CacheEntry old = container.putIfAbsent(key, entry); - if (old != null) list = old.listValue; - if (list != null) list.add(value); - } else { - entry.listValue.add(value); - } - } - - @Override - public void appendListItem(String key, Type componentType, T value) { - appendListItem(CacheEntryType.OBJECT_LIST, key, value); - } - - @Override - public void appendStringListItem(String key, String value) { - appendListItem(CacheEntryType.STRING_LIST, key, value); - } - - @Override - public void appendLongListItem(String key, long value) { - appendListItem(CacheEntryType.LONG_LIST, key, value); - } - - @Override - public CompletableFuture appendListItemAsync(final String key, final Type componentType, final T value) { - return CompletableFuture.runAsync(() -> appendListItem(key, componentType, value), getExecutor()).whenComplete(futureCompleteConsumer); - } - - @Override - public CompletableFuture appendStringListItemAsync(final String key, final String value) { - return CompletableFuture.runAsync(() -> appendStringListItem(key, value), getExecutor()).whenComplete(futureCompleteConsumer); - } - - @Override - public CompletableFuture appendLongListItemAsync(final String key, final long value) { - return CompletableFuture.runAsync(() -> appendLongListItem(key, value), getExecutor()).whenComplete(futureCompleteConsumer); - } - - @Override - public int removeListItem(String key, final Type componentType, T value) { - if (key == null) return 0; - CacheEntry entry = container.get(key); - if (entry == null || entry.listValue == null) return 0; - return entry.listValue.remove(value) ? 1 : 0; - } - - @Override - public int removeStringListItem(String key, String value) { - if (key == null) return 0; - CacheEntry entry = container.get(key); - if (entry == null || entry.listValue == null) return 0; - return entry.listValue.remove(value) ? 1 : 0; - } - - @Override - public int removeLongListItem(String key, long value) { - if (key == null) return 0; - CacheEntry entry = container.get(key); - if (entry == null || entry.listValue == null) return 0; - return entry.listValue.remove(value) ? 1 : 0; - } - - @Override - public CompletableFuture removeListItemAsync(final String key, final Type componentType, T value) { - return CompletableFuture.supplyAsync(() -> removeListItem(key, componentType, value), getExecutor()).whenComplete(futureCompleteConsumer); - } - - @Override - public CompletableFuture removeStringListItemAsync(final String key, final String value) { - return CompletableFuture.supplyAsync(() -> removeStringListItem(key, value), getExecutor()).whenComplete(futureCompleteConsumer); - } - - @Override - public CompletableFuture removeLongListItemAsync(final String key, final long value) { - return CompletableFuture.supplyAsync(() -> removeLongListItem(key, value), getExecutor()).whenComplete(futureCompleteConsumer); - } - - @Override - public String spopStringSetItem(final String key) { - return (String) spopSetItem(key, String.class); - } - - @Override - public Set spopStringSetItem(final String key, int count) { - return spopSetItem(key, count, String.class); - } - - @Override - public Long spopLongSetItem(final String key) { - return (Long) spopSetItem(key, long.class); - } - - @Override - public Set spopLongSetItem(final String key, int count) { - return spopSetItem(key, count, long.class); - } - - @Override - public T spopSetItem(final String key, final Type componentType) { - if (key == null) return null; - CacheEntry entry = container.get(key); - if (entry == null || !entry.isSetCacheType() || entry.csetValue == null) { - return null; - } - if (entry.csetValue.isEmpty()) return null; - Iterator it = entry.csetValue.iterator(); - if (it.hasNext()) { - Object obj = it.next(); - if (obj != null && componentType == long.class) obj = ((Number) obj).longValue(); - it.remove(); - return (T) obj; - } - return null; - } - - @Override - public Set spopSetItem(final String key, final int count, final Type componentType) { - if (key == null) return new LinkedHashSet<>(); - CacheEntry entry = container.get(key); - if (entry == null || !entry.isSetCacheType() || entry.csetValue == null) { - return new LinkedHashSet<>(); - } - if (entry.csetValue.isEmpty()) return new LinkedHashSet<>(); - Iterator it = entry.csetValue.iterator(); - Set list = new LinkedHashSet<>(); - int index = 0; - while (it.hasNext()) { - Object obj = it.next(); - if (obj != null && componentType == long.class) obj = ((Number) obj).longValue(); - list.add((T) obj); - it.remove(); - if (++index >= count) break; - } - return list; - } - - protected void appendSetItem(CacheEntryType cacheType, String key, Object value) { - if (key == null) return; - CacheEntry entry = container.get(key); - if (entry == null || !entry.isSetCacheType() || entry.csetValue == null) { - CopyOnWriteArraySet set = new CopyOnWriteArraySet(); - entry = new CacheEntry(cacheType, key, null, set, null, null); - CacheEntry old = container.putIfAbsent(key, entry); - if (old != null) set = old.csetValue; - if (set != null) set.add(value); - } else { - entry.csetValue.add(value); - } - } - - @Override - public void appendSetItem(String key, final Type componentType, T value) { - appendSetItem(CacheEntryType.OBJECT_SET, key, value); - } - - @Override - public void appendStringSetItem(String key, String value) { - appendSetItem(CacheEntryType.OBJECT_SET, key, value); - } - - @Override - public void appendLongSetItem(String key, long value) { - appendSetItem(CacheEntryType.OBJECT_SET, key, value); - } - - @Override - public CompletableFuture appendSetItemAsync(final String key, final Type componentType, T value) { - return CompletableFuture.runAsync(() -> appendSetItem(key, componentType, value), getExecutor()).whenComplete(futureCompleteConsumer); - } - - @Override - public CompletableFuture appendStringSetItemAsync(final String key, final String value) { - return CompletableFuture.runAsync(() -> appendStringSetItem(key, value), getExecutor()).whenComplete(futureCompleteConsumer); - } - - @Override - public CompletableFuture appendLongSetItemAsync(final String key, final long value) { - return CompletableFuture.runAsync(() -> appendLongSetItem(key, value), getExecutor()).whenComplete(futureCompleteConsumer); - } - - @Override - public int removeSetItem(String key, Type type, T value) { - if (key == null) return 0; - CacheEntry entry = container.get(key); - if (entry == null || entry.csetValue == null) return 0; - return entry.csetValue.remove(value) ? 1 : 0; - } - - @Override - public int removeStringSetItem(String key, String value) { - if (key == null) return 0; - CacheEntry entry = container.get(key); - if (entry == null || entry.csetValue == null) return 0; - return entry.csetValue.remove(value) ? 1 : 0; - } - - @Override - public int removeLongSetItem(String key, long value) { - if (key == null) return 0; - CacheEntry entry = container.get(key); - if (entry == null || entry.csetValue == null) return 0; - return entry.csetValue.remove(value) ? 1 : 0; - } - - @Override - public CompletableFuture removeSetItemAsync(final String key, final Type componentType, final T value) { - return CompletableFuture.supplyAsync(() -> removeSetItem(key, componentType, value), getExecutor()).whenComplete(futureCompleteConsumer); - } - - @Override - public CompletableFuture removeStringSetItemAsync(final String key, final String value) { - return CompletableFuture.supplyAsync(() -> removeStringSetItem(key, value), getExecutor()).whenComplete(futureCompleteConsumer); - } - - @Override - public CompletableFuture removeLongSetItemAsync(final String key, final long value) { - return CompletableFuture.supplyAsync(() -> removeLongSetItem(key, value), getExecutor()).whenComplete(futureCompleteConsumer); - } - - @Override - public byte[] getBytes(final String key) { - if (key == null) return null; - CacheEntry entry = container.get(key); - if (entry == null || entry.isExpired()) return null; - return (byte[]) entry.objectValue; - } - - @Override - public CompletableFuture getBytesAsync(final String key) { - return CompletableFuture.supplyAsync(() -> getBytes(key), getExecutor()).whenComplete(futureCompleteConsumer); - } - - @Override - public byte[] getBytesAndRefresh(String key, final int expireSeconds) { - if (key == null) return null; - CacheEntry entry = container.get(key); - if (entry == null || entry.isExpired()) return null; - entry.lastAccessed = (int) (System.currentTimeMillis() / 1000); - entry.expireSeconds = expireSeconds; - return (byte[]) entry.objectValue; - } - - @Override - public CompletableFuture getBytesAndRefreshAsync(final String key, final int expireSeconds) { - return CompletableFuture.supplyAsync(() -> getBytesAndRefresh(key, expireSeconds), getExecutor()).whenComplete(futureCompleteConsumer); - } - - @Override - public void setBytes(String key, byte[] value) { - set(CacheEntryType.BYTES, key, value); - } - - @Override - public CompletableFuture setBytesAsync(final String key, byte[] value) { - return CompletableFuture.runAsync(() -> setBytes(key, value), getExecutor()).whenComplete(futureCompleteConsumer); - } - - @Override - public void setBytes(final int expireSeconds, final String key, final byte[] value) { - set(CacheEntryType.BYTES, expireSeconds, key, value); - } - - @Override - public CompletableFuture setBytesAsync(final int expireSeconds, final String key, byte[] value) { - return CompletableFuture.runAsync(() -> setBytes(expireSeconds, key, value), getExecutor()).whenComplete(futureCompleteConsumer); - } - - @Override - public void setBytes(final String key, final Convert convert, final Type type, final T value) { - set(CacheEntryType.BYTES, key, convert.convertToBytes(type, value)); - } - - @Override - public CompletableFuture setBytesAsync(final String key, final Convert convert, final Type type, final T value) { - return CompletableFuture.runAsync(() -> setBytes(key, convert, type, value), getExecutor()).whenComplete(futureCompleteConsumer); - } - - @Override - public void setBytes(final int expireSeconds, final String key, final Convert convert, final Type type, final T value) { - set(CacheEntryType.BYTES, expireSeconds, key, convert.convertToBytes(type, value)); - } - - @Override - public CompletableFuture setBytesAsync(final int expireSeconds, final String key, final Convert convert, final Type type, final T value) { - return CompletableFuture.runAsync(() -> setBytes(expireSeconds, key, convert, type, value), getExecutor()).whenComplete(futureCompleteConsumer); - } - - @Override - public List queryKeys() { - return new ArrayList<>(container.keySet()); - } - - @Override - public List queryKeysStartsWith(String startsWith) { - if (startsWith == null) return queryKeys(); - List rs = new ArrayList<>(); - container.keySet().stream().filter(x -> x.startsWith(startsWith)).forEach(x -> rs.add(x)); - return rs; - } - - @Override - public List queryKeysEndsWith(String endsWith) { - if (endsWith == null) return queryKeys(); - List rs = new ArrayList<>(); - container.keySet().stream().filter(x -> x.endsWith(endsWith)).forEach(x -> rs.add(x)); - return rs; - } - - @Override - public int getKeySize() { - return container.size(); - } - - @Override - public CompletableFuture> queryKeysAsync() { - return CompletableFuture.completedFuture(new ArrayList<>(container.keySet())); - } - - @Override - public CompletableFuture> queryKeysStartsWithAsync(String startsWith) { - return CompletableFuture.completedFuture(queryKeysStartsWith(startsWith)); - } - - @Override - public CompletableFuture> queryKeysEndsWithAsync(String endsWith) { - return CompletableFuture.completedFuture(queryKeysEndsWith(endsWith)); - } - - @Override - public CompletableFuture getKeySizeAsync() { - return CompletableFuture.completedFuture(container.size()); - } - - @Override - public CompletableFuture spopSetItemAsync(String key, Type componentType) { - return CompletableFuture.supplyAsync(() -> spopSetItem(key, componentType), getExecutor()).whenComplete(futureCompleteConsumer); - } - - @Override - public CompletableFuture> spopSetItemAsync(String key, int count, Type componentType) { - return CompletableFuture.supplyAsync(() -> spopSetItem(key, count, componentType), getExecutor()).whenComplete(futureCompleteConsumer); - } - - @Override - public CompletableFuture spopStringSetItemAsync(String key) { - return CompletableFuture.supplyAsync(() -> spopStringSetItem(key), getExecutor()).whenComplete(futureCompleteConsumer); - } - - @Override - public CompletableFuture> spopStringSetItemAsync(String key, int count) { - return CompletableFuture.supplyAsync(() -> spopStringSetItem(key, count), getExecutor()).whenComplete(futureCompleteConsumer); - } - - @Override - public CompletableFuture spopLongSetItemAsync(String key) { - return CompletableFuture.supplyAsync(() -> spopLongSetItem(key), getExecutor()).whenComplete(futureCompleteConsumer); - } - - @Override - public CompletableFuture> spopLongSetItemAsync(String key, int count) { - return CompletableFuture.supplyAsync(() -> spopLongSetItem(key, count), getExecutor()).whenComplete(futureCompleteConsumer); - } - - public static enum CacheEntryType { - LONG, STRING, OBJECT, BYTES, ATOMIC, MAP, - LONG_SET, STRING_SET, OBJECT_SET, - LONG_LIST, STRING_LIST, OBJECT_LIST; - } - - public static final class CacheEntry { - - final CacheEntryType cacheType; - - final String key; - - //<=0琛ㄧず姘镐箙淇濆瓨 - int expireSeconds; - - volatile int lastAccessed; //鏈鍚庡埛鏂版椂闂 - - T objectValue; - - ConcurrentHashMap mapValue; - - CopyOnWriteArraySet csetValue; - - ConcurrentLinkedQueue listValue; - - public CacheEntry(CacheEntryType cacheType, String key, T objectValue, CopyOnWriteArraySet csetValue, ConcurrentLinkedQueue listValue, ConcurrentHashMap mapValue) { - this(cacheType, 0, key, objectValue, csetValue, listValue, mapValue); - } - - public CacheEntry(CacheEntryType cacheType, int expireSeconds, String key, T objectValue, CopyOnWriteArraySet csetValue, ConcurrentLinkedQueue listValue, ConcurrentHashMap mapValue) { - this(cacheType, expireSeconds, (int) (System.currentTimeMillis() / 1000), key, objectValue, csetValue, listValue, mapValue); - } - - @ConstructorParameters({"cacheType", "expireSeconds", "lastAccessed", "key", "objectValue", "csetValue", "listValue", "mapValue"}) - public CacheEntry(CacheEntryType cacheType, int expireSeconds, int lastAccessed, String key, T objectValue, CopyOnWriteArraySet csetValue, ConcurrentLinkedQueue listValue, ConcurrentHashMap mapValue) { - this.cacheType = cacheType; - this.expireSeconds = expireSeconds; - this.lastAccessed = lastAccessed; - this.key = key; - this.objectValue = objectValue; - this.csetValue = csetValue; - this.listValue = listValue; - this.mapValue = mapValue; - } - - @Override - public String toString() { - return JsonFactory.root().getConvert().convertTo(this); - } - - @ConvertColumn(ignore = true) - public boolean isListCacheType() { - return cacheType == CacheEntryType.LONG_LIST || cacheType == CacheEntryType.STRING_LIST || cacheType == CacheEntryType.OBJECT_LIST; - } - - @ConvertColumn(ignore = true) - public boolean isSetCacheType() { - return cacheType == CacheEntryType.LONG_SET || cacheType == CacheEntryType.STRING_SET || cacheType == CacheEntryType.OBJECT_SET; - } - - @ConvertColumn(ignore = true) - public boolean isMapCacheType() { - return cacheType == CacheEntryType.MAP; - } - - @ConvertColumn(ignore = true) - public boolean isExpired() { - return (expireSeconds > 0 && lastAccessed + expireSeconds < (System.currentTimeMillis() / 1000)); - } - - public CacheEntryType getCacheType() { - return cacheType; - } - - public int getExpireSeconds() { - return expireSeconds; - } - - public int getLastAccessed() { - return lastAccessed; - } - - public String getKey() { - return key; - } - - public T getObjectValue() { - return objectValue; - } - - public CopyOnWriteArraySet getCsetValue() { - return csetValue; - } - - public ConcurrentLinkedQueue getListValue() { - return listValue; - } - - public ConcurrentHashMap getMapValue() { - return mapValue; - } - } -} +/* + * 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.source; + +import java.io.*; +import java.lang.reflect.Type; +import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.*; +import java.util.logging.*; +import javax.annotation.Resource; +import org.redkale.convert.*; +import org.redkale.convert.json.*; +import org.redkale.service.*; +import org.redkale.util.*; + +/** + * CacheSource鐨勯粯璁ゅ疄鐜--鍐呭瓨缂撳瓨 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@Local +@AutoLoad(false) +@SuppressWarnings("unchecked") +@ResourceType(CacheSource.class) +public final class CacheMemorySource extends AbstractService implements CacheSource, Service, AutoCloseable, Resourcable { + + @Resource + private JsonConvert defaultConvert; + + @Resource(name = "$_convert") + private JsonConvert convert; + + private String name; + + private ScheduledThreadPoolExecutor scheduler; + + private Consumer expireHandler; + + private final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); + + protected final ConcurrentHashMap> container = new ConcurrentHashMap<>(); + + protected final BiConsumer futureCompleteConsumer = (r, t) -> { + if (t != null) logger.log(Level.SEVERE, "CompletableFuture complete error", (Throwable) t); + }; + + public CacheMemorySource(String resourceName) { + this.name = resourceName; + } + + @Override + public final String getType() { + return "memory"; + } + + @Override + public String toString() { + return "CacheMemorySource(type=memory, name='" + resourceName() + "')"; + } + + @Override //ServiceLoader鏃跺垽鏂厤缃槸鍚︾鍚堝綋鍓嶅疄鐜扮被 + public boolean acceptsConf(AnyValue config) { + return false; + } + + @Override + @SuppressWarnings("unchecked") + public void init(AnyValue conf) { + if (this.convert == null) this.convert = this.defaultConvert; + if (this.convert == null) this.convert = JsonConvert.root(); + final CacheMemorySource self = this; + AnyValue prop = conf == null ? null : conf.getAnyValue("properties"); + String expireHandlerClass = prop == null ? null : prop.getValue("expirehandler"); + if (expireHandlerClass != null) { + try { + Class clazz = Thread.currentThread().getContextClassLoader().loadClass(expireHandlerClass); + this.expireHandler = (Consumer) clazz.getDeclaredConstructor().newInstance(); + RedkaleClassLoader.putReflectionDeclaredConstructors(clazz, expireHandlerClass); + } catch (Throwable e) { + logger.log(Level.SEVERE, self.getClass().getSimpleName() + " new expirehandler class (" + expireHandlerClass + ") instance error", e); + } + } + if (scheduler == null) { + this.scheduler = new ScheduledThreadPoolExecutor(1, (Runnable r) -> { + final Thread t = new Thread(r, "Redkale-" + self.getClass().getSimpleName() + "-Expirer-Thread"); + t.setDaemon(true); + return t; + }); + final List keys = new ArrayList<>(); + scheduler.scheduleWithFixedDelay(() -> { + try { + keys.clear(); + int now = (int) (System.currentTimeMillis() / 1000); + container.forEach((k, x) -> { + if (x.expireSeconds > 0 && (now > (x.lastAccessed + x.expireSeconds))) { + keys.add(x.key); + } + }); + for (String key : keys) { + CacheEntry entry = container.remove(key); + if (expireHandler != null && entry != null) expireHandler.accept(entry); + } + } catch (Throwable t) { + logger.log(Level.SEVERE, "CacheMemorySource schedule(interval=" + 10 + "s) error", t); + } + }, 10, 10, TimeUnit.SECONDS); + if (logger.isLoggable(Level.FINEST)) logger.finest(self.getClass().getSimpleName() + ":" + self.resourceName() + " start schedule expire executor"); + } + } + + @Override + public void close() throws Exception { //缁橝pplication 鍏抽棴鏃惰皟鐢 + destroy(null); + } + + @Override + public String resourceName() { + return name; + } + + @Override + public void destroy(AnyValue conf) { + if (scheduler != null) scheduler.shutdownNow(); + } + + //----------- hxxx -------------- + @Override + public int hremove(final String key, String... fields) { + int count = 0; + CacheEntry entry = container.get(key); + if (entry == null || entry.mapValue == null) return 0; + for (String field : fields) { + if (entry.mapValue.remove(field) != null) count++; + } + return count; + } + + @Override + public List hkeys(final String key) { + List list = new ArrayList<>(); + CacheEntry entry = container.get(key); + if (entry == null || entry.mapValue == null) return list; + list.addAll(entry.mapValue.keySet()); + return list; + } + + @Override + public int hsize(final String key) { + CacheEntry entry = container.get(key); + if (entry == null || entry.mapValue == null) return 0; + return entry.mapValue.keySet().size(); + } + + @Override + public long hincr(final String key, String field) { + return hincr(key, field, 1); + } + + @Override + public long hincr(final String key, String field, long num) { + CacheEntry entry = container.get(key); + if (entry == null) { + synchronized (container) { + entry = container.get(key); + if (entry == null) { + ConcurrentHashMap map = new ConcurrentHashMap(); + map.put(field, new AtomicLong()); + entry = new CacheEntry(CacheEntryType.MAP, key, new AtomicLong(), null, null, map); + container.put(key, entry); + } + } + } + Serializable val = (Serializable) entry.mapValue.computeIfAbsent(field, f -> new AtomicLong()); + if (!(val instanceof AtomicLong)) { + synchronized (entry.mapValue) { + if (!(val instanceof AtomicLong)) { + if (val == null) { + val = new AtomicLong(); + } else { + val = new AtomicLong(((Number) val).longValue()); + } + entry.mapValue.put(field, val); + } + } + } + return ((AtomicLong) entry.mapValue.get(field)).addAndGet(num); + } + + @Override + public long hdecr(final String key, String field) { + return hincr(key, field, -1); + } + + @Override + public long hdecr(final String key, String field, long num) { + return hincr(key, field, -num); + } + + @Override + public boolean hexists(final String key, String field) { + if (key == null) return false; + CacheEntry entry = container.get(key); + if (entry == null || entry.isExpired() || entry.mapValue == null) return false; + return entry.mapValue.contains(field); + } + + @Override + public void hset(final String key, final String field, final Convert convert, final T value) { + hset(CacheEntryType.MAP, key, field, value); + } + + @Override + public void hset(final String key, final String field, final Type type, final T value) { + hset(CacheEntryType.MAP, key, field, value); + } + + @Override + public void hset(final String key, final String field, final Convert convert, final Type type, final T value) { + hset(CacheEntryType.MAP, key, field, value); + } + + @Override + public void hsetString(final String key, final String field, final String value) { + hset(CacheEntryType.MAP, key, field, value); + } + + @Override + public void hsetLong(final String key, final String field, final long value) { + hset(CacheEntryType.MAP, key, field, value); + } + + @Override + public void hmset(final String key, final Serializable... values) { + for (int i = 0; i < values.length; i += 2) { + hset(CacheEntryType.MAP, key, (String) values[i], values[i + 1]); + } + } + + @Override + public List hmget(final String key, final Type type, final String... fields) { + if (key == null) return null; + CacheEntry entry = container.get(key); + if (entry == null || entry.isExpired() || entry.mapValue == null) return null; + List rs = new ArrayList<>(fields.length); + for (int i = 0; i < fields.length; i++) { + Serializable val = (Serializable) entry.mapValue.get(fields[i]); + if (type == String.class) { + rs.add(val == null ? null : (T) String.valueOf(val)); + } else { + rs.add((T) val); + } + } + return rs; + } + + @Override + public Map hmap(final String key, final Type type, int offset, int limit) { + return hmap(key, type, offset, limit, null); + } + + @Override + public Map hmap(final String key, final Type type, int offset, int limit, String pattern) { + if (key == null) return new HashMap(); + CacheEntry entry = container.get(key); + if (entry == null || entry.isExpired() || entry.mapValue == null) return new HashMap(); + return new HashMap(entry.mapValue); + } + + @Override + public T hget(final String key, final String field, final Type type) { + if (key == null) return null; + CacheEntry entry = container.get(key); + if (entry == null || entry.isExpired() || entry.mapValue == null) return null; + return (T) entry.mapValue.get(field); + } + + @Override + public String hgetString(final String key, final String field) { + if (key == null) return null; + CacheEntry entry = container.get(key); + if (entry == null || entry.isExpired() || entry.mapValue == null) return null; + return (String) entry.mapValue.get(field); + } + + @Override + public long hgetLong(final String key, final String field, long defValue) { + if (key == null) return defValue; + CacheEntry entry = container.get(key); + if (entry == null || entry.isExpired() || entry.mapValue == null) return defValue; + return ((Number) entry.mapValue.getOrDefault(field, defValue)).longValue(); + } + //----------- hxxx -------------- + + @Override + public boolean exists(String key) { + if (key == null) return false; + CacheEntry entry = container.get(key); + if (entry == null) return false; + return !entry.isExpired(); + } + + @Override + public CompletableFuture existsAsync(final String key) { + return CompletableFuture.supplyAsync(() -> exists(key), getExecutor()); + } + + @Override + public T get(final String key, final Type type) { + if (key == null) return null; + CacheEntry entry = container.get(key); + if (entry == null || entry.isExpired()) return null; + if (entry.isListCacheType()) return (T) (entry.listValue == null ? null : new ArrayList(entry.listValue)); + if (entry.isSetCacheType()) return (T) (entry.csetValue == null ? null : new HashSet(entry.csetValue)); + return (T) entry.objectValue; + } + + @Override + public String getString(String key) { + if (key == null) return null; + CacheEntry entry = container.get(key); + if (entry == null || entry.isExpired()) return null; + return (String) entry.objectValue; + } + + @Override + public long getLong(String key, long defValue) { + if (key == null) return defValue; + CacheEntry entry = container.get(key); + if (entry == null || entry.isExpired()) return defValue; + return entry.objectValue == null ? defValue : (entry.objectValue instanceof AtomicLong ? ((AtomicLong) entry.objectValue).get() : (Long) entry.objectValue); + } + //----------- hxxx -------------- + + @Override + public CompletableFuture hremoveAsync(final String key, String... fields) { + return CompletableFuture.supplyAsync(() -> hremove(key, fields), getExecutor()); + } + + @Override + public CompletableFuture> hkeysAsync(final String key) { + return CompletableFuture.supplyAsync(() -> hkeys(key), getExecutor()); + } + + @Override + public CompletableFuture hsizeAsync(final String key) { + return CompletableFuture.supplyAsync(() -> hsize(key), getExecutor()); + } + + @Override + public CompletableFuture hincrAsync(final String key, String field) { + return CompletableFuture.supplyAsync(() -> hincr(key, field), getExecutor()); + } + + @Override + public CompletableFuture hincrAsync(final String key, String field, long num) { + return CompletableFuture.supplyAsync(() -> hincr(key, field, num), getExecutor()); + } + + @Override + public CompletableFuture hdecrAsync(final String key, String field) { + return CompletableFuture.supplyAsync(() -> hdecr(key, field), getExecutor()); + } + + @Override + public CompletableFuture hdecrAsync(final String key, String field, long num) { + return CompletableFuture.supplyAsync(() -> hdecr(key, field, num), getExecutor()); + } + + @Override + public CompletableFuture hexistsAsync(final String key, String field) { + return CompletableFuture.supplyAsync(() -> hexists(key, field), getExecutor()); + } + + @Override + public CompletableFuture hsetAsync(final String key, final String field, final Convert convert, final T value) { + return CompletableFuture.runAsync(() -> hset(key, field, convert, value), getExecutor()).whenComplete(futureCompleteConsumer); + } + + @Override + public CompletableFuture hsetAsync(final String key, final String field, final Type type, final T value) { + return CompletableFuture.runAsync(() -> hset(key, field, type, value), getExecutor()).whenComplete(futureCompleteConsumer); + } + + @Override + public CompletableFuture hsetAsync(final String key, final String field, final Convert convert, final Type type, final T value) { + return CompletableFuture.runAsync(() -> hset(key, field, convert, type, value), getExecutor()).whenComplete(futureCompleteConsumer); + } + + @Override + public CompletableFuture hsetStringAsync(final String key, final String field, final String value) { + return CompletableFuture.runAsync(() -> hsetString(key, field, value), getExecutor()).whenComplete(futureCompleteConsumer); + } + + @Override + public CompletableFuture hsetLongAsync(final String key, final String field, final long value) { + return CompletableFuture.runAsync(() -> hsetLong(key, field, value), getExecutor()).whenComplete(futureCompleteConsumer); + } + + @Override + public CompletableFuture hmsetAsync(final String key, final Serializable... values) { + return CompletableFuture.runAsync(() -> hmset(key, values), getExecutor()).whenComplete(futureCompleteConsumer); + } + + @Override + public CompletableFuture> hmgetAsync(final String key, final Type type, final String... fields) { + return CompletableFuture.supplyAsync(() -> hmget(key, type, fields), getExecutor()); + } + + @Override + public CompletableFuture> hmapAsync(final String key, final Type type, int offset, int limit) { + return CompletableFuture.supplyAsync(() -> hmap(key, type, offset, limit), getExecutor()); + } + + @Override + public CompletableFuture> hmapAsync(final String key, final Type type, int offset, int limit, String pattern) { + return CompletableFuture.supplyAsync(() -> hmap(key, type, offset, limit, pattern), getExecutor()); + } + + @Override + public CompletableFuture hgetAsync(final String key, final String field, final Type type) { + return CompletableFuture.supplyAsync(() -> hget(key, field, type), getExecutor()); + } + + @Override + public CompletableFuture hgetStringAsync(final String key, final String field) { + return CompletableFuture.supplyAsync(() -> hgetString(key, field), getExecutor()); + } + + @Override + public CompletableFuture hgetLongAsync(final String key, final String field, long defValue) { + return CompletableFuture.supplyAsync(() -> hgetLong(key, field, defValue), getExecutor()); + } + + //----------- hxxx -------------- + @Override + public CompletableFuture getAsync(final String key, final Type type) { + return CompletableFuture.supplyAsync(() -> (T) get(key, type), getExecutor()); + } + + @Override + public CompletableFuture getStringAsync(final String key) { + return CompletableFuture.supplyAsync(() -> getString(key), getExecutor()); + } + + @Override + public CompletableFuture getLongAsync(final String key, long defValue) { + return CompletableFuture.supplyAsync(() -> getLong(key, defValue), getExecutor()); + } + + @Override + public T getAndRefresh(final String key, final int expireSeconds, final Type type) { + if (key == null) return null; + CacheEntry entry = container.get(key); + if (entry == null || entry.isExpired()) return null; + entry.lastAccessed = (int) (System.currentTimeMillis() / 1000); + entry.expireSeconds = expireSeconds; + if (entry.isListCacheType()) return (T) (entry.listValue == null ? null : new ArrayList(entry.listValue)); + if (entry.isSetCacheType()) return (T) (entry.csetValue == null ? null : new HashSet(entry.csetValue)); + return (T) entry.objectValue; + } + + @Override + @SuppressWarnings("unchecked") + public String getStringAndRefresh(String key, final int expireSeconds) { + if (key == null) return null; + CacheEntry entry = container.get(key); + if (entry == null || entry.isExpired()) return null; + entry.lastAccessed = (int) (System.currentTimeMillis() / 1000); + entry.expireSeconds = expireSeconds; + return (String) entry.objectValue; + } + + @Override + public long getLongAndRefresh(String key, final int expireSeconds, long defValue) { + if (key == null) return defValue; + CacheEntry entry = container.get(key); + if (entry == null || entry.isExpired()) return defValue; + entry.lastAccessed = (int) (System.currentTimeMillis() / 1000); + entry.expireSeconds = expireSeconds; + return entry.objectValue == null ? defValue : (entry.objectValue instanceof AtomicLong ? ((AtomicLong) entry.objectValue).get() : (Long) entry.objectValue); + + } + + @Override + public CompletableFuture getAndRefreshAsync(final String key, final int expireSeconds, final Type type) { + return CompletableFuture.supplyAsync(() -> getAndRefresh(key, expireSeconds, type), getExecutor()); + } + + @Override + public CompletableFuture getStringAndRefreshAsync(final String key, final int expireSeconds) { + return CompletableFuture.supplyAsync(() -> getStringAndRefresh(key, expireSeconds), getExecutor()); + } + + @Override + public CompletableFuture getLongAndRefreshAsync(final String key, final int expireSeconds, long defValue) { + return CompletableFuture.supplyAsync(() -> getLongAndRefresh(key, expireSeconds, defValue), getExecutor()); + } + + @Override + public void refresh(String key, final int expireSeconds) { + if (key == null) return; + CacheEntry entry = container.get(key); + if (entry == null) return; + entry.lastAccessed = (int) (System.currentTimeMillis() / 1000); + entry.expireSeconds = expireSeconds; + } + + @Override + public CompletableFuture refreshAsync(final String key, final int expireSeconds) { + return CompletableFuture.runAsync(() -> refresh(key, expireSeconds), getExecutor()).whenComplete(futureCompleteConsumer); + } + + protected void set(CacheEntryType cacheType, String key, Object value) { + if (key == null) return; + CacheEntry entry = container.get(key); + if (entry == null) { + entry = new CacheEntry(cacheType, key, value, null, null, null); + container.putIfAbsent(key, entry); + } else { + entry.expireSeconds = 0; + entry.objectValue = value; + entry.lastAccessed = (int) (System.currentTimeMillis() / 1000); + } + } + + protected void hset(CacheEntryType cacheType, String key, String field, Object value) { + if (key == null) return; + CacheEntry entry = container.get(key); + if (entry == null) { + entry = new CacheEntry(CacheEntryType.MAP, key, value, null, null, new ConcurrentHashMap<>()); + container.putIfAbsent(key, entry); + entry.mapValue.put(field, value); + } else { + entry.expireSeconds = 0; + entry.mapValue.put(field, value); + entry.lastAccessed = (int) (System.currentTimeMillis() / 1000); + } + } + + @Override + public void set(String key, Convert convert, T value) { + set(CacheEntryType.OBJECT, key, value); + } + + @Override + public void set(String key, Type type, T value) { + set(CacheEntryType.OBJECT, key, value); + } + + @Override + public void set(String key, Convert convert, Type type, T value) { + set(CacheEntryType.OBJECT, key, value); + } + + @Override + public void setString(String key, String value) { + set(CacheEntryType.STRING, key, value); + } + + @Override + public void setLong(String key, long value) { + set(CacheEntryType.LONG, key, value); + } + + @Override + public CompletableFuture setAsync(String key, Convert convert, T value) { + return CompletableFuture.runAsync(() -> set(key, convert, value), getExecutor()).whenComplete(futureCompleteConsumer); + } + + @Override + public CompletableFuture setAsync(String key, Type type, T value) { + return CompletableFuture.runAsync(() -> set(key, type, value), getExecutor()).whenComplete(futureCompleteConsumer); + } + + @Override + public CompletableFuture setAsync(String key, Convert convert, Type type, T value) { + return CompletableFuture.runAsync(() -> set(key, convert, type, value), getExecutor()).whenComplete(futureCompleteConsumer); + } + + @Override + public CompletableFuture setStringAsync(String key, String value) { + return CompletableFuture.runAsync(() -> setString(key, value), getExecutor()).whenComplete(futureCompleteConsumer); + } + + @Override + public CompletableFuture setLongAsync(String key, long value) { + return CompletableFuture.runAsync(() -> setLong(key, value), getExecutor()).whenComplete(futureCompleteConsumer); + } + + protected void set(CacheEntryType cacheType, int expireSeconds, String key, Object value) { + if (key == null) return; + CacheEntry entry = container.get(key); + if (entry == null) { + entry = new CacheEntry(cacheType, expireSeconds, key, value, null, null, null); + container.putIfAbsent(key, entry); + } else { + if (expireSeconds > 0) entry.expireSeconds = expireSeconds; + entry.lastAccessed = (int) (System.currentTimeMillis() / 1000); + entry.objectValue = value; + } + } + + @Override + public void set(final int expireSeconds, String key, Convert convert, T value) { + set(CacheEntryType.OBJECT, expireSeconds, key, value); + } + + @Override + public void set(final int expireSeconds, String key, Type type, T value) { + set(CacheEntryType.OBJECT, expireSeconds, key, value); + } + + @Override + public void set(final int expireSeconds, String key, Convert convert, Type type, T value) { + set(CacheEntryType.OBJECT, expireSeconds, key, value); + } + + @Override + public void setString(int expireSeconds, String key, String value) { + set(CacheEntryType.STRING, expireSeconds, key, value); + } + + @Override + public void setLong(int expireSeconds, String key, long value) { + set(CacheEntryType.LONG, expireSeconds, key, value); + } + + @Override + public CompletableFuture setAsync(int expireSeconds, String key, Convert convert, T value) { + return CompletableFuture.runAsync(() -> set(expireSeconds, key, convert, value), getExecutor()).whenComplete(futureCompleteConsumer); + } + + @Override + public CompletableFuture setAsync(int expireSeconds, String key, Type type, T value) { + return CompletableFuture.runAsync(() -> set(expireSeconds, key, type, value), getExecutor()).whenComplete(futureCompleteConsumer); + } + + @Override + public CompletableFuture setAsync(int expireSeconds, String key, Convert convert, Type type, T value) { + return CompletableFuture.runAsync(() -> set(expireSeconds, key, convert, type, value), getExecutor()).whenComplete(futureCompleteConsumer); + } + + @Override + public CompletableFuture setStringAsync(int expireSeconds, String key, String value) { + return CompletableFuture.runAsync(() -> setString(expireSeconds, key, value), getExecutor()).whenComplete(futureCompleteConsumer); + } + + @Override + public CompletableFuture setLongAsync(int expireSeconds, String key, long value) { + return CompletableFuture.runAsync(() -> setLong(expireSeconds, key, value), getExecutor()).whenComplete(futureCompleteConsumer); + } + + @Override + public void setExpireSeconds(String key, int expireSeconds) { + if (key == null) return; + CacheEntry entry = container.get(key); + if (entry == null) return; + entry.expireSeconds = expireSeconds; + } + + @Override + public CompletableFuture setExpireSecondsAsync(final String key, final int expireSeconds) { + return CompletableFuture.runAsync(() -> setExpireSeconds(key, expireSeconds), getExecutor()).whenComplete(futureCompleteConsumer); + } + + @Override + public int remove(String key) { + if (key == null) return 0; + return container.remove(key) == null ? 0 : 1; + } + + @Override + public long incr(final String key) { + return incr(key, 1); + } + + @Override + public CompletableFuture incrAsync(final String key) { + return CompletableFuture.supplyAsync(() -> incr(key), getExecutor()).whenComplete(futureCompleteConsumer); + } + + @Override + public long incr(final String key, long num) { + CacheEntry entry = container.get(key); + if (entry == null) { + synchronized (container) { + entry = container.get(key); + if (entry == null) { + entry = new CacheEntry(CacheEntryType.ATOMIC, key, new AtomicLong(), null, null, null); + container.put(key, entry); + } + } + } + return ((AtomicLong) entry.objectValue).addAndGet(num); + } + + @Override + public CompletableFuture incrAsync(final String key, long num) { + return CompletableFuture.supplyAsync(() -> incr(key, num), getExecutor()).whenComplete(futureCompleteConsumer); + } + + @Override + public long decr(final String key) { + return incr(key, -1); + } + + @Override + public CompletableFuture decrAsync(final String key) { + return CompletableFuture.supplyAsync(() -> decr(key), getExecutor()).whenComplete(futureCompleteConsumer); + } + + @Override + public long decr(final String key, long num) { + return incr(key, -num); + } + + @Override + public CompletableFuture decrAsync(final String key, long num) { + return CompletableFuture.supplyAsync(() -> decr(key, num), getExecutor()).whenComplete(futureCompleteConsumer); + } + + @Override + public CompletableFuture removeAsync(final String key) { + return CompletableFuture.supplyAsync(() -> remove(key), getExecutor()).whenComplete(futureCompleteConsumer); + } + + @Override + public Collection getCollection(final String key, final Type componentType) { + return (Collection) get(key, componentType); + } + + @Override + public Map> getCollectionMap(final boolean set, final Type componentType, final String... keys) { + Map> map = new HashMap<>(); + for (String key : keys) { + Collection s = (Collection) get(key, componentType); + if (s != null) map.put(key, s); + } + return map; + } + + @Override + public Collection getStringCollection(final String key) { + return (Collection) get(key, String.class); + } + + @Override + public Map> getStringCollectionMap(final boolean set, final String... keys) { + Map> map = new HashMap<>(); + for (String key : keys) { + Collection s = (Collection) get(key, String.class); + if (s != null) map.put(key, s); + } + return map; + } + + @Override + public Map getLongMap(final String... keys) { + Map map = new LinkedHashMap<>(); + for (String key : keys) { + Number n = (Number) get(key, long.class); + map.put(key, n == null ? null : n.longValue()); + } + return map; + } + + @Override + public Long[] getLongArray(final String... keys) { + Long[] rs = new Long[keys.length]; + int index = -1; + for (String key : keys) { + Number n = (Number) get(key, long.class); + rs[++index] = n == null ? null : n.longValue(); + } + return rs; + } + + @Override + public CompletableFuture> getLongMapAsync(final String... keys) { + return CompletableFuture.supplyAsync(() -> getLongMap(keys), getExecutor()); + } + + @Override + public CompletableFuture getLongArrayAsync(final String... keys) { + return CompletableFuture.supplyAsync(() -> getLongArray(keys), getExecutor()); + } + + @Override + public Map getStringMap(final String... keys) { + Map map = new LinkedHashMap<>(); + for (String key : keys) { + Object n = get(key, String.class); + map.put(key, n == null ? null : n.toString()); + } + return map; + } + + @Override + public String[] getStringArray(final String... keys) { + String[] rs = new String[keys.length]; + int index = -1; + for (String key : keys) { + Object n = get(key, String.class); + rs[++index] = n == null ? null : n.toString(); + } + return rs; + } + + @Override + public CompletableFuture> getStringMapAsync(final String... keys) { + return CompletableFuture.supplyAsync(() -> getStringMap(keys), getExecutor()); + } + + @Override + public CompletableFuture getStringArrayAsync(final String... keys) { + return CompletableFuture.supplyAsync(() -> getStringArray(keys), getExecutor()); + } + + @Override + public Map getMap(final Type componentType, final String... keys) { + Map map = new LinkedHashMap<>(); + for (String key : keys) { + map.put(key, (T) get(key, componentType)); + } + return map; + } + + @Override + public CompletableFuture> getMapAsync(final Type componentType, final String... keys) { + return CompletableFuture.supplyAsync(() -> getMap(componentType, keys), getExecutor()); + } + + @Override + public Collection getLongCollection(final String key) { + return (Collection) get(key, long.class); + } + + @Override + public Map> getLongCollectionMap(final boolean set, final String... keys) { + Map> map = new HashMap<>(); + for (String key : keys) { + Collection s = (Collection) get(key, long.class); + if (s != null) map.put(key, s); + } + return map; + } + + @Override + public CompletableFuture>> getCollectionMapAsync(boolean set, Type componentType, String... keys) { + return CompletableFuture.supplyAsync(() -> getCollectionMap(set, componentType, keys), getExecutor()); + } + + @Override + public CompletableFuture> getStringCollectionAsync(final String key) { + return CompletableFuture.supplyAsync(() -> getStringCollection(key), getExecutor()); + } + + @Override + public CompletableFuture>> getStringCollectionMapAsync(final boolean set, final String... keys) { + return CompletableFuture.supplyAsync(() -> getStringCollectionMap(set, keys), getExecutor()); + } + + @Override + public CompletableFuture> getLongCollectionAsync(final String key) { + return CompletableFuture.supplyAsync(() -> getLongCollection(key), getExecutor()); + } + + @Override + public CompletableFuture>> getLongCollectionMapAsync(final boolean set, final String... keys) { + return CompletableFuture.supplyAsync(() -> getLongCollectionMap(set, keys), getExecutor()); + } + + @Override + public CompletableFuture> getCollectionAsync(String key, Type componentType) { + return CompletableFuture.supplyAsync(() -> getCollection(key, componentType), getExecutor()); + } + + @Override + public int getCollectionSize(final String key) { + Collection collection = (Collection) get(key, Object.class); + return collection == null ? 0 : collection.size(); + } + + @Override + public CompletableFuture getCollectionSizeAsync(final String key) { + return CompletableFuture.supplyAsync(() -> getCollectionSize(key), getExecutor()); + } + + @Override + public Collection getCollectionAndRefresh(final String key, final int expireSeconds, final Type componentType) { + return (Collection) getAndRefresh(key, expireSeconds, componentType); + } + + @Override + public Collection getStringCollectionAndRefresh(final String key, final int expireSeconds) { + return (Collection) getAndRefresh(key, expireSeconds, String.class); + } + + @Override + public boolean existsSetItem(final String key, final Type type, final T value) { + Collection list = getCollection(key, type); + return list != null && list.contains(value); + } + + @Override + public CompletableFuture existsSetItemAsync(final String key, final Type type, final T value) { + return CompletableFuture.supplyAsync(() -> existsSetItem(key, type, value), getExecutor()); + } + + @Override + public boolean existsStringSetItem(final String key, final String value) { + Collection list = getStringCollection(key); + return list != null && list.contains(value); + } + + @Override + public CompletableFuture existsStringSetItemAsync(final String key, final String value) { + return CompletableFuture.supplyAsync(() -> existsStringSetItem(key, value), getExecutor()); + } + + @Override + public boolean existsLongSetItem(final String key, final long value) { + Collection list = getLongCollection(key); + return list != null && list.contains(value); + } + + @Override + public CompletableFuture existsLongSetItemAsync(final String key, final long value) { + return CompletableFuture.supplyAsync(() -> existsLongSetItem(key, value), getExecutor()); + } + + @Override + public Collection getLongCollectionAndRefresh(String key, int expireSeconds) { + return (Collection) getAndRefresh(key, expireSeconds, long.class); + } + + @Override + public CompletableFuture> getCollectionAndRefreshAsync(final String key, final int expireSeconds, final Type componentType) { + return CompletableFuture.supplyAsync(() -> getCollectionAndRefresh(key, expireSeconds, componentType), getExecutor()); + } + + @Override + public CompletableFuture> getStringCollectionAndRefreshAsync(final String key, final int expireSeconds) { + return CompletableFuture.supplyAsync(() -> getStringCollectionAndRefresh(key, expireSeconds), getExecutor()); + } + + @Override + public CompletableFuture> getLongCollectionAndRefreshAsync(final String key, final int expireSeconds) { + return CompletableFuture.supplyAsync(() -> getLongCollectionAndRefresh(key, expireSeconds), getExecutor()); + } + + protected void appendListItem(CacheEntryType cacheType, String key, Object value) { + if (key == null) return; + CacheEntry entry = container.get(key); + if (entry == null || !entry.isListCacheType() || entry.listValue == null) { + ConcurrentLinkedQueue list = new ConcurrentLinkedQueue(); + entry = new CacheEntry(cacheType, key, null, null, list, null); + CacheEntry old = container.putIfAbsent(key, entry); + if (old != null) list = old.listValue; + if (list != null) list.add(value); + } else { + entry.listValue.add(value); + } + } + + @Override + public void appendListItem(String key, Type componentType, T value) { + appendListItem(CacheEntryType.OBJECT_LIST, key, value); + } + + @Override + public void appendStringListItem(String key, String value) { + appendListItem(CacheEntryType.STRING_LIST, key, value); + } + + @Override + public void appendLongListItem(String key, long value) { + appendListItem(CacheEntryType.LONG_LIST, key, value); + } + + @Override + public CompletableFuture appendListItemAsync(final String key, final Type componentType, final T value) { + return CompletableFuture.runAsync(() -> appendListItem(key, componentType, value), getExecutor()).whenComplete(futureCompleteConsumer); + } + + @Override + public CompletableFuture appendStringListItemAsync(final String key, final String value) { + return CompletableFuture.runAsync(() -> appendStringListItem(key, value), getExecutor()).whenComplete(futureCompleteConsumer); + } + + @Override + public CompletableFuture appendLongListItemAsync(final String key, final long value) { + return CompletableFuture.runAsync(() -> appendLongListItem(key, value), getExecutor()).whenComplete(futureCompleteConsumer); + } + + @Override + public int removeListItem(String key, final Type componentType, T value) { + if (key == null) return 0; + CacheEntry entry = container.get(key); + if (entry == null || entry.listValue == null) return 0; + return entry.listValue.remove(value) ? 1 : 0; + } + + @Override + public int removeStringListItem(String key, String value) { + if (key == null) return 0; + CacheEntry entry = container.get(key); + if (entry == null || entry.listValue == null) return 0; + return entry.listValue.remove(value) ? 1 : 0; + } + + @Override + public int removeLongListItem(String key, long value) { + if (key == null) return 0; + CacheEntry entry = container.get(key); + if (entry == null || entry.listValue == null) return 0; + return entry.listValue.remove(value) ? 1 : 0; + } + + @Override + public CompletableFuture removeListItemAsync(final String key, final Type componentType, T value) { + return CompletableFuture.supplyAsync(() -> removeListItem(key, componentType, value), getExecutor()).whenComplete(futureCompleteConsumer); + } + + @Override + public CompletableFuture removeStringListItemAsync(final String key, final String value) { + return CompletableFuture.supplyAsync(() -> removeStringListItem(key, value), getExecutor()).whenComplete(futureCompleteConsumer); + } + + @Override + public CompletableFuture removeLongListItemAsync(final String key, final long value) { + return CompletableFuture.supplyAsync(() -> removeLongListItem(key, value), getExecutor()).whenComplete(futureCompleteConsumer); + } + + @Override + public String spopStringSetItem(final String key) { + return (String) spopSetItem(key, String.class); + } + + @Override + public Set spopStringSetItem(final String key, int count) { + return spopSetItem(key, count, String.class); + } + + @Override + public Long spopLongSetItem(final String key) { + return (Long) spopSetItem(key, long.class); + } + + @Override + public Set spopLongSetItem(final String key, int count) { + return spopSetItem(key, count, long.class); + } + + @Override + public T spopSetItem(final String key, final Type componentType) { + if (key == null) return null; + CacheEntry entry = container.get(key); + if (entry == null || !entry.isSetCacheType() || entry.csetValue == null) { + return null; + } + if (entry.csetValue.isEmpty()) return null; + Iterator it = entry.csetValue.iterator(); + if (it.hasNext()) { + Object obj = it.next(); + if (obj != null && componentType == long.class) obj = ((Number) obj).longValue(); + it.remove(); + return (T) obj; + } + return null; + } + + @Override + public Set spopSetItem(final String key, final int count, final Type componentType) { + if (key == null) return new LinkedHashSet<>(); + CacheEntry entry = container.get(key); + if (entry == null || !entry.isSetCacheType() || entry.csetValue == null) { + return new LinkedHashSet<>(); + } + if (entry.csetValue.isEmpty()) return new LinkedHashSet<>(); + Iterator it = entry.csetValue.iterator(); + Set list = new LinkedHashSet<>(); + int index = 0; + while (it.hasNext()) { + Object obj = it.next(); + if (obj != null && componentType == long.class) obj = ((Number) obj).longValue(); + list.add((T) obj); + it.remove(); + if (++index >= count) break; + } + return list; + } + + protected void appendSetItem(CacheEntryType cacheType, String key, Object value) { + if (key == null) return; + CacheEntry entry = container.get(key); + if (entry == null || !entry.isSetCacheType() || entry.csetValue == null) { + CopyOnWriteArraySet set = new CopyOnWriteArraySet(); + entry = new CacheEntry(cacheType, key, null, set, null, null); + CacheEntry old = container.putIfAbsent(key, entry); + if (old != null) set = old.csetValue; + if (set != null) set.add(value); + } else { + entry.csetValue.add(value); + } + } + + @Override + public void appendSetItem(String key, final Type componentType, T value) { + appendSetItem(CacheEntryType.OBJECT_SET, key, value); + } + + @Override + public void appendStringSetItem(String key, String value) { + appendSetItem(CacheEntryType.OBJECT_SET, key, value); + } + + @Override + public void appendLongSetItem(String key, long value) { + appendSetItem(CacheEntryType.OBJECT_SET, key, value); + } + + @Override + public CompletableFuture appendSetItemAsync(final String key, final Type componentType, T value) { + return CompletableFuture.runAsync(() -> appendSetItem(key, componentType, value), getExecutor()).whenComplete(futureCompleteConsumer); + } + + @Override + public CompletableFuture appendStringSetItemAsync(final String key, final String value) { + return CompletableFuture.runAsync(() -> appendStringSetItem(key, value), getExecutor()).whenComplete(futureCompleteConsumer); + } + + @Override + public CompletableFuture appendLongSetItemAsync(final String key, final long value) { + return CompletableFuture.runAsync(() -> appendLongSetItem(key, value), getExecutor()).whenComplete(futureCompleteConsumer); + } + + @Override + public int removeSetItem(String key, Type type, T value) { + if (key == null) return 0; + CacheEntry entry = container.get(key); + if (entry == null || entry.csetValue == null) return 0; + return entry.csetValue.remove(value) ? 1 : 0; + } + + @Override + public int removeStringSetItem(String key, String value) { + if (key == null) return 0; + CacheEntry entry = container.get(key); + if (entry == null || entry.csetValue == null) return 0; + return entry.csetValue.remove(value) ? 1 : 0; + } + + @Override + public int removeLongSetItem(String key, long value) { + if (key == null) return 0; + CacheEntry entry = container.get(key); + if (entry == null || entry.csetValue == null) return 0; + return entry.csetValue.remove(value) ? 1 : 0; + } + + @Override + public CompletableFuture removeSetItemAsync(final String key, final Type componentType, final T value) { + return CompletableFuture.supplyAsync(() -> removeSetItem(key, componentType, value), getExecutor()).whenComplete(futureCompleteConsumer); + } + + @Override + public CompletableFuture removeStringSetItemAsync(final String key, final String value) { + return CompletableFuture.supplyAsync(() -> removeStringSetItem(key, value), getExecutor()).whenComplete(futureCompleteConsumer); + } + + @Override + public CompletableFuture removeLongSetItemAsync(final String key, final long value) { + return CompletableFuture.supplyAsync(() -> removeLongSetItem(key, value), getExecutor()).whenComplete(futureCompleteConsumer); + } + + @Override + public byte[] getBytes(final String key) { + if (key == null) return null; + CacheEntry entry = container.get(key); + if (entry == null || entry.isExpired()) return null; + return (byte[]) entry.objectValue; + } + + @Override + public CompletableFuture getBytesAsync(final String key) { + return CompletableFuture.supplyAsync(() -> getBytes(key), getExecutor()).whenComplete(futureCompleteConsumer); + } + + @Override + public byte[] getBytesAndRefresh(String key, final int expireSeconds) { + if (key == null) return null; + CacheEntry entry = container.get(key); + if (entry == null || entry.isExpired()) return null; + entry.lastAccessed = (int) (System.currentTimeMillis() / 1000); + entry.expireSeconds = expireSeconds; + return (byte[]) entry.objectValue; + } + + @Override + public CompletableFuture getBytesAndRefreshAsync(final String key, final int expireSeconds) { + return CompletableFuture.supplyAsync(() -> getBytesAndRefresh(key, expireSeconds), getExecutor()).whenComplete(futureCompleteConsumer); + } + + @Override + public void setBytes(String key, byte[] value) { + set(CacheEntryType.BYTES, key, value); + } + + @Override + public CompletableFuture setBytesAsync(final String key, byte[] value) { + return CompletableFuture.runAsync(() -> setBytes(key, value), getExecutor()).whenComplete(futureCompleteConsumer); + } + + @Override + public void setBytes(final int expireSeconds, final String key, final byte[] value) { + set(CacheEntryType.BYTES, expireSeconds, key, value); + } + + @Override + public CompletableFuture setBytesAsync(final int expireSeconds, final String key, byte[] value) { + return CompletableFuture.runAsync(() -> setBytes(expireSeconds, key, value), getExecutor()).whenComplete(futureCompleteConsumer); + } + + @Override + public void setBytes(final String key, final Convert convert, final Type type, final T value) { + set(CacheEntryType.BYTES, key, convert.convertToBytes(type, value)); + } + + @Override + public CompletableFuture setBytesAsync(final String key, final Convert convert, final Type type, final T value) { + return CompletableFuture.runAsync(() -> setBytes(key, convert, type, value), getExecutor()).whenComplete(futureCompleteConsumer); + } + + @Override + public void setBytes(final int expireSeconds, final String key, final Convert convert, final Type type, final T value) { + set(CacheEntryType.BYTES, expireSeconds, key, convert.convertToBytes(type, value)); + } + + @Override + public CompletableFuture setBytesAsync(final int expireSeconds, final String key, final Convert convert, final Type type, final T value) { + return CompletableFuture.runAsync(() -> setBytes(expireSeconds, key, convert, type, value), getExecutor()).whenComplete(futureCompleteConsumer); + } + + @Override + public List queryKeys() { + return new ArrayList<>(container.keySet()); + } + + @Override + public List queryKeysStartsWith(String startsWith) { + if (startsWith == null) return queryKeys(); + List rs = new ArrayList<>(); + container.keySet().stream().filter(x -> x.startsWith(startsWith)).forEach(x -> rs.add(x)); + return rs; + } + + @Override + public List queryKeysEndsWith(String endsWith) { + if (endsWith == null) return queryKeys(); + List rs = new ArrayList<>(); + container.keySet().stream().filter(x -> x.endsWith(endsWith)).forEach(x -> rs.add(x)); + return rs; + } + + @Override + public int getKeySize() { + return container.size(); + } + + @Override + public CompletableFuture> queryKeysAsync() { + return CompletableFuture.completedFuture(new ArrayList<>(container.keySet())); + } + + @Override + public CompletableFuture> queryKeysStartsWithAsync(String startsWith) { + return CompletableFuture.completedFuture(queryKeysStartsWith(startsWith)); + } + + @Override + public CompletableFuture> queryKeysEndsWithAsync(String endsWith) { + return CompletableFuture.completedFuture(queryKeysEndsWith(endsWith)); + } + + @Override + public CompletableFuture getKeySizeAsync() { + return CompletableFuture.completedFuture(container.size()); + } + + @Override + public CompletableFuture spopSetItemAsync(String key, Type componentType) { + return CompletableFuture.supplyAsync(() -> spopSetItem(key, componentType), getExecutor()).whenComplete(futureCompleteConsumer); + } + + @Override + public CompletableFuture> spopSetItemAsync(String key, int count, Type componentType) { + return CompletableFuture.supplyAsync(() -> spopSetItem(key, count, componentType), getExecutor()).whenComplete(futureCompleteConsumer); + } + + @Override + public CompletableFuture spopStringSetItemAsync(String key) { + return CompletableFuture.supplyAsync(() -> spopStringSetItem(key), getExecutor()).whenComplete(futureCompleteConsumer); + } + + @Override + public CompletableFuture> spopStringSetItemAsync(String key, int count) { + return CompletableFuture.supplyAsync(() -> spopStringSetItem(key, count), getExecutor()).whenComplete(futureCompleteConsumer); + } + + @Override + public CompletableFuture spopLongSetItemAsync(String key) { + return CompletableFuture.supplyAsync(() -> spopLongSetItem(key), getExecutor()).whenComplete(futureCompleteConsumer); + } + + @Override + public CompletableFuture> spopLongSetItemAsync(String key, int count) { + return CompletableFuture.supplyAsync(() -> spopLongSetItem(key, count), getExecutor()).whenComplete(futureCompleteConsumer); + } + + public static enum CacheEntryType { + LONG, STRING, OBJECT, BYTES, ATOMIC, MAP, + LONG_SET, STRING_SET, OBJECT_SET, + LONG_LIST, STRING_LIST, OBJECT_LIST; + } + + public static final class CacheEntry { + + final CacheEntryType cacheType; + + final String key; + + //<=0琛ㄧず姘镐箙淇濆瓨 + int expireSeconds; + + volatile int lastAccessed; //鏈鍚庡埛鏂版椂闂 + + T objectValue; + + ConcurrentHashMap mapValue; + + CopyOnWriteArraySet csetValue; + + ConcurrentLinkedQueue listValue; + + public CacheEntry(CacheEntryType cacheType, String key, T objectValue, CopyOnWriteArraySet csetValue, ConcurrentLinkedQueue listValue, ConcurrentHashMap mapValue) { + this(cacheType, 0, key, objectValue, csetValue, listValue, mapValue); + } + + public CacheEntry(CacheEntryType cacheType, int expireSeconds, String key, T objectValue, CopyOnWriteArraySet csetValue, ConcurrentLinkedQueue listValue, ConcurrentHashMap mapValue) { + this(cacheType, expireSeconds, (int) (System.currentTimeMillis() / 1000), key, objectValue, csetValue, listValue, mapValue); + } + + @ConstructorParameters({"cacheType", "expireSeconds", "lastAccessed", "key", "objectValue", "csetValue", "listValue", "mapValue"}) + public CacheEntry(CacheEntryType cacheType, int expireSeconds, int lastAccessed, String key, T objectValue, CopyOnWriteArraySet csetValue, ConcurrentLinkedQueue listValue, ConcurrentHashMap mapValue) { + this.cacheType = cacheType; + this.expireSeconds = expireSeconds; + this.lastAccessed = lastAccessed; + this.key = key; + this.objectValue = objectValue; + this.csetValue = csetValue; + this.listValue = listValue; + this.mapValue = mapValue; + } + + @Override + public String toString() { + return JsonFactory.root().getConvert().convertTo(this); + } + + @ConvertColumn(ignore = true) + public boolean isListCacheType() { + return cacheType == CacheEntryType.LONG_LIST || cacheType == CacheEntryType.STRING_LIST || cacheType == CacheEntryType.OBJECT_LIST; + } + + @ConvertColumn(ignore = true) + public boolean isSetCacheType() { + return cacheType == CacheEntryType.LONG_SET || cacheType == CacheEntryType.STRING_SET || cacheType == CacheEntryType.OBJECT_SET; + } + + @ConvertColumn(ignore = true) + public boolean isMapCacheType() { + return cacheType == CacheEntryType.MAP; + } + + @ConvertColumn(ignore = true) + public boolean isExpired() { + return (expireSeconds > 0 && lastAccessed + expireSeconds < (System.currentTimeMillis() / 1000)); + } + + public CacheEntryType getCacheType() { + return cacheType; + } + + public int getExpireSeconds() { + return expireSeconds; + } + + public int getLastAccessed() { + return lastAccessed; + } + + public String getKey() { + return key; + } + + public T getObjectValue() { + return objectValue; + } + + public CopyOnWriteArraySet getCsetValue() { + return csetValue; + } + + public ConcurrentLinkedQueue getListValue() { + return listValue; + } + + public ConcurrentHashMap getMapValue() { + return mapValue; + } + } +} diff --git a/src/main/java/org/redkale/source/CacheSource.java b/src/main/java/org/redkale/source/CacheSource.java index ad0377e9e..36cff644f 100644 --- a/src/main/java/org/redkale/source/CacheSource.java +++ b/src/main/java/org/redkale/source/CacheSource.java @@ -1,409 +1,409 @@ -/* - * 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.source; - -import java.io.Serializable; -import java.lang.reflect.Type; -import java.util.*; -import java.util.concurrent.*; -import org.redkale.convert.*; -import org.redkale.util.*; - -/** - * Redkale涓紦瀛樻暟鎹簮鐨勬牳蹇冪被銆 涓昏渚涗笟鍔″紑鍙戣呬娇鐢紝 鎶鏈紑鍙戣呮彁渚汣acheSource鐨勫疄鐜般
- * CacheSource鎻愪緵涓夌鏁版嵁绫诲瀷鎿嶄綔: String銆丩ong銆乥yte[]鍜屾硾鍨嬫寚瀹氱殑鏁版嵁绫诲瀷銆
- * String缁熶竴鐢╯etString銆乬etString绛夌郴鍒楁柟娉曘
- * Long缁熶竴鐢╯etLong銆乬etLong銆乮ncr绛夌郴鍒楁柟娉曘
- * byte[]缁熶竴鐢╯etBytes銆乬etBytes绛夌郴鍒楁柟娉曘
- * 鍏朵粬鍒欎緵鑷畾涔夋暟鎹被鍨嬩娇鐢ㄣ - * - * param V value鐨勭被鍨 绉婚櫎 @2.4.0 - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public interface CacheSource { - - public String getType(); - - //ServiceLoader鏃跺垽鏂厤缃槸鍚︾鍚堝綋鍓嶅疄鐜扮被 - public boolean acceptsConf(AnyValue config); - - default boolean isOpen() { - return true; - } - - public boolean exists(final String key); - - public T get(final String key, final Type type); - - public T getAndRefresh(final String key, final int expireSeconds, final Type type); - - //----------- hxxx -------------- - public int hremove(final String key, String... fields); - - public List hkeys(final String key); - - public int hsize(final String key); - - public long hincr(final String key, String field); - - public long hincr(final String key, String field, long num); - - public long hdecr(final String key, String field); - - public long hdecr(final String key, String field, long num); - - public boolean hexists(final String key, String field); - - public void hset(final String key, final String field, final Convert convert, final T value); - - public void hset(final String key, final String field, final Type type, final T value); - - public void hset(final String key, final String field, final Convert convert, final Type type, final T value); - - public void hsetString(final String key, final String field, final String value); - - public void hsetLong(final String key, final String field, final long value); - - public void hmset(final String key, final Serializable... values); - - public List hmget(final String key, final Type type, final String... fields); - - public Map hmap(final String key, final Type type, int offset, int limit); - - public Map hmap(final String key, final Type type, int offset, int limit, String pattern); - - public T hget(final String key, final String field, final Type type); - - public String hgetString(final String key, final String field); - - public long hgetLong(final String key, final String field, long defValue); - //----------- hxxx -------------- - - public void refresh(final String key, final int expireSeconds); - - public void set(final String key, final Convert convert, final T value); - - public void set(final String key, final Type type, final T value); - - public void set(final String key, final Convert convert, final Type type, final T value); - - public void set(final int expireSeconds, final String key, final Convert convert, final T value); - - public void set(final int expireSeconds, final String key, final Type type, final T value); - - public void set(final int expireSeconds, final String key, final Convert convert, final Type type, final T value); - - public void setExpireSeconds(final String key, final int expireSeconds); - - public int remove(final String key); - - public long incr(final String key); - - public long incr(final String key, long num); - - public long decr(final String key); - - public long decr(final String key, long num); - - public Map getMap(final Type componentType, final String... keys); - - public Collection getCollection(final String key, final Type componentType); - - public Map> getCollectionMap(final boolean set, final Type componentType, final String... keys); - - public int getCollectionSize(final String key); - - public Collection getCollectionAndRefresh(final String key, final int expireSeconds, final Type componentType); - - public void appendListItem(final String key, final Type componentType, final T value); - - public int removeListItem(final String key, final Type componentType, final T value); - - public boolean existsSetItem(final String key, final Type componentType, final T value); - - public void appendSetItem(final String key, final Type componentType, final T value); - - public int removeSetItem(final String key, final Type componentType, final T value); - - public T spopSetItem(final String key, final Type componentType); - - public Set spopSetItem(final String key, final int count, final Type componentType); - - public byte[] getBytes(final String key); - - public byte[] getBytesAndRefresh(final String key, final int expireSeconds); - - public void setBytes(final String key, final byte[] value); - - public void setBytes(final int expireSeconds, final String key, final byte[] value); - - public void setBytes(final String key, final Convert convert, final Type type, final T value); - - public void setBytes(final int expireSeconds, final String key, final Convert convert, final Type type, final T value); - - public List queryKeys(); - - public List queryKeysStartsWith(String startsWith); - - public List queryKeysEndsWith(String endsWith); - - public int getKeySize(); - - public String getString(final String key); - - public String getStringAndRefresh(final String key, final int expireSeconds); - - public void setString(final String key, final String value); - - public void setString(final int expireSeconds, final String key, final String value); - - public Map getStringMap(final String... keys); - - public String[] getStringArray(final String... keys); - - public Collection getStringCollection(final String key); - - public Map> getStringCollectionMap(final boolean set, final String... keys); - - public Collection getStringCollectionAndRefresh(final String key, final int expireSeconds); - - public void appendStringListItem(final String key, final String value); - - public String spopStringSetItem(final String key); - - public Set spopStringSetItem(final String key, final int count); - - public int removeStringListItem(final String key, final String value); - - public boolean existsStringSetItem(final String key, final String value); - - public void appendStringSetItem(final String key, final String value); - - public int removeStringSetItem(final String key, final String value); - - public long getLong(final String key, long defValue); - - public long getLongAndRefresh(final String key, final int expireSeconds, long defValue); - - public void setLong(final String key, final long value); - - public void setLong(final int expireSeconds, final String key, final long value); - - public Map getLongMap(final String... keys); - - public Long[] getLongArray(final String... keys); - - public Collection getLongCollection(final String key); - - public Map> getLongCollectionMap(final boolean set, final String... keys); - - public Collection getLongCollectionAndRefresh(final String key, final int expireSeconds); - - public void appendLongListItem(final String key, final long value); - - public Long spopLongSetItem(final String key); - - public Set spopLongSetItem(final String key, final int count); - - public int removeLongListItem(final String key, final long value); - - public boolean existsLongSetItem(final String key, final long value); - - public void appendLongSetItem(final String key, final long value); - - public int removeLongSetItem(final String key, final long value); - - //---------------------- CompletableFuture 寮傛鐗 --------------------------------- - public CompletableFuture existsAsync(final String key); - - public CompletableFuture getAsync(final String key, final Type type); - - public CompletableFuture getAndRefreshAsync(final String key, final int expireSeconds, final Type type); - - public CompletableFuture refreshAsync(final String key, final int expireSeconds); - - public CompletableFuture setAsync(final String key, final Convert convert, final T value); - - public CompletableFuture setAsync(final String key, final Type type, final T value); - - public CompletableFuture setAsync(final String key, final Convert convert, final Type type, final T value); - - public CompletableFuture setAsync(final int expireSeconds, final String key, final Convert convert, final T value); - - public CompletableFuture setAsync(final int expireSeconds, final String key, final Type type, final T value); - - public CompletableFuture setAsync(final int expireSeconds, final String key, final Convert convert, final Type type, final T value); - - public CompletableFuture setExpireSecondsAsync(final String key, final int expireSeconds); - - public CompletableFuture removeAsync(final String key); - - public CompletableFuture incrAsync(final String key); - - public CompletableFuture incrAsync(final String key, long num); - - public CompletableFuture decrAsync(final String key); - - public CompletableFuture decrAsync(final String key, long num); - - //----------- hxxx -------------- - public CompletableFuture hremoveAsync(final String key, String... fields); - - public CompletableFuture> hkeysAsync(final String key); - - public CompletableFuture hsizeAsync(final String key); - - public CompletableFuture hincrAsync(final String key, String field); - - public CompletableFuture hincrAsync(final String key, String field, long num); - - public CompletableFuture hdecrAsync(final String key, String field); - - public CompletableFuture hdecrAsync(final String key, String field, long num); - - public CompletableFuture hexistsAsync(final String key, String field); - - public CompletableFuture hsetAsync(final String key, final String field, final Convert convert, final T value); - - public CompletableFuture hsetAsync(final String key, final String field, final Type type, final T value); - - public CompletableFuture hsetAsync(final String key, final String field, final Convert convert, final Type type, final T value); - - public CompletableFuture hsetStringAsync(final String key, final String field, final String value); - - public CompletableFuture hsetLongAsync(final String key, final String field, final long value); - - public CompletableFuture hmsetAsync(final String key, final Serializable... values); - - public CompletableFuture> hmgetAsync(final String key, final Type type, final String... fields); - - public CompletableFuture> hmapAsync(final String key, final Type type, int offset, int limit); - - public CompletableFuture> hmapAsync(final String key, final Type type, int offset, int limit, String pattern); - - public CompletableFuture hgetAsync(final String key, final String field, final Type type); - - public CompletableFuture hgetStringAsync(final String key, final String field); - - public CompletableFuture hgetLongAsync(final String key, final String field, long defValue); - //----------- hxxx -------------- - - public CompletableFuture> getMapAsync(final Type componentType, final String... keys); - - public CompletableFuture> getCollectionAsync(final String key, final Type componentType); - - public CompletableFuture>> getCollectionMapAsync(final boolean set, final Type componentType, final String... keys); - - public CompletableFuture getCollectionSizeAsync(final String key); - - public CompletableFuture> getCollectionAndRefreshAsync(final String key, final int expireSeconds, final Type componentType); - - public CompletableFuture spopSetItemAsync(final String key, final Type componentType); - - public CompletableFuture> spopSetItemAsync(final String key, final int count, final Type componentType); - - public CompletableFuture appendListItemAsync(final String key, final Type componentType, final T value); - - public CompletableFuture removeListItemAsync(final String key, final Type componentType, final T value); - - public CompletableFuture existsSetItemAsync(final String key, final Type componentType, final T value); - - public CompletableFuture appendSetItemAsync(final String key, final Type componentType, final T value); - - public CompletableFuture removeSetItemAsync(final String key, final Type componentType, final T value); - - public CompletableFuture getBytesAsync(final String key); - - public CompletableFuture getBytesAndRefreshAsync(final String key, final int expireSeconds); - - public CompletableFuture setBytesAsync(final String key, final byte[] value); - - public CompletableFuture setBytesAsync(final int expireSeconds, final String key, final byte[] value); - - public CompletableFuture setBytesAsync(final String key, final Convert convert, final Type type, final T value); - - public CompletableFuture setBytesAsync(final int expireSeconds, final String key, final Convert convert, final Type type, final T value); - - public CompletableFuture> queryKeysAsync(); - - public CompletableFuture> queryKeysStartsWithAsync(String startsWith); - - public CompletableFuture> queryKeysEndsWithAsync(String endsWith); - - public CompletableFuture getKeySizeAsync(); - - public CompletableFuture getStringAsync(final String key); - - public CompletableFuture getStringAndRefreshAsync(final String key, final int expireSeconds); - - public CompletableFuture setStringAsync(final String key, final String value); - - public CompletableFuture setStringAsync(final int expireSeconds, final String key, final String value); - - public CompletableFuture> getStringMapAsync(final String... keys); - - public CompletableFuture getStringArrayAsync(final String... keys); - - public CompletableFuture> getStringCollectionAsync(final String key); - - public CompletableFuture>> getStringCollectionMapAsync(final boolean set, final String... keys); - - public CompletableFuture> getStringCollectionAndRefreshAsync(final String key, final int expireSeconds); - - public CompletableFuture appendStringListItemAsync(final String key, final String value); - - public CompletableFuture spopStringSetItemAsync(final String key); - - public CompletableFuture> spopStringSetItemAsync(final String key, final int count); - - public CompletableFuture removeStringListItemAsync(final String key, final String value); - - public CompletableFuture existsStringSetItemAsync(final String key, final String value); - - public CompletableFuture appendStringSetItemAsync(final String key, final String value); - - public CompletableFuture removeStringSetItemAsync(final String key, final String value); - - public CompletableFuture getLongAsync(final String key, long defValue); - - public CompletableFuture getLongAndRefreshAsync(final String key, final int expireSeconds, long defValue); - - public CompletableFuture setLongAsync(final String key, long value); - - public CompletableFuture setLongAsync(final int expireSeconds, final String key, final long value); - - public CompletableFuture> getLongMapAsync(final String... keys); - - public CompletableFuture getLongArrayAsync(final String... keys); - - public CompletableFuture> getLongCollectionAsync(final String key); - - public CompletableFuture>> getLongCollectionMapAsync(final boolean set, final String... keys); - - public CompletableFuture> getLongCollectionAndRefreshAsync(final String key, final int expireSeconds); - - public CompletableFuture appendLongListItemAsync(final String key, final long value); - - public CompletableFuture spopLongSetItemAsync(final String key); - - public CompletableFuture> spopLongSetItemAsync(final String key, final int count); - - public CompletableFuture removeLongListItemAsync(final String key, final long value); - - public CompletableFuture existsLongSetItemAsync(final String key, final long value); - - public CompletableFuture appendLongSetItemAsync(final String key, final long value); - - public CompletableFuture removeLongSetItemAsync(final String key, final long value); - - default CompletableFuture isOpenAsync() { - return CompletableFuture.completedFuture(isOpen()); - } - -} +/* + * 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.source; + +import java.io.Serializable; +import java.lang.reflect.Type; +import java.util.*; +import java.util.concurrent.*; +import org.redkale.convert.*; +import org.redkale.util.*; + +/** + * Redkale涓紦瀛樻暟鎹簮鐨勬牳蹇冪被銆 涓昏渚涗笟鍔″紑鍙戣呬娇鐢紝 鎶鏈紑鍙戣呮彁渚汣acheSource鐨勫疄鐜般
+ * CacheSource鎻愪緵涓夌鏁版嵁绫诲瀷鎿嶄綔: String銆丩ong銆乥yte[]鍜屾硾鍨嬫寚瀹氱殑鏁版嵁绫诲瀷銆
+ * String缁熶竴鐢╯etString銆乬etString绛夌郴鍒楁柟娉曘
+ * Long缁熶竴鐢╯etLong銆乬etLong銆乮ncr绛夌郴鍒楁柟娉曘
+ * byte[]缁熶竴鐢╯etBytes銆乬etBytes绛夌郴鍒楁柟娉曘
+ * 鍏朵粬鍒欎緵鑷畾涔夋暟鎹被鍨嬩娇鐢ㄣ + * + * param V value鐨勭被鍨 绉婚櫎 @2.4.0 + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public interface CacheSource { + + public String getType(); + + //ServiceLoader鏃跺垽鏂厤缃槸鍚︾鍚堝綋鍓嶅疄鐜扮被 + public boolean acceptsConf(AnyValue config); + + default boolean isOpen() { + return true; + } + + public boolean exists(final String key); + + public T get(final String key, final Type type); + + public T getAndRefresh(final String key, final int expireSeconds, final Type type); + + //----------- hxxx -------------- + public int hremove(final String key, String... fields); + + public List hkeys(final String key); + + public int hsize(final String key); + + public long hincr(final String key, String field); + + public long hincr(final String key, String field, long num); + + public long hdecr(final String key, String field); + + public long hdecr(final String key, String field, long num); + + public boolean hexists(final String key, String field); + + public void hset(final String key, final String field, final Convert convert, final T value); + + public void hset(final String key, final String field, final Type type, final T value); + + public void hset(final String key, final String field, final Convert convert, final Type type, final T value); + + public void hsetString(final String key, final String field, final String value); + + public void hsetLong(final String key, final String field, final long value); + + public void hmset(final String key, final Serializable... values); + + public List hmget(final String key, final Type type, final String... fields); + + public Map hmap(final String key, final Type type, int offset, int limit); + + public Map hmap(final String key, final Type type, int offset, int limit, String pattern); + + public T hget(final String key, final String field, final Type type); + + public String hgetString(final String key, final String field); + + public long hgetLong(final String key, final String field, long defValue); + //----------- hxxx -------------- + + public void refresh(final String key, final int expireSeconds); + + public void set(final String key, final Convert convert, final T value); + + public void set(final String key, final Type type, final T value); + + public void set(final String key, final Convert convert, final Type type, final T value); + + public void set(final int expireSeconds, final String key, final Convert convert, final T value); + + public void set(final int expireSeconds, final String key, final Type type, final T value); + + public void set(final int expireSeconds, final String key, final Convert convert, final Type type, final T value); + + public void setExpireSeconds(final String key, final int expireSeconds); + + public int remove(final String key); + + public long incr(final String key); + + public long incr(final String key, long num); + + public long decr(final String key); + + public long decr(final String key, long num); + + public Map getMap(final Type componentType, final String... keys); + + public Collection getCollection(final String key, final Type componentType); + + public Map> getCollectionMap(final boolean set, final Type componentType, final String... keys); + + public int getCollectionSize(final String key); + + public Collection getCollectionAndRefresh(final String key, final int expireSeconds, final Type componentType); + + public void appendListItem(final String key, final Type componentType, final T value); + + public int removeListItem(final String key, final Type componentType, final T value); + + public boolean existsSetItem(final String key, final Type componentType, final T value); + + public void appendSetItem(final String key, final Type componentType, final T value); + + public int removeSetItem(final String key, final Type componentType, final T value); + + public T spopSetItem(final String key, final Type componentType); + + public Set spopSetItem(final String key, final int count, final Type componentType); + + public byte[] getBytes(final String key); + + public byte[] getBytesAndRefresh(final String key, final int expireSeconds); + + public void setBytes(final String key, final byte[] value); + + public void setBytes(final int expireSeconds, final String key, final byte[] value); + + public void setBytes(final String key, final Convert convert, final Type type, final T value); + + public void setBytes(final int expireSeconds, final String key, final Convert convert, final Type type, final T value); + + public List queryKeys(); + + public List queryKeysStartsWith(String startsWith); + + public List queryKeysEndsWith(String endsWith); + + public int getKeySize(); + + public String getString(final String key); + + public String getStringAndRefresh(final String key, final int expireSeconds); + + public void setString(final String key, final String value); + + public void setString(final int expireSeconds, final String key, final String value); + + public Map getStringMap(final String... keys); + + public String[] getStringArray(final String... keys); + + public Collection getStringCollection(final String key); + + public Map> getStringCollectionMap(final boolean set, final String... keys); + + public Collection getStringCollectionAndRefresh(final String key, final int expireSeconds); + + public void appendStringListItem(final String key, final String value); + + public String spopStringSetItem(final String key); + + public Set spopStringSetItem(final String key, final int count); + + public int removeStringListItem(final String key, final String value); + + public boolean existsStringSetItem(final String key, final String value); + + public void appendStringSetItem(final String key, final String value); + + public int removeStringSetItem(final String key, final String value); + + public long getLong(final String key, long defValue); + + public long getLongAndRefresh(final String key, final int expireSeconds, long defValue); + + public void setLong(final String key, final long value); + + public void setLong(final int expireSeconds, final String key, final long value); + + public Map getLongMap(final String... keys); + + public Long[] getLongArray(final String... keys); + + public Collection getLongCollection(final String key); + + public Map> getLongCollectionMap(final boolean set, final String... keys); + + public Collection getLongCollectionAndRefresh(final String key, final int expireSeconds); + + public void appendLongListItem(final String key, final long value); + + public Long spopLongSetItem(final String key); + + public Set spopLongSetItem(final String key, final int count); + + public int removeLongListItem(final String key, final long value); + + public boolean existsLongSetItem(final String key, final long value); + + public void appendLongSetItem(final String key, final long value); + + public int removeLongSetItem(final String key, final long value); + + //---------------------- CompletableFuture 寮傛鐗 --------------------------------- + public CompletableFuture existsAsync(final String key); + + public CompletableFuture getAsync(final String key, final Type type); + + public CompletableFuture getAndRefreshAsync(final String key, final int expireSeconds, final Type type); + + public CompletableFuture refreshAsync(final String key, final int expireSeconds); + + public CompletableFuture setAsync(final String key, final Convert convert, final T value); + + public CompletableFuture setAsync(final String key, final Type type, final T value); + + public CompletableFuture setAsync(final String key, final Convert convert, final Type type, final T value); + + public CompletableFuture setAsync(final int expireSeconds, final String key, final Convert convert, final T value); + + public CompletableFuture setAsync(final int expireSeconds, final String key, final Type type, final T value); + + public CompletableFuture setAsync(final int expireSeconds, final String key, final Convert convert, final Type type, final T value); + + public CompletableFuture setExpireSecondsAsync(final String key, final int expireSeconds); + + public CompletableFuture removeAsync(final String key); + + public CompletableFuture incrAsync(final String key); + + public CompletableFuture incrAsync(final String key, long num); + + public CompletableFuture decrAsync(final String key); + + public CompletableFuture decrAsync(final String key, long num); + + //----------- hxxx -------------- + public CompletableFuture hremoveAsync(final String key, String... fields); + + public CompletableFuture> hkeysAsync(final String key); + + public CompletableFuture hsizeAsync(final String key); + + public CompletableFuture hincrAsync(final String key, String field); + + public CompletableFuture hincrAsync(final String key, String field, long num); + + public CompletableFuture hdecrAsync(final String key, String field); + + public CompletableFuture hdecrAsync(final String key, String field, long num); + + public CompletableFuture hexistsAsync(final String key, String field); + + public CompletableFuture hsetAsync(final String key, final String field, final Convert convert, final T value); + + public CompletableFuture hsetAsync(final String key, final String field, final Type type, final T value); + + public CompletableFuture hsetAsync(final String key, final String field, final Convert convert, final Type type, final T value); + + public CompletableFuture hsetStringAsync(final String key, final String field, final String value); + + public CompletableFuture hsetLongAsync(final String key, final String field, final long value); + + public CompletableFuture hmsetAsync(final String key, final Serializable... values); + + public CompletableFuture> hmgetAsync(final String key, final Type type, final String... fields); + + public CompletableFuture> hmapAsync(final String key, final Type type, int offset, int limit); + + public CompletableFuture> hmapAsync(final String key, final Type type, int offset, int limit, String pattern); + + public CompletableFuture hgetAsync(final String key, final String field, final Type type); + + public CompletableFuture hgetStringAsync(final String key, final String field); + + public CompletableFuture hgetLongAsync(final String key, final String field, long defValue); + //----------- hxxx -------------- + + public CompletableFuture> getMapAsync(final Type componentType, final String... keys); + + public CompletableFuture> getCollectionAsync(final String key, final Type componentType); + + public CompletableFuture>> getCollectionMapAsync(final boolean set, final Type componentType, final String... keys); + + public CompletableFuture getCollectionSizeAsync(final String key); + + public CompletableFuture> getCollectionAndRefreshAsync(final String key, final int expireSeconds, final Type componentType); + + public CompletableFuture spopSetItemAsync(final String key, final Type componentType); + + public CompletableFuture> spopSetItemAsync(final String key, final int count, final Type componentType); + + public CompletableFuture appendListItemAsync(final String key, final Type componentType, final T value); + + public CompletableFuture removeListItemAsync(final String key, final Type componentType, final T value); + + public CompletableFuture existsSetItemAsync(final String key, final Type componentType, final T value); + + public CompletableFuture appendSetItemAsync(final String key, final Type componentType, final T value); + + public CompletableFuture removeSetItemAsync(final String key, final Type componentType, final T value); + + public CompletableFuture getBytesAsync(final String key); + + public CompletableFuture getBytesAndRefreshAsync(final String key, final int expireSeconds); + + public CompletableFuture setBytesAsync(final String key, final byte[] value); + + public CompletableFuture setBytesAsync(final int expireSeconds, final String key, final byte[] value); + + public CompletableFuture setBytesAsync(final String key, final Convert convert, final Type type, final T value); + + public CompletableFuture setBytesAsync(final int expireSeconds, final String key, final Convert convert, final Type type, final T value); + + public CompletableFuture> queryKeysAsync(); + + public CompletableFuture> queryKeysStartsWithAsync(String startsWith); + + public CompletableFuture> queryKeysEndsWithAsync(String endsWith); + + public CompletableFuture getKeySizeAsync(); + + public CompletableFuture getStringAsync(final String key); + + public CompletableFuture getStringAndRefreshAsync(final String key, final int expireSeconds); + + public CompletableFuture setStringAsync(final String key, final String value); + + public CompletableFuture setStringAsync(final int expireSeconds, final String key, final String value); + + public CompletableFuture> getStringMapAsync(final String... keys); + + public CompletableFuture getStringArrayAsync(final String... keys); + + public CompletableFuture> getStringCollectionAsync(final String key); + + public CompletableFuture>> getStringCollectionMapAsync(final boolean set, final String... keys); + + public CompletableFuture> getStringCollectionAndRefreshAsync(final String key, final int expireSeconds); + + public CompletableFuture appendStringListItemAsync(final String key, final String value); + + public CompletableFuture spopStringSetItemAsync(final String key); + + public CompletableFuture> spopStringSetItemAsync(final String key, final int count); + + public CompletableFuture removeStringListItemAsync(final String key, final String value); + + public CompletableFuture existsStringSetItemAsync(final String key, final String value); + + public CompletableFuture appendStringSetItemAsync(final String key, final String value); + + public CompletableFuture removeStringSetItemAsync(final String key, final String value); + + public CompletableFuture getLongAsync(final String key, long defValue); + + public CompletableFuture getLongAndRefreshAsync(final String key, final int expireSeconds, long defValue); + + public CompletableFuture setLongAsync(final String key, long value); + + public CompletableFuture setLongAsync(final int expireSeconds, final String key, final long value); + + public CompletableFuture> getLongMapAsync(final String... keys); + + public CompletableFuture getLongArrayAsync(final String... keys); + + public CompletableFuture> getLongCollectionAsync(final String key); + + public CompletableFuture>> getLongCollectionMapAsync(final boolean set, final String... keys); + + public CompletableFuture> getLongCollectionAndRefreshAsync(final String key, final int expireSeconds); + + public CompletableFuture appendLongListItemAsync(final String key, final long value); + + public CompletableFuture spopLongSetItemAsync(final String key); + + public CompletableFuture> spopLongSetItemAsync(final String key, final int count); + + public CompletableFuture removeLongListItemAsync(final String key, final long value); + + public CompletableFuture existsLongSetItemAsync(final String key, final long value); + + public CompletableFuture appendLongSetItemAsync(final String key, final long value); + + public CompletableFuture removeLongSetItemAsync(final String key, final long value); + + default CompletableFuture isOpenAsync() { + return CompletableFuture.completedFuture(isOpen()); + } + +} diff --git a/src/main/java/org/redkale/source/CacheSourceProvider.java b/src/main/java/org/redkale/source/CacheSourceProvider.java index 2c220d2b8..f43b4af9f 100644 --- a/src/main/java/org/redkale/source/CacheSourceProvider.java +++ b/src/main/java/org/redkale/source/CacheSourceProvider.java @@ -1,25 +1,25 @@ -/* - * 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.source; - -import org.redkale.util.AnyValue; - -/** - * - * 鑷畾涔夌殑CacheSource鍔犺浇鍣, 濡傛灉鏍囪@Priority鍔犺浇鍣ㄧ殑浼樺厛绾ч渶瑕佸ぇ浜1000锛 1000浠ヤ笅棰勭暀缁欏畼鏂瑰姞杞藉櫒 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @since 2.5.0 - */ -public interface CacheSourceProvider { - - public boolean acceptsConf(AnyValue config); - - public Class sourceClass(); -} +/* + * 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.source; + +import org.redkale.util.AnyValue; + +/** + * + * 鑷畾涔夌殑CacheSource鍔犺浇鍣, 濡傛灉鏍囪@Priority鍔犺浇鍣ㄧ殑浼樺厛绾ч渶瑕佸ぇ浜1000锛 1000浠ヤ笅棰勭暀缁欏畼鏂瑰姞杞藉櫒 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @since 2.5.0 + */ +public interface CacheSourceProvider { + + public boolean acceptsConf(AnyValue config); + + public Class sourceClass(); +} diff --git a/src/main/java/org/redkale/source/ColumnExpress.java b/src/main/java/org/redkale/source/ColumnExpress.java index b07c5a9a9..dcfd6c807 100644 --- a/src/main/java/org/redkale/source/ColumnExpress.java +++ b/src/main/java/org/redkale/source/ColumnExpress.java @@ -1,49 +1,49 @@ -/* - * 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.source; - -/** - * 鍑芥暟琛ㄨ揪寮忥紝 鍧囦笌SQL瀹氫箟涓殑琛ㄨ揪寮忕浉鍚 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public enum ColumnExpress { - /** - * 璧嬪 col = val - */ - MOV, - /** - * 鍔犲 col = col + val - */ - INC, - /** - * 鍔犲 col = col - val - */ - DEC, - /** - * 涔樺 col = col * val - */ - MUL, - /** - * 闄ゅ col = col / val - */ - DIV, - /** - * 鍙栨ā col = col % val - */ - MOD, - /** - * 涓庡 col = col & val - */ - AND, //涓庡 col = col & val - /** - * 鎴栧 col = col | val - */ - ORR; -} +/* + * 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.source; + +/** + * 鍑芥暟琛ㄨ揪寮忥紝 鍧囦笌SQL瀹氫箟涓殑琛ㄨ揪寮忕浉鍚 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public enum ColumnExpress { + /** + * 璧嬪 col = val + */ + MOV, + /** + * 鍔犲 col = col + val + */ + INC, + /** + * 鍔犲 col = col - val + */ + DEC, + /** + * 涔樺 col = col * val + */ + MUL, + /** + * 闄ゅ col = col / val + */ + DIV, + /** + * 鍙栨ā col = col % val + */ + MOD, + /** + * 涓庡 col = col & val + */ + AND, //涓庡 col = col & val + /** + * 鎴栧 col = col | val + */ + ORR; +} diff --git a/src/main/java/org/redkale/source/ColumnFuncNode.java b/src/main/java/org/redkale/source/ColumnFuncNode.java index 7edcfa2cd..c0ba981ec 100644 --- a/src/main/java/org/redkale/source/ColumnFuncNode.java +++ b/src/main/java/org/redkale/source/ColumnFuncNode.java @@ -1,83 +1,83 @@ -/* - * 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.source; - -import java.io.Serializable; - -/** - * 涓嶤olumnNodeValue 缁勫悎锛岀敤浜庡鏉傜殑瀛楁琛ㄨ揪寮 銆 - * String 瑙嗕负 瀛楁鍚 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @since 2.0.0 - */ -public class ColumnFuncNode implements ColumnNode { - - protected FilterFunc func; - - protected Serializable value;//绫诲瀷鍙兘鏄疭tring銆丆olumnNodeValue - - public ColumnFuncNode() { - } - - public ColumnFuncNode(FilterFunc func, Serializable node) { - if (!(node instanceof String) && !(node instanceof ColumnNodeValue)) throw new IllegalArgumentException("value must be String or ColumnNodeValue"); - this.func = func; - this.value = node; - } - - public static ColumnFuncNode create(FilterFunc func, Serializable node) { - return new ColumnFuncNode(func, node); - } - - public static ColumnFuncNode avg(Serializable node) { - return new ColumnFuncNode(FilterFunc.AVG, node); - } - - public static ColumnFuncNode count(Serializable node) { - return new ColumnFuncNode(FilterFunc.COUNT, node); - } - - public static ColumnFuncNode distinctCount(Serializable node) { - return new ColumnFuncNode(FilterFunc.DISTINCTCOUNT, node); - } - - public static ColumnFuncNode max(Serializable node) { - return new ColumnFuncNode(FilterFunc.MAX, node); - } - - public static ColumnFuncNode min(Serializable node) { - return new ColumnFuncNode(FilterFunc.MIN, node); - } - - public static ColumnFuncNode sum(Serializable node) { - return new ColumnFuncNode(FilterFunc.SUM, node); - } - - public FilterFunc getFunc() { - return func; - } - - public void setFunc(FilterFunc func) { - this.func = func; - } - - public Serializable getValue() { - return value; - } - - public void setValue(Serializable value) { - this.value = value; - } - - @Override - public String toString() { - return "{\"func\":\"" + func + "\", \"value\":" + ((value instanceof CharSequence) ? ("\"" + value + "\"") : value) + "}"; - } -} +/* + * 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.source; + +import java.io.Serializable; + +/** + * 涓嶤olumnNodeValue 缁勫悎锛岀敤浜庡鏉傜殑瀛楁琛ㄨ揪寮 銆 + * String 瑙嗕负 瀛楁鍚 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @since 2.0.0 + */ +public class ColumnFuncNode implements ColumnNode { + + protected FilterFunc func; + + protected Serializable value;//绫诲瀷鍙兘鏄疭tring銆丆olumnNodeValue + + public ColumnFuncNode() { + } + + public ColumnFuncNode(FilterFunc func, Serializable node) { + if (!(node instanceof String) && !(node instanceof ColumnNodeValue)) throw new IllegalArgumentException("value must be String or ColumnNodeValue"); + this.func = func; + this.value = node; + } + + public static ColumnFuncNode create(FilterFunc func, Serializable node) { + return new ColumnFuncNode(func, node); + } + + public static ColumnFuncNode avg(Serializable node) { + return new ColumnFuncNode(FilterFunc.AVG, node); + } + + public static ColumnFuncNode count(Serializable node) { + return new ColumnFuncNode(FilterFunc.COUNT, node); + } + + public static ColumnFuncNode distinctCount(Serializable node) { + return new ColumnFuncNode(FilterFunc.DISTINCTCOUNT, node); + } + + public static ColumnFuncNode max(Serializable node) { + return new ColumnFuncNode(FilterFunc.MAX, node); + } + + public static ColumnFuncNode min(Serializable node) { + return new ColumnFuncNode(FilterFunc.MIN, node); + } + + public static ColumnFuncNode sum(Serializable node) { + return new ColumnFuncNode(FilterFunc.SUM, node); + } + + public FilterFunc getFunc() { + return func; + } + + public void setFunc(FilterFunc func) { + this.func = func; + } + + public Serializable getValue() { + return value; + } + + public void setValue(Serializable value) { + this.value = value; + } + + @Override + public String toString() { + return "{\"func\":\"" + func + "\", \"value\":" + ((value instanceof CharSequence) ? ("\"" + value + "\"") : value) + "}"; + } +} diff --git a/src/main/java/org/redkale/source/ColumnNode.java b/src/main/java/org/redkale/source/ColumnNode.java index b62b4a62c..e73e69015 100644 --- a/src/main/java/org/redkale/source/ColumnNode.java +++ b/src/main/java/org/redkale/source/ColumnNode.java @@ -1,21 +1,21 @@ -/* - * 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.source; - -import java.io.Serializable; - -/** - * ColumnFuncNode涓嶤olumnNodeValue 鐨勬帴鍙 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @since 2.0.0 - */ -public interface ColumnNode extends Serializable { - -} +/* + * 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.source; + +import java.io.Serializable; + +/** + * ColumnFuncNode涓嶤olumnNodeValue 鐨勬帴鍙 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @since 2.0.0 + */ +public interface ColumnNode extends Serializable { + +} diff --git a/src/main/java/org/redkale/source/ColumnNodeValue.java b/src/main/java/org/redkale/source/ColumnNodeValue.java index 0627fa8af..5405bec1d 100644 --- a/src/main/java/org/redkale/source/ColumnNodeValue.java +++ b/src/main/java/org/redkale/source/ColumnNodeValue.java @@ -1,154 +1,154 @@ -/* - * 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.source; - -import java.io.Serializable; -import static org.redkale.source.ColumnExpress.*; - -/** - * 浣滀负ColumnValue鐨剉alue瀛楁鍊硷紝鐢ㄤ簬澶嶆潅鐨勫瓧娈佃〃杈惧紡 銆
- * String 瑙嗕负 瀛楁鍚
- * Number 瑙嗕负 鏁板
- * 渚嬪锛 UPDATE Reord SET updateTime = createTime + 10 WHERE id = 1
- * source.updateColumn(Record.class, 1, ColumnValue.mov("updateTime", ColumnNodeValue.inc("createTime", 10))); - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @since 2.0.0 - */ -public class ColumnNodeValue implements ColumnNode { - - protected Serializable left;//绫诲瀷鍙兘鏄疭tring銆丯umber銆丆olumnNodeValue - - protected ColumnExpress express; //MOV鏃讹紝left蹇呴』鏄疭tring, right蹇呴』鏄痭ull - - protected Serializable right;//绫诲瀷鍙兘鏄疭tring銆丯umber銆丆olumnNodeValue - - public ColumnNodeValue() { - } - - public ColumnNodeValue(Serializable left, ColumnExpress express, Serializable right) { - if (express == null) { - throw new IllegalArgumentException("express cannot be null"); - } - if (express == MOV) { - if (!(left instanceof String) || right != null) throw new IllegalArgumentException("left value must be String, right value must be null on ColumnExpress.MOV"); - } else { - if (!(left instanceof String) && !(left instanceof Number) && !(left instanceof ColumnNodeValue) && !(left instanceof ColumnFuncNode)) { - throw new IllegalArgumentException("left value must be String, Number, ColumnFuncNode or ColumnNodeValue"); - } - if (!(right instanceof String) && !(right instanceof Number) && !(right instanceof ColumnNodeValue) && !(right instanceof ColumnFuncNode)) { - throw new IllegalArgumentException("right value must be String, Number, ColumnFuncNode or ColumnNodeValue"); - } - } - this.left = left; - this.express = express; - this.right = right; - } - - public static ColumnNodeValue create(Serializable left, ColumnExpress express, Serializable right) { - return new ColumnNodeValue(left, express, right); - } - - public static ColumnNodeValue mov(String left) { - return new ColumnNodeValue(left, MOV, null); - } - - public static ColumnNodeValue inc(Serializable left, Serializable right) { - return new ColumnNodeValue(left, INC, right); - } - - public static ColumnNodeValue dec(Serializable left, Serializable right) { - return new ColumnNodeValue(left, DEC, right); - } - - public static ColumnNodeValue mul(Serializable left, Serializable right) { - return new ColumnNodeValue(left, MUL, right); - } - - public static ColumnNodeValue div(Serializable left, Serializable right) { - return new ColumnNodeValue(left, DIV, right); - } - - public static ColumnNodeValue mod(Serializable left, Serializable right) { - return new ColumnNodeValue(left, MOD, right); - } - - public static ColumnNodeValue and(Serializable left, Serializable right) { - return new ColumnNodeValue(left, AND, right); - } - - public static ColumnNodeValue orr(Serializable left, Serializable right) { - return new ColumnNodeValue(left, ORR, right); - } - - public ColumnNodeValue inc(Serializable right) { - return any(INC, right); - } - - public ColumnNodeValue dec(Serializable right) { - return any(DEC, right); - } - - public ColumnNodeValue mul(Serializable right) { - return any(MUL, right); - } - - public ColumnNodeValue div(Serializable right) { - return any(DIV, right); - } - - public ColumnNodeValue mod(Serializable right) { - return any(MOD, right); - } - - public ColumnNodeValue and(Serializable right) { - return any(AND, right); - } - - public ColumnNodeValue orr(Serializable right) { - return any(ORR, right); - } - - protected ColumnNodeValue any(ColumnExpress express, Serializable right) { - ColumnNodeValue one = new ColumnNodeValue(this.left, this.express, this.right); - this.left = one; - this.express = express; - this.right = right; - return this; - } - - public Serializable getLeft() { - return left; - } - - public void setLeft(Serializable left) { - this.left = left; - } - - public ColumnExpress getExpress() { - return express; - } - - public void setExpress(ColumnExpress express) { - this.express = express; - } - - public Serializable getRight() { - return right; - } - - public void setRight(Serializable right) { - this.right = right; - } - - @Override - public String toString() { - return "{\"column\":" + ((left instanceof CharSequence) ? ("\"" + left + "\"") : left) + ", \"express\":" + express + ", \"value\":" + ((right instanceof CharSequence) ? ("\"" + right + "\"") : right) + "}"; - } -} +/* + * 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.source; + +import java.io.Serializable; +import static org.redkale.source.ColumnExpress.*; + +/** + * 浣滀负ColumnValue鐨剉alue瀛楁鍊硷紝鐢ㄤ簬澶嶆潅鐨勫瓧娈佃〃杈惧紡 銆
+ * String 瑙嗕负 瀛楁鍚
+ * Number 瑙嗕负 鏁板
+ * 渚嬪锛 UPDATE Reord SET updateTime = createTime + 10 WHERE id = 1
+ * source.updateColumn(Record.class, 1, ColumnValue.mov("updateTime", ColumnNodeValue.inc("createTime", 10))); + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @since 2.0.0 + */ +public class ColumnNodeValue implements ColumnNode { + + protected Serializable left;//绫诲瀷鍙兘鏄疭tring銆丯umber銆丆olumnNodeValue + + protected ColumnExpress express; //MOV鏃讹紝left蹇呴』鏄疭tring, right蹇呴』鏄痭ull + + protected Serializable right;//绫诲瀷鍙兘鏄疭tring銆丯umber銆丆olumnNodeValue + + public ColumnNodeValue() { + } + + public ColumnNodeValue(Serializable left, ColumnExpress express, Serializable right) { + if (express == null) { + throw new IllegalArgumentException("express cannot be null"); + } + if (express == MOV) { + if (!(left instanceof String) || right != null) throw new IllegalArgumentException("left value must be String, right value must be null on ColumnExpress.MOV"); + } else { + if (!(left instanceof String) && !(left instanceof Number) && !(left instanceof ColumnNodeValue) && !(left instanceof ColumnFuncNode)) { + throw new IllegalArgumentException("left value must be String, Number, ColumnFuncNode or ColumnNodeValue"); + } + if (!(right instanceof String) && !(right instanceof Number) && !(right instanceof ColumnNodeValue) && !(right instanceof ColumnFuncNode)) { + throw new IllegalArgumentException("right value must be String, Number, ColumnFuncNode or ColumnNodeValue"); + } + } + this.left = left; + this.express = express; + this.right = right; + } + + public static ColumnNodeValue create(Serializable left, ColumnExpress express, Serializable right) { + return new ColumnNodeValue(left, express, right); + } + + public static ColumnNodeValue mov(String left) { + return new ColumnNodeValue(left, MOV, null); + } + + public static ColumnNodeValue inc(Serializable left, Serializable right) { + return new ColumnNodeValue(left, INC, right); + } + + public static ColumnNodeValue dec(Serializable left, Serializable right) { + return new ColumnNodeValue(left, DEC, right); + } + + public static ColumnNodeValue mul(Serializable left, Serializable right) { + return new ColumnNodeValue(left, MUL, right); + } + + public static ColumnNodeValue div(Serializable left, Serializable right) { + return new ColumnNodeValue(left, DIV, right); + } + + public static ColumnNodeValue mod(Serializable left, Serializable right) { + return new ColumnNodeValue(left, MOD, right); + } + + public static ColumnNodeValue and(Serializable left, Serializable right) { + return new ColumnNodeValue(left, AND, right); + } + + public static ColumnNodeValue orr(Serializable left, Serializable right) { + return new ColumnNodeValue(left, ORR, right); + } + + public ColumnNodeValue inc(Serializable right) { + return any(INC, right); + } + + public ColumnNodeValue dec(Serializable right) { + return any(DEC, right); + } + + public ColumnNodeValue mul(Serializable right) { + return any(MUL, right); + } + + public ColumnNodeValue div(Serializable right) { + return any(DIV, right); + } + + public ColumnNodeValue mod(Serializable right) { + return any(MOD, right); + } + + public ColumnNodeValue and(Serializable right) { + return any(AND, right); + } + + public ColumnNodeValue orr(Serializable right) { + return any(ORR, right); + } + + protected ColumnNodeValue any(ColumnExpress express, Serializable right) { + ColumnNodeValue one = new ColumnNodeValue(this.left, this.express, this.right); + this.left = one; + this.express = express; + this.right = right; + return this; + } + + public Serializable getLeft() { + return left; + } + + public void setLeft(Serializable left) { + this.left = left; + } + + public ColumnExpress getExpress() { + return express; + } + + public void setExpress(ColumnExpress express) { + this.express = express; + } + + public Serializable getRight() { + return right; + } + + public void setRight(Serializable right) { + this.right = right; + } + + @Override + public String toString() { + return "{\"column\":" + ((left instanceof CharSequence) ? ("\"" + left + "\"") : left) + ", \"express\":" + express + ", \"value\":" + ((right instanceof CharSequence) ? ("\"" + right + "\"") : right) + "}"; + } +} diff --git a/src/main/java/org/redkale/source/ColumnValue.java b/src/main/java/org/redkale/source/ColumnValue.java index e71b05548..8d2eabfb6 100644 --- a/src/main/java/org/redkale/source/ColumnValue.java +++ b/src/main/java/org/redkale/source/ColumnValue.java @@ -1,204 +1,204 @@ -/* - * 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.source; - -import java.io.Serializable; -import static org.redkale.source.ColumnExpress.*; - -/** - * ColumnValue涓昏鐢ㄤ簬澶氫釜瀛楁鏇存柊鐨勮〃杈惧紡銆 - * value鍊间竴鑸负: ColumnNodeValue銆丆olumnFuncNode銆丯umber銆丼tring绛
- * 鐢ㄤ簬 DataSource.updateColumn 鏂规硶
- * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public class ColumnValue { - - private String column; - - private ColumnExpress express; - - private Serializable value; - - public ColumnValue() { - } - - public ColumnValue(String column, Serializable value) { - this(column, ColumnExpress.MOV, value); - } - - public ColumnValue(String column, ColumnExpress express, Serializable value) { - this.column = column; - this.express = express == null ? ColumnExpress.MOV : express; - this.value = value; - } - - /** - * 鍚 mov 鎿嶄綔 - * - * @param column 瀛楁鍚 - * @param value 瀛楁鍊 - * - * @return ColumnValue - */ - public static ColumnValue create(String column, Serializable value) { - return new ColumnValue(column, value); - } - - /** - * 杩斿洖 {column} = {value} 鎿嶄綔 - * - * @param column 瀛楁鍚 - * @param value 瀛楁鍊 - * - * @return ColumnValue - */ - public static ColumnValue mov(String column, Serializable value) { - return new ColumnValue(column, MOV, value); - } - - /** - * 杩斿洖 {column} = {column} + {value} 鎿嶄綔 - * - * @param column 瀛楁鍚 - * @param value 瀛楁鍊 - * - * @return ColumnValue - */ - public static ColumnValue inc(String column, Serializable value) { - return new ColumnValue(column, INC, value); - } - - /** - * 杩斿洖 {column} = {column} + 1 鎿嶄綔 - * - * @param column 瀛楁鍚 - * - * @return ColumnValue - * - * @since 2.4.0 - */ - public static ColumnValue inc(String column) { - return new ColumnValue(column, INC, 1); - } - - /** - * 杩斿洖 {column} = {column} - {value} 鎿嶄綔 - * - * @param column 瀛楁鍚 - * @param value 瀛楁鍊 - * - * @return ColumnValue - */ - public static ColumnValue dec(String column, Serializable value) { - return new ColumnValue(column, DEC, value); - } - - /** - * 杩斿洖 {column} = {column} - 1 鎿嶄綔 - * - * @param column 瀛楁鍚 - * - * @return ColumnValue - * - * @since 2.4.0 - */ - public static ColumnValue dec(String column) { - return new ColumnValue(column, DEC, 1); - } - - /** - * 杩斿洖 {column} = {column} * {value} 鎿嶄綔 - * - * @param column 瀛楁鍚 - * @param value 瀛楁鍊 - * - * @return ColumnValue - */ - public static ColumnValue mul(String column, Serializable value) { - return new ColumnValue(column, MUL, value); - } - - /** - * 杩斿洖 {column} = {column} / {value} 鎿嶄綔 - * - * @param column 瀛楁鍚 - * @param value 瀛楁鍊 - * - * @return ColumnValue - */ - public static ColumnValue div(String column, Serializable value) { - return new ColumnValue(column, DIV, value); - } - - /** - * 杩斿洖 {column} = {column} % {value} 鎿嶄綔 - * - * @param column 瀛楁鍚 - * @param value 瀛楁鍊 - * - * @return ColumnValue - */ - //涓嶅父鐢紝闃叉寮鍙戣呭鏄撳湪mov鏃惰杈撳叆mod -// public static ColumnValue mod(String column, Serializable value) { -// return new ColumnValue(column, MOD, value); -// } - /** - * 杩斿洖 {column} = {column} & {value} 鎿嶄綔 - * - * @param column 瀛楁鍚 - * @param value 瀛楁鍊 - * - * @return ColumnValue - */ - public static ColumnValue and(String column, Serializable value) { - return new ColumnValue(column, AND, value); - } - - /** - * 杩斿洖 {column} = {column} | {value} 鎿嶄綔 - * - * @param column 瀛楁鍚 - * @param value 瀛楁鍊 - * - * @return ColumnValue - */ - public static ColumnValue orr(String column, Serializable value) { - return new ColumnValue(column, ORR, value); - } - - public String getColumn() { - return column; - } - - public void setColumn(String column) { - this.column = column; - } - - public ColumnExpress getExpress() { - return express; - } - - public void setExpress(ColumnExpress express) { - this.express = express; - } - - public Serializable getValue() { - return value; - } - - public void setValue(Serializable value) { - this.value = value; - } - - @Override - public String toString() { - return "{\"column\":\"" + column + "\", \"express\":" + express + ", \"value\":" + ((value instanceof CharSequence) ? ("\"" + value + "\"") : value) + "}"; - } -} +/* + * 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.source; + +import java.io.Serializable; +import static org.redkale.source.ColumnExpress.*; + +/** + * ColumnValue涓昏鐢ㄤ簬澶氫釜瀛楁鏇存柊鐨勮〃杈惧紡銆 + * value鍊间竴鑸负: ColumnNodeValue銆丆olumnFuncNode銆丯umber銆丼tring绛
+ * 鐢ㄤ簬 DataSource.updateColumn 鏂规硶
+ * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public class ColumnValue { + + private String column; + + private ColumnExpress express; + + private Serializable value; + + public ColumnValue() { + } + + public ColumnValue(String column, Serializable value) { + this(column, ColumnExpress.MOV, value); + } + + public ColumnValue(String column, ColumnExpress express, Serializable value) { + this.column = column; + this.express = express == null ? ColumnExpress.MOV : express; + this.value = value; + } + + /** + * 鍚 mov 鎿嶄綔 + * + * @param column 瀛楁鍚 + * @param value 瀛楁鍊 + * + * @return ColumnValue + */ + public static ColumnValue create(String column, Serializable value) { + return new ColumnValue(column, value); + } + + /** + * 杩斿洖 {column} = {value} 鎿嶄綔 + * + * @param column 瀛楁鍚 + * @param value 瀛楁鍊 + * + * @return ColumnValue + */ + public static ColumnValue mov(String column, Serializable value) { + return new ColumnValue(column, MOV, value); + } + + /** + * 杩斿洖 {column} = {column} + {value} 鎿嶄綔 + * + * @param column 瀛楁鍚 + * @param value 瀛楁鍊 + * + * @return ColumnValue + */ + public static ColumnValue inc(String column, Serializable value) { + return new ColumnValue(column, INC, value); + } + + /** + * 杩斿洖 {column} = {column} + 1 鎿嶄綔 + * + * @param column 瀛楁鍚 + * + * @return ColumnValue + * + * @since 2.4.0 + */ + public static ColumnValue inc(String column) { + return new ColumnValue(column, INC, 1); + } + + /** + * 杩斿洖 {column} = {column} - {value} 鎿嶄綔 + * + * @param column 瀛楁鍚 + * @param value 瀛楁鍊 + * + * @return ColumnValue + */ + public static ColumnValue dec(String column, Serializable value) { + return new ColumnValue(column, DEC, value); + } + + /** + * 杩斿洖 {column} = {column} - 1 鎿嶄綔 + * + * @param column 瀛楁鍚 + * + * @return ColumnValue + * + * @since 2.4.0 + */ + public static ColumnValue dec(String column) { + return new ColumnValue(column, DEC, 1); + } + + /** + * 杩斿洖 {column} = {column} * {value} 鎿嶄綔 + * + * @param column 瀛楁鍚 + * @param value 瀛楁鍊 + * + * @return ColumnValue + */ + public static ColumnValue mul(String column, Serializable value) { + return new ColumnValue(column, MUL, value); + } + + /** + * 杩斿洖 {column} = {column} / {value} 鎿嶄綔 + * + * @param column 瀛楁鍚 + * @param value 瀛楁鍊 + * + * @return ColumnValue + */ + public static ColumnValue div(String column, Serializable value) { + return new ColumnValue(column, DIV, value); + } + + /** + * 杩斿洖 {column} = {column} % {value} 鎿嶄綔 + * + * @param column 瀛楁鍚 + * @param value 瀛楁鍊 + * + * @return ColumnValue + */ + //涓嶅父鐢紝闃叉寮鍙戣呭鏄撳湪mov鏃惰杈撳叆mod +// public static ColumnValue mod(String column, Serializable value) { +// return new ColumnValue(column, MOD, value); +// } + /** + * 杩斿洖 {column} = {column} & {value} 鎿嶄綔 + * + * @param column 瀛楁鍚 + * @param value 瀛楁鍊 + * + * @return ColumnValue + */ + public static ColumnValue and(String column, Serializable value) { + return new ColumnValue(column, AND, value); + } + + /** + * 杩斿洖 {column} = {column} | {value} 鎿嶄綔 + * + * @param column 瀛楁鍚 + * @param value 瀛楁鍊 + * + * @return ColumnValue + */ + public static ColumnValue orr(String column, Serializable value) { + return new ColumnValue(column, ORR, value); + } + + public String getColumn() { + return column; + } + + public void setColumn(String column) { + this.column = column; + } + + public ColumnExpress getExpress() { + return express; + } + + public void setExpress(ColumnExpress express) { + this.express = express; + } + + public Serializable getValue() { + return value; + } + + public void setValue(Serializable value) { + this.value = value; + } + + @Override + public String toString() { + return "{\"column\":\"" + column + "\", \"express\":" + express + ", \"value\":" + ((value instanceof CharSequence) ? ("\"" + value + "\"") : value) + "}"; + } +} diff --git a/src/main/java/org/redkale/source/CryptColumn.java b/src/main/java/org/redkale/source/CryptColumn.java index aa5add93f..35a5c39c9 100644 --- a/src/main/java/org/redkale/source/CryptColumn.java +++ b/src/main/java/org/redkale/source/CryptColumn.java @@ -1,30 +1,30 @@ -/* - * 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.source; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.RetentionPolicy.RUNTIME; -import java.lang.annotation.*; - -/** - * 鍔犲瘑瀛楁鏍囪
- * 娉ㄦ剰: 鍔犲瘑瀛楁涓嶈兘鐢ㄤ簬 LIKE 绛夎繃婊ゆ煡璇
- * 濡傛灉鏈夊鍔犲瘑瀛楁杩涜杩囨护鏌ヨ鐨勯渶姹傦紝灏辫淇濊瘉鍔犲瘑绠楁硶涔熻兘鍏煎LIKE锛屽锛"abc"鐨勫姞瀵嗗瓧绗︿覆涔熸槸"abcde"鐨勫姞瀵嗗瓧绗︿覆鐨勪竴閮ㄥ垎 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @since 2.0.0 - */ -@Inherited -@Documented -@Target({FIELD}) -@Retention(RUNTIME) -public @interface CryptColumn { - - Class handler(); -} +/* + * 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.source; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import java.lang.annotation.*; + +/** + * 鍔犲瘑瀛楁鏍囪
+ * 娉ㄦ剰: 鍔犲瘑瀛楁涓嶈兘鐢ㄤ簬 LIKE 绛夎繃婊ゆ煡璇
+ * 濡傛灉鏈夊鍔犲瘑瀛楁杩涜杩囨护鏌ヨ鐨勯渶姹傦紝灏辫淇濊瘉鍔犲瘑绠楁硶涔熻兘鍏煎LIKE锛屽锛"abc"鐨勫姞瀵嗗瓧绗︿覆涔熸槸"abcde"鐨勫姞瀵嗗瓧绗︿覆鐨勪竴閮ㄥ垎 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @since 2.0.0 + */ +@Inherited +@Documented +@Target({FIELD}) +@Retention(RUNTIME) +public @interface CryptColumn { + + Class handler(); +} diff --git a/src/main/java/org/redkale/source/CryptHandler.java b/src/main/java/org/redkale/source/CryptHandler.java index 0fece30af..cf08dc0fd 100644 --- a/src/main/java/org/redkale/source/CryptHandler.java +++ b/src/main/java/org/redkale/source/CryptHandler.java @@ -1,38 +1,38 @@ -/* - * 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.source; - -/** - * 瀛楁鍔犲瘑瑙e瘑鎺ュ彛 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @since 2.0.0 - * @param 鍔犲瘑鐨勫瓧娈电被鍨 - * @param 鍔犲瘑鍚庣殑鏁版嵁绫诲瀷 - */ -public interface CryptHandler { - - /** - * 鍔犲瘑 - * - * @param value 鍔犲瘑鍓嶇殑瀛楁鍊 - * - * @return 鍔犲瘑鍚庣殑瀛楁鍊 - */ - public D encrypt(S value); - - /** - * 瑙e瘑 - * - * @param value 鍔犲瘑鐨勫瓧娈靛 - * - * @return 瑙e瘑鍚庣殑瀛楁鍊 - */ - public S decrypt(D value); -} +/* + * 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.source; + +/** + * 瀛楁鍔犲瘑瑙e瘑鎺ュ彛 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @since 2.0.0 + * @param 鍔犲瘑鐨勫瓧娈电被鍨 + * @param 鍔犲瘑鍚庣殑鏁版嵁绫诲瀷 + */ +public interface CryptHandler { + + /** + * 鍔犲瘑 + * + * @param value 鍔犲瘑鍓嶇殑瀛楁鍊 + * + * @return 鍔犲瘑鍚庣殑瀛楁鍊 + */ + public D encrypt(S value); + + /** + * 瑙e瘑 + * + * @param value 鍔犲瘑鐨勫瓧娈靛 + * + * @return 瑙e瘑鍚庣殑瀛楁鍊 + */ + public S decrypt(D value); +} diff --git a/src/main/java/org/redkale/source/DataJdbcSource.java b/src/main/java/org/redkale/source/DataJdbcSource.java index 5ac537bfd..be30fede3 100644 --- a/src/main/java/org/redkale/source/DataJdbcSource.java +++ b/src/main/java/org/redkale/source/DataJdbcSource.java @@ -1,1096 +1,1096 @@ -/* - * 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.source; - -import java.io.*; -import java.net.URL; -import java.sql.*; -import java.util.*; -import java.util.concurrent.*; -import java.util.concurrent.atomic.*; -import java.util.function.*; -import java.util.logging.*; -import org.redkale.service.Local; -import static org.redkale.source.DataSources.*; -import org.redkale.util.*; - -/** - * DataSource鐨凧DBC瀹炵幇绫 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@Local -@AutoLoad(false) -@SuppressWarnings("unchecked") -@ResourceType(DataSource.class) -public class DataJdbcSource extends DataSqlSource { - - protected ConnectionPool readPool; - - protected ConnectionPool writePool; - - public DataJdbcSource(String unitName, URL persistFile, String dbtype, Properties readprop, Properties writeprop) { - super(unitName, persistFile, dbtype, readprop, writeprop); - } - - @Override - public void init(AnyValue conf) { - super.init(conf); - this.readPool = new ConnectionPool(readConfProps); - if (readConfProps == writeConfProps) { - this.writePool = readPool; - } else { - this.writePool = new ConnectionPool(writeConfProps); - } - } - - @Override - public void destroy(AnyValue config) { - if (readPool != null) readPool.close(); - if (writePool != null) writePool.close(); - } - - @Local - @Override - public void close() throws Exception { - super.close(); - if (readPool != null) readPool.close(); - if (writePool != null) writePool.close(); - } - - public static boolean acceptsConf(Properties property) { - try { - final Class driverClass = DriverManager.getDriver(property.getProperty(JDBC_URL)).getClass(); - RedkaleClassLoader.putReflectionDeclaredConstructors(driverClass, driverClass.getName()); - RedkaleClassLoader.putServiceLoader(java.sql.Driver.class); - } catch (Exception e) { - return false; - } - return true; - } - - @Local - protected ConnectionPool readPool() { - return readPool; - } - - @Local - protected ConnectionPool writePool() { - return writePool; - } - - @Override - protected final String prepareParamSign(int index) { - return "?"; - } - - @Override - protected final boolean isAsync() { - return false; - } - - @Override - protected CompletableFuture insertDB(EntityInfo info, T... entitys) { - Connection conn = null; - try { - int c = 0; - conn = writePool.pollConnection(); - final String sql = info.getInsertQuestionPrepareSQL(entitys[0]); - final Class primaryType = info.getPrimary().type(); - final Attribute primary = info.getPrimary(); - Attribute[] attrs = info.insertAttributes; - conn.setReadOnly(false); - conn.setAutoCommit(true); - PreparedStatement prestmt = createInsertPreparedStatement(conn, sql, info, entitys); - try { - int[] cs = prestmt.executeBatch(); - int c1 = 0; - for (int cc : cs) { - c1 += cc; - } - c = c1; - } catch (SQLException se) { - if (!isTableNotExist(info, se.getSQLState())) throw se; - if (info.getTableStrategy() == null) { - String tablesql = createTableSql(info); - if (tablesql == null) throw se; - Statement st = conn.createStatement(); - st.execute(tablesql); - st.close(); - } else { - synchronized (info.disTableLock()) { - final String catalog = conn.getCatalog(); - final String newTable = info.getTable(entitys[0]); - final String tablekey = newTable.indexOf('.') > 0 ? newTable : (catalog + '.' + newTable); - if (!info.containsDisTable(tablekey)) { - try { - //鎵ц涓閬嶅鍒惰〃鎿嶄綔 - Statement st = conn.createStatement(); - st.execute(getTableCopySQL(info, newTable)); - st.close(); - info.addDisTable(tablekey); - } catch (SQLException sqle) { //澶氳繘绋嬪苟鍙戞椂鍙兘浼氬嚭鐜伴噸澶嶅缓琛 - if (isTableNotExist(info, sqle.getSQLState())) { - if (newTable.indexOf('.') < 0) { - String tablesql = createTableSql(info); - if (tablesql != null) { - Statement st = conn.createStatement(); - st.execute(tablesql); - st.close(); - //鍐嶆墽琛屼竴閬嶅鍒惰〃鎿嶄綔 - st = conn.createStatement(); - st.execute(getTableCopySQL(info, newTable)); - st.close(); - info.addDisTable(tablekey); - } - } else { //闇瑕佸厛寤哄簱 - Statement st; - try { - st = conn.createStatement(); - st.execute(("postgresql".equals(dbtype()) ? "CREATE SCHEMA IF NOT EXISTS " : "CREATE DATABASE IF NOT EXISTS ") + newTable.substring(0, newTable.indexOf('.'))); - st.close(); - } catch (SQLException sqle1) { - logger.log(Level.SEVERE, "create database(" + newTable.substring(0, newTable.indexOf('.')) + ") error", sqle1); - } - try { - //鍐嶆墽琛屼竴閬嶅鍒惰〃鎿嶄綔 - st = conn.createStatement(); - st.execute(getTableCopySQL(info, newTable)); - st.close(); - info.addDisTable(tablekey); - } catch (SQLException sqle2) { - if (isTableNotExist(info, sqle2.getSQLState())) { - String tablesql = createTableSql(info); - if (tablesql != null) { - st = conn.createStatement(); - st.execute(tablesql); - st.close(); - //鍐嶆墽琛屼竴閬嶅鍒惰〃鎿嶄綔 - st = conn.createStatement(); - st.execute(getTableCopySQL(info, newTable)); - st.close(); - info.addDisTable(tablekey); - } - } else { - logger.log(Level.SEVERE, "create table2(" + getTableCopySQL(info, newTable) + ") error", sqle2); - } - } - } - } - } - } - } - } - prestmt.close(); - prestmt = createInsertPreparedStatement(conn, sql, info, entitys); - int[] cs = prestmt.executeBatch(); - int c1 = 0; - for (int cc : cs) { - c1 += cc; - } - c = c1; - } - prestmt.close(); - //------------------------------------------------------------ - if (info.isLoggable(logger, Level.FINEST)) { //鎵撳嵃璋冭瘯淇℃伅 - char[] sqlchars = sql.toCharArray(); - for (final T value : entitys) { - //----------------------------- - StringBuilder sb = new StringBuilder(128); - int i = 0; - for (char ch : sqlchars) { - if (ch == '?') { - Object obj = info.getSQLValue(attrs[i++], value); - if (obj != null && obj.getClass().isArray()) { - sb.append("'[length=").append(java.lang.reflect.Array.getLength(obj)).append("]'"); - } else { - sb.append(info.formatSQLValue(obj, sqlFormatter)); - } - } else { - sb.append(ch); - } - } - String debugsql = sb.toString(); - if (info.isLoggable(logger, Level.FINEST, debugsql)) logger.finest(info.getType().getSimpleName() + " insert sql=" + debugsql.replaceAll("(\r|\n)", "\\n")); - } - } //鎵撳嵃缁撴潫 - return CompletableFuture.completedFuture(c); - } catch (SQLException e) { - return CompletableFuture.failedFuture(e); - } finally { - if (conn != null) writePool.offerConnection(conn); - } - } - - protected PreparedStatement createInsertPreparedStatement(final Connection conn, final String sql, - final EntityInfo info, T... entitys) throws SQLException { - Attribute[] attrs = info.insertAttributes; - final PreparedStatement prestmt = conn.prepareStatement(sql); - - for (final T value : entitys) { - batchStatementParameters(conn, prestmt, info, attrs, value); - prestmt.addBatch(); - } - return prestmt; - } - - protected int batchStatementParameters(Connection conn, PreparedStatement prestmt, EntityInfo info, Attribute[] attrs, T entity) throws SQLException { - int i = 0; - for (Attribute attr : attrs) { - Object val = info.getSQLValue(attr, entity); - if (val instanceof byte[]) { - Blob blob = conn.createBlob(); - blob.setBytes(1, (byte[]) val); - prestmt.setObject(++i, blob); - } else if (val instanceof Boolean) { - prestmt.setObject(++i, ((Boolean) val) ? (byte) 1 : (byte) 0); - } else if (val instanceof AtomicInteger) { - prestmt.setObject(++i, ((AtomicInteger) val).get()); - } else if (val instanceof AtomicLong) { - prestmt.setObject(++i, ((AtomicLong) val).get()); - } else if (val != null && !(val instanceof Number) && !(val instanceof CharSequence) && !(val instanceof java.util.Date) - && !val.getClass().getName().startsWith("java.sql.") && !val.getClass().getName().startsWith("java.time.")) { - prestmt.setObject(++i, info.jsonConvert.convertTo(attr.genericType(), val)); - } else if (val == null && info.isNotNullJson(attr)) { - prestmt.setObject(++i, ""); - } else { - prestmt.setObject(++i, val); - } - } - return i; - } - - @Override - protected CompletableFuture deleteDB(EntityInfo info, Flipper flipper, String sql) { - Connection conn = null; - try { - conn = writePool.pollConnection(); - conn.setReadOnly(false); - conn.setAutoCommit(true); - sql += ((flipper == null || flipper.getLimit() < 1) ? "" : (" LIMIT " + flipper.getLimit())); - if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " delete sql=" + sql); - final Statement stmt = conn.createStatement(); - int c = stmt.executeUpdate(sql); - stmt.close(); - return CompletableFuture.completedFuture(c); - } catch (SQLException e) { - if (isTableNotExist(info, e.getSQLState())) { - if (info.getTableStrategy() == null) { - String tablesql = createTableSql(info); - if (tablesql != null) { - try { - Statement st = conn.createStatement(); - st.execute(tablesql); - st.close(); - return CompletableFuture.completedFuture(0); - } catch (SQLException e2) { - return CompletableFuture.failedFuture(e2); - } - } - } - } - return CompletableFuture.failedFuture(e); - } finally { - if (conn != null) writePool.offerConnection(conn); - } - } - - @Override - protected CompletableFuture clearTableDB(EntityInfo info, final String table, String sql) { - Connection conn = null; - try { - conn = writePool.pollConnection(); - conn.setReadOnly(false); - conn.setAutoCommit(true); - final Statement stmt = conn.createStatement(); - int c = stmt.executeUpdate(sql); - stmt.close(); - return CompletableFuture.completedFuture(c); - } catch (SQLException e) { - if (isTableNotExist(info, e.getSQLState())) return CompletableFuture.completedFuture(-1); - return CompletableFuture.failedFuture(e); - } finally { - if (conn != null) writePool.offerConnection(conn); - } - } - - @Override - protected CompletableFuture dropTableDB(EntityInfo info, final String table, String sql) { - Connection conn = null; - try { - conn = writePool.pollConnection(); - conn.setReadOnly(false); - conn.setAutoCommit(true); - final Statement stmt = conn.createStatement(); - int c = stmt.executeUpdate(sql); - stmt.close(); - if (info.getTableStrategy() != null) { - String tablekey = table.indexOf('.') > 0 ? table : (conn.getCatalog() + '.' + table); - info.removeDisTable(tablekey); - } - return CompletableFuture.completedFuture(c); - } catch (SQLException e) { - if (isTableNotExist(info, e.getSQLState())) return CompletableFuture.completedFuture(-1); - return CompletableFuture.failedFuture(e); - } finally { - if (conn != null) writePool.offerConnection(conn); - } - } - - @Override - protected CompletableFuture updateEntityDB(EntityInfo info, T... entitys) { - Connection conn = null; - try { - conn = writePool.pollConnection(); - conn.setReadOnly(false); - conn.setAutoCommit(true); - final String updateSQL = info.getUpdateQuestionPrepareSQL(entitys[0]); - final PreparedStatement prestmt = conn.prepareStatement(updateSQL); - Attribute[] attrs = info.updateAttributes; - final boolean debugfinest = info.isLoggable(logger, Level.FINEST); - char[] sqlchars = debugfinest ? updateSQL.toCharArray() : null; - final Attribute primary = info.getPrimary(); - for (final T value : entitys) { - int k = batchStatementParameters(conn, prestmt, info, attrs, value); - prestmt.setObject(++k, primary.get(value)); - prestmt.addBatch();//------------------------------------------------------------ - if (debugfinest) { //鎵撳嵃璋冭瘯淇℃伅 - //----------------------------- - int i = 0; - StringBuilder sb = new StringBuilder(128); - for (char ch : sqlchars) { - if (ch == '?') { - Object obj = i == attrs.length ? info.getSQLValue(primary, value) : info.getSQLValue(attrs[i++], value); - if (obj != null && obj.getClass().isArray()) { - sb.append("'[length=").append(java.lang.reflect.Array.getLength(obj)).append("]'"); - } else { - sb.append(info.formatSQLValue(obj, sqlFormatter)); - } - } else { - sb.append(ch); - } - } - String debugsql = sb.toString(); - if (info.isLoggable(logger, Level.FINEST, debugsql)) logger.finest(info.getType().getSimpleName() + " updates sql=" + debugsql.replaceAll("(\r|\n)", "\\n")); - } //鎵撳嵃缁撴潫 - } - int[] pc = prestmt.executeBatch(); - int c = 0; - for (int p : pc) { - if (p >= 0) c += p; - } - prestmt.close(); - return CompletableFuture.completedFuture(c); - } catch (SQLException e) { - if (isTableNotExist(info, e.getSQLState())) { - if (info.getTableStrategy() == null) { - String tablesql = createTableSql(info); - if (tablesql != null) { - try { - Statement st = conn.createStatement(); - st.execute(tablesql); - st.close(); - } catch (SQLException e2) { - } - } - } - return CompletableFuture.completedFuture(0); - } - return CompletableFuture.failedFuture(e); - } finally { - if (conn != null) writePool.offerConnection(conn); - } - } - - @Override - protected CompletableFuture updateColumnDB(EntityInfo info, Flipper flipper, String sql, boolean prepared, Object... params) { - Connection conn = null; - try { - conn = writePool.pollConnection(); - conn.setReadOnly(false); - conn.setAutoCommit(true); - if (prepared) { - final PreparedStatement prestmt = conn.prepareStatement(sql); - int index = 0; - for (Object param : params) { - Blob blob = conn.createBlob(); - blob.setBytes(1, (byte[]) param); - prestmt.setBlob(++index, blob); - } - int c = prestmt.executeUpdate(); - prestmt.close(); - return CompletableFuture.completedFuture(c); - } else { - if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " update sql=" + sql); - final Statement stmt = conn.createStatement(); - int c = stmt.executeUpdate(sql); - stmt.close(); - return CompletableFuture.completedFuture(c); - } - } catch (SQLException e) { - if (isTableNotExist(info, e.getSQLState())) { - if (info.getTableStrategy() == null) { - String tablesql = createTableSql(info); - if (tablesql != null) { - try { - Statement st = conn.createStatement(); - st.execute(tablesql); - st.close(); - } catch (SQLException e2) { - } - } - } - return CompletableFuture.completedFuture(0); - } - return CompletableFuture.failedFuture(e); - } finally { - if (conn != null) writePool.offerConnection(conn); - } - } - - @Override - protected CompletableFuture> getNumberMapDB(EntityInfo info, String sql, FilterFuncColumn... columns) { - Connection conn = null; - final Map map = new HashMap<>(); - try { - conn = readPool.pollConnection(); - //conn.setReadOnly(true); - final Statement stmt = conn.createStatement(); - ResultSet set = stmt.executeQuery(sql); - if (set.next()) { - int index = 0; - for (FilterFuncColumn ffc : columns) { - for (String col : ffc.cols()) { - Object o = set.getObject(++index); - Number rs = ffc.getDefvalue(); - if (o != null) rs = (Number) o; - map.put(ffc.col(col), rs); - } - } - } - set.close(); - stmt.close(); - return CompletableFuture.completedFuture(map); - } catch (SQLException e) { - if (isTableNotExist(info, e.getSQLState())) { - if (info.getTableStrategy() == null) { - String tablesql = createTableSql(info); - if (tablesql != null) { - try { - Statement st = conn.createStatement(); - st.execute(tablesql); - st.close(); - } catch (SQLException e2) { - } - } - } - return CompletableFuture.completedFuture(map); - } - return CompletableFuture.failedFuture(e); - } finally { - if (conn != null) readPool.offerConnection(conn); - } - } - - @Override - protected CompletableFuture getNumberResultDB(EntityInfo info, String sql, Number defVal, String column) { - Connection conn = null; - try { - conn = readPool.pollConnection(); - //conn.setReadOnly(true); - final Statement stmt = conn.createStatement(); - Number rs = defVal; - ResultSet set = stmt.executeQuery(sql); - if (set.next()) { - Object o = set.getObject(1); - if (o != null) rs = (Number) o; - } - set.close(); - stmt.close(); - return CompletableFuture.completedFuture(rs); - } catch (SQLException e) { - if (isTableNotExist(info, e.getSQLState())) { - if (info.getTableStrategy() == null) { - String tablesql = createTableSql(info); - if (tablesql != null) { - try { - Statement st = conn.createStatement(); - st.execute(tablesql); - st.close(); - } catch (SQLException e2) { - } - } - } - return CompletableFuture.completedFuture(defVal); - } - return CompletableFuture.failedFuture(e); - } finally { - if (conn != null) readPool.offerConnection(conn); - } - } - - @Override - protected CompletableFuture> queryColumnMapDB(EntityInfo info, String sql, String keyColumn) { - Connection conn = null; - Map rs = new LinkedHashMap<>(); - try { - conn = readPool.pollConnection(); - //conn.setReadOnly(true); - final Statement stmt = conn.createStatement(); - ResultSet set = stmt.executeQuery(sql); - ResultSetMetaData rsd = set.getMetaData(); - boolean smallint = rsd == null ? false : rsd.getColumnType(1) == Types.SMALLINT; - while (set.next()) { - rs.put((K) (smallint ? set.getShort(1) : set.getObject(1)), (N) set.getObject(2)); - } - set.close(); - stmt.close(); - return CompletableFuture.completedFuture(rs); - } catch (SQLException e) { - if (isTableNotExist(info, e.getSQLState())) { - if (info.getTableStrategy() == null) { - String tablesql = createTableSql(info); - if (tablesql != null) { - try { - Statement st = conn.createStatement(); - st.execute(tablesql); - st.close(); - } catch (SQLException e2) { - } - } - } - return CompletableFuture.completedFuture(rs); - } - return CompletableFuture.failedFuture(e); - } finally { - if (conn != null) readPool.offerConnection(conn); - } - } - - @Override - protected CompletableFuture> queryColumnMapDB(EntityInfo info, String sql, final ColumnNode[] funcNodes, final String[] groupByColumns) { - Connection conn = null; - Map rs = new LinkedHashMap<>(); - try { - conn = readPool.pollConnection(); - //conn.setReadOnly(true); - final Statement stmt = conn.createStatement(); - ResultSet set = stmt.executeQuery(sql); - ResultSetMetaData rsd = set.getMetaData(); - boolean[] smallints = null; - while (set.next()) { - int index = 0; - Serializable[] keys = new Serializable[groupByColumns.length]; - if (smallints == null) { - smallints = new boolean[keys.length]; - for (int i = 0; i < keys.length; i++) { - smallints[i] = rsd == null ? false : rsd.getColumnType(i + 1) == Types.SMALLINT; - } - } - for (int i = 0; i < keys.length; i++) { - keys[i] = (Serializable) ((smallints[i] && index == 0) ? set.getShort(++index) : set.getObject(++index)); - } - Number[] vals = new Number[funcNodes.length]; - for (int i = 0; i < vals.length; i++) { - vals[i] = (Number) set.getObject(++index); - } - rs.put(keys, vals); - } - set.close(); - stmt.close(); - return CompletableFuture.completedFuture(rs); - } catch (SQLException e) { - if (isTableNotExist(info, e.getSQLState())) { - if (info.getTableStrategy() == null) { - String tablesql = createTableSql(info); - if (tablesql != null) { - try { - Statement st = conn.createStatement(); - st.execute(tablesql); - st.close(); - } catch (SQLException e2) { - } - } - } - return CompletableFuture.completedFuture(rs); - } - return CompletableFuture.failedFuture(e); - } finally { - if (conn != null) readPool.offerConnection(conn); - } - } - - @Override - protected CompletableFuture findDB(EntityInfo info, String sql, boolean onlypk, SelectColumn selects) { - Connection conn = null; - try { - conn = readPool.pollConnection(); - //conn.setReadOnly(true); - final PreparedStatement ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); - ps.setFetchSize(1); - final DataResultSet set = createDataResultSet(ps.executeQuery()); - T rs = set.next() ? selects == null ? info.getFullEntityValue(set) : info.getEntityValue(selects, set) : null; - set.close(); - ps.close(); - return CompletableFuture.completedFuture(rs); - } catch (SQLException e) { - if (isTableNotExist(info, e.getSQLState())) { - if (info.getTableStrategy() == null) { - String tablesql = createTableSql(info); - if (tablesql != null) { - try { - Statement st = conn.createStatement(); - st.execute(tablesql); - st.close(); - } catch (SQLException e2) { - } - } - } - return CompletableFuture.completedFuture(null); - } - return CompletableFuture.failedFuture(e); - } finally { - if (conn != null) readPool.offerConnection(conn); - } - } - - @Override - protected CompletableFuture findColumnDB(EntityInfo info, String sql, boolean onlypk, String column, Serializable defValue) { - Connection conn = null; - try { - conn = readPool.pollConnection(); - //conn.setReadOnly(true); - final Attribute attr = info.getAttribute(column); - final PreparedStatement ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); - ps.setFetchSize(1); - final DataResultSet set = createDataResultSet(ps.executeQuery()); - Serializable val = defValue; - if (set.next()) { - val = info.getFieldValue(attr, set, 1); - } - set.close(); - ps.close(); - return CompletableFuture.completedFuture(val == null ? defValue : val); - } catch (SQLException e) { - if (isTableNotExist(info, e.getSQLState())) { - if (info.getTableStrategy() == null) { - String tablesql = createTableSql(info); - if (tablesql != null) { - try { - Statement st = conn.createStatement(); - st.execute(tablesql); - st.close(); - } catch (SQLException e2) { - } - } - } - return CompletableFuture.completedFuture(null); - } - return CompletableFuture.failedFuture(e); - } finally { - if (conn != null) readPool.offerConnection(conn); - } - } - - @Override - protected CompletableFuture existsDB(EntityInfo info, String sql, boolean onlypk) { - Connection conn = null; - try { - conn = readPool.pollConnection(); - //conn.setReadOnly(true); - final PreparedStatement ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); - final ResultSet set = ps.executeQuery(); - boolean rs = set.next() ? (set.getInt(1) > 0) : false; - set.close(); - ps.close(); - if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " exists (" + rs + ") sql=" + sql); - return CompletableFuture.completedFuture(rs); - } catch (SQLException e) { - if (isTableNotExist(info, e.getSQLState())) { - if (info.getTableStrategy() == null) { - String tablesql = createTableSql(info); - if (tablesql != null) { - try { - Statement st = conn.createStatement(); - st.execute(tablesql); - st.close(); - } catch (SQLException e2) { - } - } - } - return CompletableFuture.completedFuture(false); - } - return CompletableFuture.failedFuture(e); - } finally { - if (conn != null) readPool.offerConnection(conn); - } - } - - @Override - protected CompletableFuture> querySheetDB(EntityInfo info, final boolean readcache, boolean needtotal, final boolean distinct, SelectColumn selects, Flipper flipper, FilterNode node) { - Connection conn = null; - try { - conn = readPool.pollConnection(); - //conn.setReadOnly(true); - final SelectColumn sels = selects; - final List list = new ArrayList(); - final Map joinTabalis = node == null ? null : node.getJoinTabalis(); - final CharSequence join = node == null ? null : node.createSQLJoin(this, false, joinTabalis, new HashSet<>(), info); - final CharSequence where = node == null ? null : node.createSQLExpress(this, info, joinTabalis); - if ("mysql".equals(dbtype()) || "postgresql".equals(dbtype())) { //sql鍙互甯imit銆乷ffset - final String listsql = "SELECT " + (distinct ? "DISTINCT " : "") + info.getFullQueryColumns("a", selects) + " FROM " + info.getTable(node) + " a" + (join == null ? "" : join) - + ((where == null || where.length() == 0) ? "" : (" WHERE " + where)) + createSQLOrderby(info, flipper) - + (flipper == null || flipper.getLimit() < 1 ? "" : (" LIMIT " + flipper.getLimit() + " OFFSET " + flipper.getOffset())); - if (readcache && info.isLoggable(logger, Level.FINEST, listsql)) { - logger.finest(info.getType().getSimpleName() + " query sql=" + listsql); - } - PreparedStatement ps = conn.prepareStatement(listsql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); - ResultSet set = ps.executeQuery(); - final DataResultSet rr = createDataResultSet(set); - while (set.next()) { - list.add(getEntityValue(info, sels, rr)); - } - set.close(); - ps.close(); - long total = list.size(); - if (needtotal) { - final String countsql = "SELECT " + (distinct ? "DISTINCT COUNT(" + info.getQueryColumns("a", selects) + ")" : "COUNT(*)") + " FROM " + info.getTable(node) + " a" + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where)); - if (readcache && info.isLoggable(logger, Level.FINEST, countsql)) { - logger.finest(info.getType().getSimpleName() + " query countsql=" + countsql); - } - ps = conn.prepareStatement(countsql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); - set = ps.executeQuery(); - if (set.next()) total = set.getLong(1); - set.close(); - ps.close(); - } - return CompletableFuture.completedFuture(new Sheet<>(total, list)); - } - final String listsql = "SELECT " + (distinct ? "DISTINCT " : "") + info.getFullQueryColumns("a", selects) + " FROM " + info.getTable(node) + " a" + (join == null ? "" : join) - + ((where == null || where.length() == 0) ? "" : (" WHERE " + where)) + info.createSQLOrderby(flipper); - if (readcache && info.isLoggable(logger, Level.FINEST, listsql)) { - logger.finest(info.getType().getSimpleName() + " query sql=" + listsql + (flipper == null || flipper.getLimit() < 1 ? "" : (" LIMIT " + flipper.getLimit() + " OFFSET " + flipper.getOffset()))); - } - //conn.setReadOnly(true); - final PreparedStatement ps = conn.prepareStatement(listsql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); - if (flipper != null && flipper.getLimit() > 0) ps.setFetchSize(flipper.getLimit()); - final ResultSet set = ps.executeQuery(); - if (flipper != null && flipper.getOffset() > 0) set.absolute(flipper.getOffset()); - final int limit = flipper == null || flipper.getLimit() < 1 ? Integer.MAX_VALUE : flipper.getLimit(); - int i = 0; - final DataResultSet rr = createDataResultSet(set); - if (sels == null) { - while (set.next()) { - i++; - list.add(info.getFullEntityValue(rr)); - if (limit <= i) break; - } - } else { - while (set.next()) { - i++; - list.add(info.getEntityValue(sels, rr)); - if (limit <= i) break; - } - } - long total = list.size(); - if (needtotal && flipper != null) { - set.last(); - total = set.getRow(); - } - set.close(); - ps.close(); - return CompletableFuture.completedFuture(new Sheet<>(total, list)); - } catch (SQLException e) { - if (isTableNotExist(info, e.getSQLState())) { - if (info.getTableStrategy() == null) { - String tablesql = createTableSql(info); - if (tablesql != null) { - try { - Statement st = conn.createStatement(); - st.execute(tablesql); - st.close(); - } catch (SQLException e2) { - } - } - } - return CompletableFuture.completedFuture(new Sheet<>(0, new ArrayList())); - } - return CompletableFuture.failedFuture(e); - } finally { - if (conn != null) readPool.offerConnection(conn); - } - } - - /** - * 鐩存帴鏈湴鎵цSQL璇彞杩涜澧炲垹鏀规搷浣滐紝杩滅▼妯″紡涓嶅彲鐢
- * 閫氬父鐢ㄤ簬澶嶆潅鐨勬洿鏂版搷浣
- * - * @param sql SQL璇彞 - * - * @return 缁撴灉鏁扮粍 - */ - @Local - @Override - public int directExecute(String sql) { - return directExecute(new String[]{sql})[0]; - } - - /** - * 鐩存帴鏈湴鎵цSQL璇彞杩涜澧炲垹鏀规搷浣滐紝杩滅▼妯″紡涓嶅彲鐢
- * 閫氬父鐢ㄤ簬澶嶆潅鐨勬洿鏂版搷浣
- * - * @param sqls SQL璇彞 - * - * @return 缁撴灉鏁扮粍 - */ - @Local - @Override - public int[] directExecute(String... sqls) { - if (sqls.length == 0) return new int[0]; - Connection conn = writePool.pollConnection(); - try { - conn.setReadOnly(false); - final Statement stmt = conn.createStatement(); - final int[] rs = new int[sqls.length]; - int i = -1; - for (String sql : sqls) { - rs[++i] = stmt.execute(sql) ? 1 : 0; - } - stmt.close(); - return rs; - } catch (SQLException e) { - throw new RuntimeException(e); - } finally { - if (conn != null) writePool.offerConnection(conn); - } - } - - /** - * 鐩存帴鏈湴鎵цSQL璇彞杩涜鏌ヨ锛岃繙绋嬫ā寮忎笉鍙敤
- * 閫氬父鐢ㄤ簬澶嶆潅鐨勫叧鑱旀煡璇
- * - * @param 娉涘瀷 - * @param sql SQL璇彞 - * @param handler 鍥炶皟鍑芥暟 - * - * @return 缁撴灉 - */ - @Local - @Override - public V directQuery(String sql, Function handler) { - final Connection conn = readPool.pollConnection(); - try { - if (logger.isLoggable(Level.FINEST)) logger.finest("direct query sql=" + sql); - //conn.setReadOnly(true); - final Statement statement = conn.createStatement(); - //final PreparedStatement statement = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); - final ResultSet set = statement.executeQuery(sql);// ps.executeQuery(); - V rs = handler.apply(createDataResultSet(set)); - set.close(); - statement.close(); - return rs; - } catch (Exception ex) { - throw new RuntimeException(ex); - } finally { - if (conn != null) readPool.offerConnection(conn); - } - } - - public static DataResultSet createDataResultSet(ResultSet set) { - - final ResultSet rr = set; - - return new DataResultSet() { - - @Override - public Serializable getObject(Attribute attr, int index, String column) { - Class t = attr.type(); - if (t == java.util.Date.class) { - Object val = index > 0 ? getObject(index) : getObject(column); - if (val == null) return null; - return new java.util.Date(((java.sql.Date) val).getTime()); - } else if (t == java.time.LocalDate.class) { - Object val = index > 0 ? getObject(index) : getObject(column); - if (val == null) return null; - return ((java.sql.Date) val).toLocalDate(); - } else if (t == java.time.LocalTime.class) { - Object val = index > 0 ? getObject(index) : getObject(column); - if (val == null) return null; - return ((java.sql.Time) val).toLocalTime(); - } else if (t == java.time.LocalDateTime.class) { - Object val = index > 0 ? getObject(index) : getObject(column); - if (val == null) return null; - return ((java.sql.Timestamp) val).toLocalDateTime(); - } else if (t.getName().startsWith("java.sql.")) { - return index > 0 ? (Serializable) getObject(index) : (Serializable) getObject(column); - } - return DataResultSet.getRowColumnValue(this, attr, index, column); - } - - @Override - public boolean next() { - try { - return rr.next(); - } catch (SQLException e) { - throw new RuntimeException(e); - } - } - - @Override - public boolean wasNull() { - try { - return rr.wasNull(); - } catch (SQLException e) { - throw new RuntimeException(e); - } - } - - @Override - public void close() { - try { - rr.close(); - } catch (SQLException e) { - throw new RuntimeException(e); - } - } - - @Override - public Object getObject(int index) { - try { - return rr.getObject(index); - } catch (SQLException e) { - throw new RuntimeException(e); - } - } - - @Override - public Object getObject(String column) { - try { - return rr.getObject(column); - } catch (SQLException e) { - throw new RuntimeException(e); - } - } - - }; - } - - protected class ConnectionPool implements AutoCloseable { - - protected final LongAdder closeCounter = new LongAdder(); //宸插叧闂繛鎺ユ暟 - - protected final LongAdder usingCounter = new LongAdder(); //浣跨敤涓繛鎺ユ暟 - - protected final LongAdder creatCounter = new LongAdder(); //宸插垱寤鸿繛鎺ユ暟 - - protected final LongAdder cycleCounter = new LongAdder(); //宸插鐢ㄨ繛鎺ユ暟 - - protected final LongAdder waitingCounter = new LongAdder(); //鍙敤涓繛鎺ユ暟 - - protected final java.sql.Driver driver; - - protected final Properties connectAttrs; - - protected final ArrayBlockingQueue queue; - - protected int connectTimeoutSeconds; - - protected int maxconns; - - protected String url; - - public ConnectionPool(Properties prop) { - this.connectTimeoutSeconds = Integer.decode(prop.getProperty(JDBC_CONNECTTIMEOUT_SECONDS, "6")); - this.maxconns = Math.max(1, Integer.decode(prop.getProperty(JDBC_CONNECTIONS_LIMIT, "" + Utility.cpus() * 4))); - this.queue = new ArrayBlockingQueue<>(maxconns); - this.url = prop.getProperty(JDBC_URL); - String username = prop.getProperty(JDBC_USER, ""); - String password = prop.getProperty(JDBC_PWD, ""); - this.connectAttrs = new Properties(); - if (username != null) this.connectAttrs.put("user", username); - if (password != null) this.connectAttrs.put("password", password); - try { - this.driver = DriverManager.getDriver(this.url); - } catch (SQLException e) { - throw new RuntimeException(e); - } - } - - public synchronized Connection pollConnection() { - Connection conn = queue.poll(); - if (conn == null) { - if (usingCounter.intValue() >= maxconns) { - try { - conn = queue.poll(connectTimeoutSeconds, TimeUnit.SECONDS); - } catch (InterruptedException t) { - logger.log(Level.WARNING, "take pooled connection error", t); - } - if (conn == null) throw new RuntimeException("create pooled connection timeout"); - } - } - if (conn != null) { - usingCounter.increment(); - waitingCounter.decrement(); - if (checkValid(conn)) { - cycleCounter.increment(); - return conn; - } else { - offerConnection(conn); - conn = null; - } - } - try { - conn = driver.connect(url, connectAttrs); - } catch (SQLException ex) { - throw new RuntimeException(ex); - } - usingCounter.increment(); - creatCounter.increment(); - return conn; - } - - public void offerConnection(final C connection) { - Connection conn = (Connection) connection; - if (conn == null) return; - try { - if (checkValid(conn) && queue.offer(conn)) { - usingCounter.decrement(); - waitingCounter.increment(); - } else { - usingCounter.decrement(); - closeCounter.increment(); - conn.close(); - } - } catch (Exception e) { - logger.log(Level.WARNING, "closeSQLConnection abort", e); - } - } - - protected boolean checkValid(Connection conn) { - try { - return !conn.isClosed() && conn.isValid(1); - } catch (SQLException ex) { - if (!"08S01".equals(ex.getSQLState())) {//MySQL鐗规э紝 闀挎椂闂磋繛鎺ユ病浣跨敤浼氭姏鍑篶om.mysql.jdbc.exceptions.jdbc4.CommunicationsException - logger.log(Level.FINER, "result.getConnection from pooled connection abort [" + ex.getSQLState() + "]", ex); - } - return false; - } - } - - @Override - public void close() { - queue.stream().forEach(x -> { - try { - x.close(); - } catch (Exception e) { - } - }); - } - } -} +/* + * 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.source; + +import java.io.*; +import java.net.URL; +import java.sql.*; +import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.*; +import java.util.function.*; +import java.util.logging.*; +import org.redkale.service.Local; +import static org.redkale.source.DataSources.*; +import org.redkale.util.*; + +/** + * DataSource鐨凧DBC瀹炵幇绫 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@Local +@AutoLoad(false) +@SuppressWarnings("unchecked") +@ResourceType(DataSource.class) +public class DataJdbcSource extends DataSqlSource { + + protected ConnectionPool readPool; + + protected ConnectionPool writePool; + + public DataJdbcSource(String unitName, URL persistFile, String dbtype, Properties readprop, Properties writeprop) { + super(unitName, persistFile, dbtype, readprop, writeprop); + } + + @Override + public void init(AnyValue conf) { + super.init(conf); + this.readPool = new ConnectionPool(readConfProps); + if (readConfProps == writeConfProps) { + this.writePool = readPool; + } else { + this.writePool = new ConnectionPool(writeConfProps); + } + } + + @Override + public void destroy(AnyValue config) { + if (readPool != null) readPool.close(); + if (writePool != null) writePool.close(); + } + + @Local + @Override + public void close() throws Exception { + super.close(); + if (readPool != null) readPool.close(); + if (writePool != null) writePool.close(); + } + + public static boolean acceptsConf(Properties property) { + try { + final Class driverClass = DriverManager.getDriver(property.getProperty(JDBC_URL)).getClass(); + RedkaleClassLoader.putReflectionDeclaredConstructors(driverClass, driverClass.getName()); + RedkaleClassLoader.putServiceLoader(java.sql.Driver.class); + } catch (Exception e) { + return false; + } + return true; + } + + @Local + protected ConnectionPool readPool() { + return readPool; + } + + @Local + protected ConnectionPool writePool() { + return writePool; + } + + @Override + protected final String prepareParamSign(int index) { + return "?"; + } + + @Override + protected final boolean isAsync() { + return false; + } + + @Override + protected CompletableFuture insertDB(EntityInfo info, T... entitys) { + Connection conn = null; + try { + int c = 0; + conn = writePool.pollConnection(); + final String sql = info.getInsertQuestionPrepareSQL(entitys[0]); + final Class primaryType = info.getPrimary().type(); + final Attribute primary = info.getPrimary(); + Attribute[] attrs = info.insertAttributes; + conn.setReadOnly(false); + conn.setAutoCommit(true); + PreparedStatement prestmt = createInsertPreparedStatement(conn, sql, info, entitys); + try { + int[] cs = prestmt.executeBatch(); + int c1 = 0; + for (int cc : cs) { + c1 += cc; + } + c = c1; + } catch (SQLException se) { + if (!isTableNotExist(info, se.getSQLState())) throw se; + if (info.getTableStrategy() == null) { + String tablesql = createTableSql(info); + if (tablesql == null) throw se; + Statement st = conn.createStatement(); + st.execute(tablesql); + st.close(); + } else { + synchronized (info.disTableLock()) { + final String catalog = conn.getCatalog(); + final String newTable = info.getTable(entitys[0]); + final String tablekey = newTable.indexOf('.') > 0 ? newTable : (catalog + '.' + newTable); + if (!info.containsDisTable(tablekey)) { + try { + //鎵ц涓閬嶅鍒惰〃鎿嶄綔 + Statement st = conn.createStatement(); + st.execute(getTableCopySQL(info, newTable)); + st.close(); + info.addDisTable(tablekey); + } catch (SQLException sqle) { //澶氳繘绋嬪苟鍙戞椂鍙兘浼氬嚭鐜伴噸澶嶅缓琛 + if (isTableNotExist(info, sqle.getSQLState())) { + if (newTable.indexOf('.') < 0) { + String tablesql = createTableSql(info); + if (tablesql != null) { + Statement st = conn.createStatement(); + st.execute(tablesql); + st.close(); + //鍐嶆墽琛屼竴閬嶅鍒惰〃鎿嶄綔 + st = conn.createStatement(); + st.execute(getTableCopySQL(info, newTable)); + st.close(); + info.addDisTable(tablekey); + } + } else { //闇瑕佸厛寤哄簱 + Statement st; + try { + st = conn.createStatement(); + st.execute(("postgresql".equals(dbtype()) ? "CREATE SCHEMA IF NOT EXISTS " : "CREATE DATABASE IF NOT EXISTS ") + newTable.substring(0, newTable.indexOf('.'))); + st.close(); + } catch (SQLException sqle1) { + logger.log(Level.SEVERE, "create database(" + newTable.substring(0, newTable.indexOf('.')) + ") error", sqle1); + } + try { + //鍐嶆墽琛屼竴閬嶅鍒惰〃鎿嶄綔 + st = conn.createStatement(); + st.execute(getTableCopySQL(info, newTable)); + st.close(); + info.addDisTable(tablekey); + } catch (SQLException sqle2) { + if (isTableNotExist(info, sqle2.getSQLState())) { + String tablesql = createTableSql(info); + if (tablesql != null) { + st = conn.createStatement(); + st.execute(tablesql); + st.close(); + //鍐嶆墽琛屼竴閬嶅鍒惰〃鎿嶄綔 + st = conn.createStatement(); + st.execute(getTableCopySQL(info, newTable)); + st.close(); + info.addDisTable(tablekey); + } + } else { + logger.log(Level.SEVERE, "create table2(" + getTableCopySQL(info, newTable) + ") error", sqle2); + } + } + } + } + } + } + } + } + prestmt.close(); + prestmt = createInsertPreparedStatement(conn, sql, info, entitys); + int[] cs = prestmt.executeBatch(); + int c1 = 0; + for (int cc : cs) { + c1 += cc; + } + c = c1; + } + prestmt.close(); + //------------------------------------------------------------ + if (info.isLoggable(logger, Level.FINEST)) { //鎵撳嵃璋冭瘯淇℃伅 + char[] sqlchars = sql.toCharArray(); + for (final T value : entitys) { + //----------------------------- + StringBuilder sb = new StringBuilder(128); + int i = 0; + for (char ch : sqlchars) { + if (ch == '?') { + Object obj = info.getSQLValue(attrs[i++], value); + if (obj != null && obj.getClass().isArray()) { + sb.append("'[length=").append(java.lang.reflect.Array.getLength(obj)).append("]'"); + } else { + sb.append(info.formatSQLValue(obj, sqlFormatter)); + } + } else { + sb.append(ch); + } + } + String debugsql = sb.toString(); + if (info.isLoggable(logger, Level.FINEST, debugsql)) logger.finest(info.getType().getSimpleName() + " insert sql=" + debugsql.replaceAll("(\r|\n)", "\\n")); + } + } //鎵撳嵃缁撴潫 + return CompletableFuture.completedFuture(c); + } catch (SQLException e) { + return CompletableFuture.failedFuture(e); + } finally { + if (conn != null) writePool.offerConnection(conn); + } + } + + protected PreparedStatement createInsertPreparedStatement(final Connection conn, final String sql, + final EntityInfo info, T... entitys) throws SQLException { + Attribute[] attrs = info.insertAttributes; + final PreparedStatement prestmt = conn.prepareStatement(sql); + + for (final T value : entitys) { + batchStatementParameters(conn, prestmt, info, attrs, value); + prestmt.addBatch(); + } + return prestmt; + } + + protected int batchStatementParameters(Connection conn, PreparedStatement prestmt, EntityInfo info, Attribute[] attrs, T entity) throws SQLException { + int i = 0; + for (Attribute attr : attrs) { + Object val = info.getSQLValue(attr, entity); + if (val instanceof byte[]) { + Blob blob = conn.createBlob(); + blob.setBytes(1, (byte[]) val); + prestmt.setObject(++i, blob); + } else if (val instanceof Boolean) { + prestmt.setObject(++i, ((Boolean) val) ? (byte) 1 : (byte) 0); + } else if (val instanceof AtomicInteger) { + prestmt.setObject(++i, ((AtomicInteger) val).get()); + } else if (val instanceof AtomicLong) { + prestmt.setObject(++i, ((AtomicLong) val).get()); + } else if (val != null && !(val instanceof Number) && !(val instanceof CharSequence) && !(val instanceof java.util.Date) + && !val.getClass().getName().startsWith("java.sql.") && !val.getClass().getName().startsWith("java.time.")) { + prestmt.setObject(++i, info.jsonConvert.convertTo(attr.genericType(), val)); + } else if (val == null && info.isNotNullJson(attr)) { + prestmt.setObject(++i, ""); + } else { + prestmt.setObject(++i, val); + } + } + return i; + } + + @Override + protected CompletableFuture deleteDB(EntityInfo info, Flipper flipper, String sql) { + Connection conn = null; + try { + conn = writePool.pollConnection(); + conn.setReadOnly(false); + conn.setAutoCommit(true); + sql += ((flipper == null || flipper.getLimit() < 1) ? "" : (" LIMIT " + flipper.getLimit())); + if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " delete sql=" + sql); + final Statement stmt = conn.createStatement(); + int c = stmt.executeUpdate(sql); + stmt.close(); + return CompletableFuture.completedFuture(c); + } catch (SQLException e) { + if (isTableNotExist(info, e.getSQLState())) { + if (info.getTableStrategy() == null) { + String tablesql = createTableSql(info); + if (tablesql != null) { + try { + Statement st = conn.createStatement(); + st.execute(tablesql); + st.close(); + return CompletableFuture.completedFuture(0); + } catch (SQLException e2) { + return CompletableFuture.failedFuture(e2); + } + } + } + } + return CompletableFuture.failedFuture(e); + } finally { + if (conn != null) writePool.offerConnection(conn); + } + } + + @Override + protected CompletableFuture clearTableDB(EntityInfo info, final String table, String sql) { + Connection conn = null; + try { + conn = writePool.pollConnection(); + conn.setReadOnly(false); + conn.setAutoCommit(true); + final Statement stmt = conn.createStatement(); + int c = stmt.executeUpdate(sql); + stmt.close(); + return CompletableFuture.completedFuture(c); + } catch (SQLException e) { + if (isTableNotExist(info, e.getSQLState())) return CompletableFuture.completedFuture(-1); + return CompletableFuture.failedFuture(e); + } finally { + if (conn != null) writePool.offerConnection(conn); + } + } + + @Override + protected CompletableFuture dropTableDB(EntityInfo info, final String table, String sql) { + Connection conn = null; + try { + conn = writePool.pollConnection(); + conn.setReadOnly(false); + conn.setAutoCommit(true); + final Statement stmt = conn.createStatement(); + int c = stmt.executeUpdate(sql); + stmt.close(); + if (info.getTableStrategy() != null) { + String tablekey = table.indexOf('.') > 0 ? table : (conn.getCatalog() + '.' + table); + info.removeDisTable(tablekey); + } + return CompletableFuture.completedFuture(c); + } catch (SQLException e) { + if (isTableNotExist(info, e.getSQLState())) return CompletableFuture.completedFuture(-1); + return CompletableFuture.failedFuture(e); + } finally { + if (conn != null) writePool.offerConnection(conn); + } + } + + @Override + protected CompletableFuture updateEntityDB(EntityInfo info, T... entitys) { + Connection conn = null; + try { + conn = writePool.pollConnection(); + conn.setReadOnly(false); + conn.setAutoCommit(true); + final String updateSQL = info.getUpdateQuestionPrepareSQL(entitys[0]); + final PreparedStatement prestmt = conn.prepareStatement(updateSQL); + Attribute[] attrs = info.updateAttributes; + final boolean debugfinest = info.isLoggable(logger, Level.FINEST); + char[] sqlchars = debugfinest ? updateSQL.toCharArray() : null; + final Attribute primary = info.getPrimary(); + for (final T value : entitys) { + int k = batchStatementParameters(conn, prestmt, info, attrs, value); + prestmt.setObject(++k, primary.get(value)); + prestmt.addBatch();//------------------------------------------------------------ + if (debugfinest) { //鎵撳嵃璋冭瘯淇℃伅 + //----------------------------- + int i = 0; + StringBuilder sb = new StringBuilder(128); + for (char ch : sqlchars) { + if (ch == '?') { + Object obj = i == attrs.length ? info.getSQLValue(primary, value) : info.getSQLValue(attrs[i++], value); + if (obj != null && obj.getClass().isArray()) { + sb.append("'[length=").append(java.lang.reflect.Array.getLength(obj)).append("]'"); + } else { + sb.append(info.formatSQLValue(obj, sqlFormatter)); + } + } else { + sb.append(ch); + } + } + String debugsql = sb.toString(); + if (info.isLoggable(logger, Level.FINEST, debugsql)) logger.finest(info.getType().getSimpleName() + " updates sql=" + debugsql.replaceAll("(\r|\n)", "\\n")); + } //鎵撳嵃缁撴潫 + } + int[] pc = prestmt.executeBatch(); + int c = 0; + for (int p : pc) { + if (p >= 0) c += p; + } + prestmt.close(); + return CompletableFuture.completedFuture(c); + } catch (SQLException e) { + if (isTableNotExist(info, e.getSQLState())) { + if (info.getTableStrategy() == null) { + String tablesql = createTableSql(info); + if (tablesql != null) { + try { + Statement st = conn.createStatement(); + st.execute(tablesql); + st.close(); + } catch (SQLException e2) { + } + } + } + return CompletableFuture.completedFuture(0); + } + return CompletableFuture.failedFuture(e); + } finally { + if (conn != null) writePool.offerConnection(conn); + } + } + + @Override + protected CompletableFuture updateColumnDB(EntityInfo info, Flipper flipper, String sql, boolean prepared, Object... params) { + Connection conn = null; + try { + conn = writePool.pollConnection(); + conn.setReadOnly(false); + conn.setAutoCommit(true); + if (prepared) { + final PreparedStatement prestmt = conn.prepareStatement(sql); + int index = 0; + for (Object param : params) { + Blob blob = conn.createBlob(); + blob.setBytes(1, (byte[]) param); + prestmt.setBlob(++index, blob); + } + int c = prestmt.executeUpdate(); + prestmt.close(); + return CompletableFuture.completedFuture(c); + } else { + if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " update sql=" + sql); + final Statement stmt = conn.createStatement(); + int c = stmt.executeUpdate(sql); + stmt.close(); + return CompletableFuture.completedFuture(c); + } + } catch (SQLException e) { + if (isTableNotExist(info, e.getSQLState())) { + if (info.getTableStrategy() == null) { + String tablesql = createTableSql(info); + if (tablesql != null) { + try { + Statement st = conn.createStatement(); + st.execute(tablesql); + st.close(); + } catch (SQLException e2) { + } + } + } + return CompletableFuture.completedFuture(0); + } + return CompletableFuture.failedFuture(e); + } finally { + if (conn != null) writePool.offerConnection(conn); + } + } + + @Override + protected CompletableFuture> getNumberMapDB(EntityInfo info, String sql, FilterFuncColumn... columns) { + Connection conn = null; + final Map map = new HashMap<>(); + try { + conn = readPool.pollConnection(); + //conn.setReadOnly(true); + final Statement stmt = conn.createStatement(); + ResultSet set = stmt.executeQuery(sql); + if (set.next()) { + int index = 0; + for (FilterFuncColumn ffc : columns) { + for (String col : ffc.cols()) { + Object o = set.getObject(++index); + Number rs = ffc.getDefvalue(); + if (o != null) rs = (Number) o; + map.put(ffc.col(col), rs); + } + } + } + set.close(); + stmt.close(); + return CompletableFuture.completedFuture(map); + } catch (SQLException e) { + if (isTableNotExist(info, e.getSQLState())) { + if (info.getTableStrategy() == null) { + String tablesql = createTableSql(info); + if (tablesql != null) { + try { + Statement st = conn.createStatement(); + st.execute(tablesql); + st.close(); + } catch (SQLException e2) { + } + } + } + return CompletableFuture.completedFuture(map); + } + return CompletableFuture.failedFuture(e); + } finally { + if (conn != null) readPool.offerConnection(conn); + } + } + + @Override + protected CompletableFuture getNumberResultDB(EntityInfo info, String sql, Number defVal, String column) { + Connection conn = null; + try { + conn = readPool.pollConnection(); + //conn.setReadOnly(true); + final Statement stmt = conn.createStatement(); + Number rs = defVal; + ResultSet set = stmt.executeQuery(sql); + if (set.next()) { + Object o = set.getObject(1); + if (o != null) rs = (Number) o; + } + set.close(); + stmt.close(); + return CompletableFuture.completedFuture(rs); + } catch (SQLException e) { + if (isTableNotExist(info, e.getSQLState())) { + if (info.getTableStrategy() == null) { + String tablesql = createTableSql(info); + if (tablesql != null) { + try { + Statement st = conn.createStatement(); + st.execute(tablesql); + st.close(); + } catch (SQLException e2) { + } + } + } + return CompletableFuture.completedFuture(defVal); + } + return CompletableFuture.failedFuture(e); + } finally { + if (conn != null) readPool.offerConnection(conn); + } + } + + @Override + protected CompletableFuture> queryColumnMapDB(EntityInfo info, String sql, String keyColumn) { + Connection conn = null; + Map rs = new LinkedHashMap<>(); + try { + conn = readPool.pollConnection(); + //conn.setReadOnly(true); + final Statement stmt = conn.createStatement(); + ResultSet set = stmt.executeQuery(sql); + ResultSetMetaData rsd = set.getMetaData(); + boolean smallint = rsd == null ? false : rsd.getColumnType(1) == Types.SMALLINT; + while (set.next()) { + rs.put((K) (smallint ? set.getShort(1) : set.getObject(1)), (N) set.getObject(2)); + } + set.close(); + stmt.close(); + return CompletableFuture.completedFuture(rs); + } catch (SQLException e) { + if (isTableNotExist(info, e.getSQLState())) { + if (info.getTableStrategy() == null) { + String tablesql = createTableSql(info); + if (tablesql != null) { + try { + Statement st = conn.createStatement(); + st.execute(tablesql); + st.close(); + } catch (SQLException e2) { + } + } + } + return CompletableFuture.completedFuture(rs); + } + return CompletableFuture.failedFuture(e); + } finally { + if (conn != null) readPool.offerConnection(conn); + } + } + + @Override + protected CompletableFuture> queryColumnMapDB(EntityInfo info, String sql, final ColumnNode[] funcNodes, final String[] groupByColumns) { + Connection conn = null; + Map rs = new LinkedHashMap<>(); + try { + conn = readPool.pollConnection(); + //conn.setReadOnly(true); + final Statement stmt = conn.createStatement(); + ResultSet set = stmt.executeQuery(sql); + ResultSetMetaData rsd = set.getMetaData(); + boolean[] smallints = null; + while (set.next()) { + int index = 0; + Serializable[] keys = new Serializable[groupByColumns.length]; + if (smallints == null) { + smallints = new boolean[keys.length]; + for (int i = 0; i < keys.length; i++) { + smallints[i] = rsd == null ? false : rsd.getColumnType(i + 1) == Types.SMALLINT; + } + } + for (int i = 0; i < keys.length; i++) { + keys[i] = (Serializable) ((smallints[i] && index == 0) ? set.getShort(++index) : set.getObject(++index)); + } + Number[] vals = new Number[funcNodes.length]; + for (int i = 0; i < vals.length; i++) { + vals[i] = (Number) set.getObject(++index); + } + rs.put(keys, vals); + } + set.close(); + stmt.close(); + return CompletableFuture.completedFuture(rs); + } catch (SQLException e) { + if (isTableNotExist(info, e.getSQLState())) { + if (info.getTableStrategy() == null) { + String tablesql = createTableSql(info); + if (tablesql != null) { + try { + Statement st = conn.createStatement(); + st.execute(tablesql); + st.close(); + } catch (SQLException e2) { + } + } + } + return CompletableFuture.completedFuture(rs); + } + return CompletableFuture.failedFuture(e); + } finally { + if (conn != null) readPool.offerConnection(conn); + } + } + + @Override + protected CompletableFuture findDB(EntityInfo info, String sql, boolean onlypk, SelectColumn selects) { + Connection conn = null; + try { + conn = readPool.pollConnection(); + //conn.setReadOnly(true); + final PreparedStatement ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); + ps.setFetchSize(1); + final DataResultSet set = createDataResultSet(ps.executeQuery()); + T rs = set.next() ? selects == null ? info.getFullEntityValue(set) : info.getEntityValue(selects, set) : null; + set.close(); + ps.close(); + return CompletableFuture.completedFuture(rs); + } catch (SQLException e) { + if (isTableNotExist(info, e.getSQLState())) { + if (info.getTableStrategy() == null) { + String tablesql = createTableSql(info); + if (tablesql != null) { + try { + Statement st = conn.createStatement(); + st.execute(tablesql); + st.close(); + } catch (SQLException e2) { + } + } + } + return CompletableFuture.completedFuture(null); + } + return CompletableFuture.failedFuture(e); + } finally { + if (conn != null) readPool.offerConnection(conn); + } + } + + @Override + protected CompletableFuture findColumnDB(EntityInfo info, String sql, boolean onlypk, String column, Serializable defValue) { + Connection conn = null; + try { + conn = readPool.pollConnection(); + //conn.setReadOnly(true); + final Attribute attr = info.getAttribute(column); + final PreparedStatement ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); + ps.setFetchSize(1); + final DataResultSet set = createDataResultSet(ps.executeQuery()); + Serializable val = defValue; + if (set.next()) { + val = info.getFieldValue(attr, set, 1); + } + set.close(); + ps.close(); + return CompletableFuture.completedFuture(val == null ? defValue : val); + } catch (SQLException e) { + if (isTableNotExist(info, e.getSQLState())) { + if (info.getTableStrategy() == null) { + String tablesql = createTableSql(info); + if (tablesql != null) { + try { + Statement st = conn.createStatement(); + st.execute(tablesql); + st.close(); + } catch (SQLException e2) { + } + } + } + return CompletableFuture.completedFuture(null); + } + return CompletableFuture.failedFuture(e); + } finally { + if (conn != null) readPool.offerConnection(conn); + } + } + + @Override + protected CompletableFuture existsDB(EntityInfo info, String sql, boolean onlypk) { + Connection conn = null; + try { + conn = readPool.pollConnection(); + //conn.setReadOnly(true); + final PreparedStatement ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); + final ResultSet set = ps.executeQuery(); + boolean rs = set.next() ? (set.getInt(1) > 0) : false; + set.close(); + ps.close(); + if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " exists (" + rs + ") sql=" + sql); + return CompletableFuture.completedFuture(rs); + } catch (SQLException e) { + if (isTableNotExist(info, e.getSQLState())) { + if (info.getTableStrategy() == null) { + String tablesql = createTableSql(info); + if (tablesql != null) { + try { + Statement st = conn.createStatement(); + st.execute(tablesql); + st.close(); + } catch (SQLException e2) { + } + } + } + return CompletableFuture.completedFuture(false); + } + return CompletableFuture.failedFuture(e); + } finally { + if (conn != null) readPool.offerConnection(conn); + } + } + + @Override + protected CompletableFuture> querySheetDB(EntityInfo info, final boolean readcache, boolean needtotal, final boolean distinct, SelectColumn selects, Flipper flipper, FilterNode node) { + Connection conn = null; + try { + conn = readPool.pollConnection(); + //conn.setReadOnly(true); + final SelectColumn sels = selects; + final List list = new ArrayList(); + final Map joinTabalis = node == null ? null : node.getJoinTabalis(); + final CharSequence join = node == null ? null : node.createSQLJoin(this, false, joinTabalis, new HashSet<>(), info); + final CharSequence where = node == null ? null : node.createSQLExpress(this, info, joinTabalis); + if ("mysql".equals(dbtype()) || "postgresql".equals(dbtype())) { //sql鍙互甯imit銆乷ffset + final String listsql = "SELECT " + (distinct ? "DISTINCT " : "") + info.getFullQueryColumns("a", selects) + " FROM " + info.getTable(node) + " a" + (join == null ? "" : join) + + ((where == null || where.length() == 0) ? "" : (" WHERE " + where)) + createSQLOrderby(info, flipper) + + (flipper == null || flipper.getLimit() < 1 ? "" : (" LIMIT " + flipper.getLimit() + " OFFSET " + flipper.getOffset())); + if (readcache && info.isLoggable(logger, Level.FINEST, listsql)) { + logger.finest(info.getType().getSimpleName() + " query sql=" + listsql); + } + PreparedStatement ps = conn.prepareStatement(listsql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); + ResultSet set = ps.executeQuery(); + final DataResultSet rr = createDataResultSet(set); + while (set.next()) { + list.add(getEntityValue(info, sels, rr)); + } + set.close(); + ps.close(); + long total = list.size(); + if (needtotal) { + final String countsql = "SELECT " + (distinct ? "DISTINCT COUNT(" + info.getQueryColumns("a", selects) + ")" : "COUNT(*)") + " FROM " + info.getTable(node) + " a" + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where)); + if (readcache && info.isLoggable(logger, Level.FINEST, countsql)) { + logger.finest(info.getType().getSimpleName() + " query countsql=" + countsql); + } + ps = conn.prepareStatement(countsql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); + set = ps.executeQuery(); + if (set.next()) total = set.getLong(1); + set.close(); + ps.close(); + } + return CompletableFuture.completedFuture(new Sheet<>(total, list)); + } + final String listsql = "SELECT " + (distinct ? "DISTINCT " : "") + info.getFullQueryColumns("a", selects) + " FROM " + info.getTable(node) + " a" + (join == null ? "" : join) + + ((where == null || where.length() == 0) ? "" : (" WHERE " + where)) + info.createSQLOrderby(flipper); + if (readcache && info.isLoggable(logger, Level.FINEST, listsql)) { + logger.finest(info.getType().getSimpleName() + " query sql=" + listsql + (flipper == null || flipper.getLimit() < 1 ? "" : (" LIMIT " + flipper.getLimit() + " OFFSET " + flipper.getOffset()))); + } + //conn.setReadOnly(true); + final PreparedStatement ps = conn.prepareStatement(listsql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); + if (flipper != null && flipper.getLimit() > 0) ps.setFetchSize(flipper.getLimit()); + final ResultSet set = ps.executeQuery(); + if (flipper != null && flipper.getOffset() > 0) set.absolute(flipper.getOffset()); + final int limit = flipper == null || flipper.getLimit() < 1 ? Integer.MAX_VALUE : flipper.getLimit(); + int i = 0; + final DataResultSet rr = createDataResultSet(set); + if (sels == null) { + while (set.next()) { + i++; + list.add(info.getFullEntityValue(rr)); + if (limit <= i) break; + } + } else { + while (set.next()) { + i++; + list.add(info.getEntityValue(sels, rr)); + if (limit <= i) break; + } + } + long total = list.size(); + if (needtotal && flipper != null) { + set.last(); + total = set.getRow(); + } + set.close(); + ps.close(); + return CompletableFuture.completedFuture(new Sheet<>(total, list)); + } catch (SQLException e) { + if (isTableNotExist(info, e.getSQLState())) { + if (info.getTableStrategy() == null) { + String tablesql = createTableSql(info); + if (tablesql != null) { + try { + Statement st = conn.createStatement(); + st.execute(tablesql); + st.close(); + } catch (SQLException e2) { + } + } + } + return CompletableFuture.completedFuture(new Sheet<>(0, new ArrayList())); + } + return CompletableFuture.failedFuture(e); + } finally { + if (conn != null) readPool.offerConnection(conn); + } + } + + /** + * 鐩存帴鏈湴鎵цSQL璇彞杩涜澧炲垹鏀规搷浣滐紝杩滅▼妯″紡涓嶅彲鐢
+ * 閫氬父鐢ㄤ簬澶嶆潅鐨勬洿鏂版搷浣
+ * + * @param sql SQL璇彞 + * + * @return 缁撴灉鏁扮粍 + */ + @Local + @Override + public int directExecute(String sql) { + return directExecute(new String[]{sql})[0]; + } + + /** + * 鐩存帴鏈湴鎵цSQL璇彞杩涜澧炲垹鏀规搷浣滐紝杩滅▼妯″紡涓嶅彲鐢
+ * 閫氬父鐢ㄤ簬澶嶆潅鐨勬洿鏂版搷浣
+ * + * @param sqls SQL璇彞 + * + * @return 缁撴灉鏁扮粍 + */ + @Local + @Override + public int[] directExecute(String... sqls) { + if (sqls.length == 0) return new int[0]; + Connection conn = writePool.pollConnection(); + try { + conn.setReadOnly(false); + final Statement stmt = conn.createStatement(); + final int[] rs = new int[sqls.length]; + int i = -1; + for (String sql : sqls) { + rs[++i] = stmt.execute(sql) ? 1 : 0; + } + stmt.close(); + return rs; + } catch (SQLException e) { + throw new RuntimeException(e); + } finally { + if (conn != null) writePool.offerConnection(conn); + } + } + + /** + * 鐩存帴鏈湴鎵цSQL璇彞杩涜鏌ヨ锛岃繙绋嬫ā寮忎笉鍙敤
+ * 閫氬父鐢ㄤ簬澶嶆潅鐨勫叧鑱旀煡璇
+ * + * @param 娉涘瀷 + * @param sql SQL璇彞 + * @param handler 鍥炶皟鍑芥暟 + * + * @return 缁撴灉 + */ + @Local + @Override + public V directQuery(String sql, Function handler) { + final Connection conn = readPool.pollConnection(); + try { + if (logger.isLoggable(Level.FINEST)) logger.finest("direct query sql=" + sql); + //conn.setReadOnly(true); + final Statement statement = conn.createStatement(); + //final PreparedStatement statement = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); + final ResultSet set = statement.executeQuery(sql);// ps.executeQuery(); + V rs = handler.apply(createDataResultSet(set)); + set.close(); + statement.close(); + return rs; + } catch (Exception ex) { + throw new RuntimeException(ex); + } finally { + if (conn != null) readPool.offerConnection(conn); + } + } + + public static DataResultSet createDataResultSet(ResultSet set) { + + final ResultSet rr = set; + + return new DataResultSet() { + + @Override + public Serializable getObject(Attribute attr, int index, String column) { + Class t = attr.type(); + if (t == java.util.Date.class) { + Object val = index > 0 ? getObject(index) : getObject(column); + if (val == null) return null; + return new java.util.Date(((java.sql.Date) val).getTime()); + } else if (t == java.time.LocalDate.class) { + Object val = index > 0 ? getObject(index) : getObject(column); + if (val == null) return null; + return ((java.sql.Date) val).toLocalDate(); + } else if (t == java.time.LocalTime.class) { + Object val = index > 0 ? getObject(index) : getObject(column); + if (val == null) return null; + return ((java.sql.Time) val).toLocalTime(); + } else if (t == java.time.LocalDateTime.class) { + Object val = index > 0 ? getObject(index) : getObject(column); + if (val == null) return null; + return ((java.sql.Timestamp) val).toLocalDateTime(); + } else if (t.getName().startsWith("java.sql.")) { + return index > 0 ? (Serializable) getObject(index) : (Serializable) getObject(column); + } + return DataResultSet.getRowColumnValue(this, attr, index, column); + } + + @Override + public boolean next() { + try { + return rr.next(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + @Override + public boolean wasNull() { + try { + return rr.wasNull(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + @Override + public void close() { + try { + rr.close(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + @Override + public Object getObject(int index) { + try { + return rr.getObject(index); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + @Override + public Object getObject(String column) { + try { + return rr.getObject(column); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + }; + } + + protected class ConnectionPool implements AutoCloseable { + + protected final LongAdder closeCounter = new LongAdder(); //宸插叧闂繛鎺ユ暟 + + protected final LongAdder usingCounter = new LongAdder(); //浣跨敤涓繛鎺ユ暟 + + protected final LongAdder creatCounter = new LongAdder(); //宸插垱寤鸿繛鎺ユ暟 + + protected final LongAdder cycleCounter = new LongAdder(); //宸插鐢ㄨ繛鎺ユ暟 + + protected final LongAdder waitingCounter = new LongAdder(); //鍙敤涓繛鎺ユ暟 + + protected final java.sql.Driver driver; + + protected final Properties connectAttrs; + + protected final ArrayBlockingQueue queue; + + protected int connectTimeoutSeconds; + + protected int maxconns; + + protected String url; + + public ConnectionPool(Properties prop) { + this.connectTimeoutSeconds = Integer.decode(prop.getProperty(JDBC_CONNECTTIMEOUT_SECONDS, "6")); + this.maxconns = Math.max(1, Integer.decode(prop.getProperty(JDBC_CONNECTIONS_LIMIT, "" + Utility.cpus() * 4))); + this.queue = new ArrayBlockingQueue<>(maxconns); + this.url = prop.getProperty(JDBC_URL); + String username = prop.getProperty(JDBC_USER, ""); + String password = prop.getProperty(JDBC_PWD, ""); + this.connectAttrs = new Properties(); + if (username != null) this.connectAttrs.put("user", username); + if (password != null) this.connectAttrs.put("password", password); + try { + this.driver = DriverManager.getDriver(this.url); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + public synchronized Connection pollConnection() { + Connection conn = queue.poll(); + if (conn == null) { + if (usingCounter.intValue() >= maxconns) { + try { + conn = queue.poll(connectTimeoutSeconds, TimeUnit.SECONDS); + } catch (InterruptedException t) { + logger.log(Level.WARNING, "take pooled connection error", t); + } + if (conn == null) throw new RuntimeException("create pooled connection timeout"); + } + } + if (conn != null) { + usingCounter.increment(); + waitingCounter.decrement(); + if (checkValid(conn)) { + cycleCounter.increment(); + return conn; + } else { + offerConnection(conn); + conn = null; + } + } + try { + conn = driver.connect(url, connectAttrs); + } catch (SQLException ex) { + throw new RuntimeException(ex); + } + usingCounter.increment(); + creatCounter.increment(); + return conn; + } + + public void offerConnection(final C connection) { + Connection conn = (Connection) connection; + if (conn == null) return; + try { + if (checkValid(conn) && queue.offer(conn)) { + usingCounter.decrement(); + waitingCounter.increment(); + } else { + usingCounter.decrement(); + closeCounter.increment(); + conn.close(); + } + } catch (Exception e) { + logger.log(Level.WARNING, "closeSQLConnection abort", e); + } + } + + protected boolean checkValid(Connection conn) { + try { + return !conn.isClosed() && conn.isValid(1); + } catch (SQLException ex) { + if (!"08S01".equals(ex.getSQLState())) {//MySQL鐗规э紝 闀挎椂闂磋繛鎺ユ病浣跨敤浼氭姏鍑篶om.mysql.jdbc.exceptions.jdbc4.CommunicationsException + logger.log(Level.FINER, "result.getConnection from pooled connection abort [" + ex.getSQLState() + "]", ex); + } + return false; + } + } + + @Override + public void close() { + queue.stream().forEach(x -> { + try { + x.close(); + } catch (Exception e) { + } + }); + } + } +} diff --git a/src/main/java/org/redkale/source/DataResultSet.java b/src/main/java/org/redkale/source/DataResultSet.java index b0cbbdf41..b976445c2 100644 --- a/src/main/java/org/redkale/source/DataResultSet.java +++ b/src/main/java/org/redkale/source/DataResultSet.java @@ -1,151 +1,151 @@ -/* - * 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.source; - -import java.io.Serializable; -import java.math.*; -import java.util.concurrent.atomic.*; -import org.redkale.convert.json.JsonConvert; -import org.redkale.util.Attribute; - -/** - * java.sql.ResultSet鐨勭畝鍖栫増銆
- *
- * 瀛楁绫诲瀷鏀寔锛
- * 1銆乥oolean/Boolean
- * 2銆乥yte/Byte
- * 3銆乻hort/Short
- * 4銆乧har/Character
- * 5銆乮nt/Integer/AtomicInteger
- * 6銆乴ong/Long/AtomicLong/LongAdder
- * 7銆乫loat/Float
- * 8銆乨ouble/Double
- * 9銆乯ava.math.BigInteger
- * 10銆乯ava.math.BigDecimal
- * 11銆丼tring
- * 12銆乥yte[]
- * 13銆乯ava.time.LocalDate/java.sql.Date/java.util.Date
- * 14銆乯ava.time.LocalTime/java.sql.Time
- * 15銆乯ava.time.LocalDateTime/java.sql.Timestamp
- * 16銆丣avaBean/鍏朵粬鍙疛SON鍖栫被鍨
- * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @since 2.5.0 - */ -public interface DataResultSet extends EntityInfo.DataResultSetRow { - - public boolean next(); - - public void close(); - - public static Serializable getRowColumnValue(final EntityInfo.DataResultSetRow row, Attribute attr, int index, String column) { - final Class t = attr.type(); - Serializable o; - if (t == byte[].class) { - Object blob = index > 0 ? row.getObject(index) : row.getObject(column); - if (blob == null) { - o = null; - } else { //涓嶆敮鎸佽秴杩2G鐨勬暟鎹 -// if (blob instanceof java.sql.Blob) { -// java.sql.Blob b = (java.sql.Blob) blob; -// try { -// o = b.getBytes(1, (int) b.length()); -// } catch (Exception e) { //涓鑸笉浼氬彂鐢 -// o = null; -// } -// } else { - o = (byte[]) blob; - //} - CryptHandler cryptHandler = attr.attach(); - if (cryptHandler != null) o = (Serializable) cryptHandler.decrypt(o); - } - } else { - o = (Serializable) (index > 0 ? row.getObject(index) : row.getObject(column)); - CryptHandler cryptHandler = attr.attach(); - if (cryptHandler != null) o = (Serializable) cryptHandler.decrypt(o); - if (t.isPrimitive()) { - if (o != null) { - if (t == int.class) { - o = ((Number) o).intValue(); - } else if (t == long.class) { - o = ((Number) o).longValue(); - } else if (t == short.class) { - o = ((Number) o).shortValue(); - } else if (t == float.class) { - o = ((Number) o).floatValue(); - } else if (t == double.class) { - o = ((Number) o).doubleValue(); - } else if (t == byte.class) { - o = ((Number) o).byteValue(); - } else if (t == char.class) { - o = (char) ((Number) o).intValue(); - } else if (t == boolean.class) { - o = (Boolean) o; - } - } else if (t == int.class) { - o = 0; - } else if (t == long.class) { - o = 0L; - } else if (t == short.class) { - o = (short) 0; - } else if (t == float.class) { - o = 0.0f; - } else if (t == double.class) { - o = 0.0d; - } else if (t == byte.class) { - o = (byte) 0; - } else if (t == boolean.class) { - o = false; - } else if (t == char.class) { - o = (char) 0; - } - } else if (t == AtomicInteger.class) { - if (o != null) { - o = new AtomicInteger(((Number) o).intValue()); - } else { - o = new AtomicInteger(); - } - } else if (t == AtomicLong.class) { - if (o != null) { - o = new AtomicLong(((Number) o).longValue()); - } else { - o = new AtomicLong(); - } - } else if (t == LongAdder.class) { - if (o != null) { - LongAdder v = new LongAdder(); - v.add(((Number) o).longValue()); - o = v; - } else { - o = new LongAdder(); - } - } else if (t == BigInteger.class) { - if (o != null && !(o instanceof BigInteger)) { - if (o instanceof byte[]) { - o = new BigInteger((byte[]) o); - } else { - o = new BigInteger(o.toString(), 10); - } - } - } else if (t == BigDecimal.class) { - if (o != null && !(o instanceof BigDecimal)) { - if (o instanceof byte[]) { - o = new BigDecimal(new String((byte[]) o)); - } else { - o = new BigInteger(o.toString()); - } - } - } else if (o != null && !t.isAssignableFrom(o.getClass()) && o instanceof CharSequence) { - o = ((CharSequence) o).length() == 0 ? null : JsonConvert.root().convertFrom(attr.genericType(), o.toString()); - } - } - return o; - } - -} +/* + * 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.source; + +import java.io.Serializable; +import java.math.*; +import java.util.concurrent.atomic.*; +import org.redkale.convert.json.JsonConvert; +import org.redkale.util.Attribute; + +/** + * java.sql.ResultSet鐨勭畝鍖栫増銆
+ *
+ * 瀛楁绫诲瀷鏀寔锛
+ * 1銆乥oolean/Boolean
+ * 2銆乥yte/Byte
+ * 3銆乻hort/Short
+ * 4銆乧har/Character
+ * 5銆乮nt/Integer/AtomicInteger
+ * 6銆乴ong/Long/AtomicLong/LongAdder
+ * 7銆乫loat/Float
+ * 8銆乨ouble/Double
+ * 9銆乯ava.math.BigInteger
+ * 10銆乯ava.math.BigDecimal
+ * 11銆丼tring
+ * 12銆乥yte[]
+ * 13銆乯ava.time.LocalDate/java.sql.Date/java.util.Date
+ * 14銆乯ava.time.LocalTime/java.sql.Time
+ * 15銆乯ava.time.LocalDateTime/java.sql.Timestamp
+ * 16銆丣avaBean/鍏朵粬鍙疛SON鍖栫被鍨
+ * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @since 2.5.0 + */ +public interface DataResultSet extends EntityInfo.DataResultSetRow { + + public boolean next(); + + public void close(); + + public static Serializable getRowColumnValue(final EntityInfo.DataResultSetRow row, Attribute attr, int index, String column) { + final Class t = attr.type(); + Serializable o; + if (t == byte[].class) { + Object blob = index > 0 ? row.getObject(index) : row.getObject(column); + if (blob == null) { + o = null; + } else { //涓嶆敮鎸佽秴杩2G鐨勬暟鎹 +// if (blob instanceof java.sql.Blob) { +// java.sql.Blob b = (java.sql.Blob) blob; +// try { +// o = b.getBytes(1, (int) b.length()); +// } catch (Exception e) { //涓鑸笉浼氬彂鐢 +// o = null; +// } +// } else { + o = (byte[]) blob; + //} + CryptHandler cryptHandler = attr.attach(); + if (cryptHandler != null) o = (Serializable) cryptHandler.decrypt(o); + } + } else { + o = (Serializable) (index > 0 ? row.getObject(index) : row.getObject(column)); + CryptHandler cryptHandler = attr.attach(); + if (cryptHandler != null) o = (Serializable) cryptHandler.decrypt(o); + if (t.isPrimitive()) { + if (o != null) { + if (t == int.class) { + o = ((Number) o).intValue(); + } else if (t == long.class) { + o = ((Number) o).longValue(); + } else if (t == short.class) { + o = ((Number) o).shortValue(); + } else if (t == float.class) { + o = ((Number) o).floatValue(); + } else if (t == double.class) { + o = ((Number) o).doubleValue(); + } else if (t == byte.class) { + o = ((Number) o).byteValue(); + } else if (t == char.class) { + o = (char) ((Number) o).intValue(); + } else if (t == boolean.class) { + o = (Boolean) o; + } + } else if (t == int.class) { + o = 0; + } else if (t == long.class) { + o = 0L; + } else if (t == short.class) { + o = (short) 0; + } else if (t == float.class) { + o = 0.0f; + } else if (t == double.class) { + o = 0.0d; + } else if (t == byte.class) { + o = (byte) 0; + } else if (t == boolean.class) { + o = false; + } else if (t == char.class) { + o = (char) 0; + } + } else if (t == AtomicInteger.class) { + if (o != null) { + o = new AtomicInteger(((Number) o).intValue()); + } else { + o = new AtomicInteger(); + } + } else if (t == AtomicLong.class) { + if (o != null) { + o = new AtomicLong(((Number) o).longValue()); + } else { + o = new AtomicLong(); + } + } else if (t == LongAdder.class) { + if (o != null) { + LongAdder v = new LongAdder(); + v.add(((Number) o).longValue()); + o = v; + } else { + o = new LongAdder(); + } + } else if (t == BigInteger.class) { + if (o != null && !(o instanceof BigInteger)) { + if (o instanceof byte[]) { + o = new BigInteger((byte[]) o); + } else { + o = new BigInteger(o.toString(), 10); + } + } + } else if (t == BigDecimal.class) { + if (o != null && !(o instanceof BigDecimal)) { + if (o instanceof byte[]) { + o = new BigDecimal(new String((byte[]) o)); + } else { + o = new BigInteger(o.toString()); + } + } + } else if (o != null && !t.isAssignableFrom(o.getClass()) && o instanceof CharSequence) { + o = ((CharSequence) o).length() == 0 ? null : JsonConvert.root().convertFrom(attr.genericType(), o.toString()); + } + } + return o; + } + +} diff --git a/src/main/java/org/redkale/source/DataSource.java b/src/main/java/org/redkale/source/DataSource.java index 0f9b294d7..63d0e6d64 100644 --- a/src/main/java/org/redkale/source/DataSource.java +++ b/src/main/java/org/redkale/source/DataSource.java @@ -1,3326 +1,3326 @@ -/* - * 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.source; - -import java.io.Serializable; -import java.util.*; -import java.util.concurrent.CompletableFuture; -import java.util.stream.Stream; -import org.redkale.util.*; - -/** - * - * DataSource 涓烘暟鎹簱鎴栧唴瀛樻暟鎹簱鐨勬暟鎹簮锛屾彁渚涚被浼糐PA銆丠ibernate鐨勬帴鍙d笌鍔熻兘銆
- * 杩斿洖绫诲瀷涓篊ompletableFuture鐨勬帴鍙d负寮傛鎺ュ彛
- *
- * 瀛楁绫诲瀷鏀寔锛
- * 1銆乥oolean/Boolean
- * 2銆乥yte/Byte
- * 3銆乻hort/Short
- * 4銆乧har/Character
- * 5銆乮nt/Integer/AtomicInteger
- * 6銆乴ong/Long/AtomicLong/LongAdder
- * 7銆乫loat/Float
- * 8銆乨ouble/Double
- * 9銆乯ava.math.BigInteger
- * 10銆乯ava.math.BigDecimal
- * 11銆丼tring
- * 12銆乥yte[]
- * 13銆乯ava.time.LocalDate/java.sql.Date/java.util.Date
- * 14銆乯ava.time.LocalTime/java.sql.Time
- * 15銆乯ava.time.LocalDateTime/java.sql.Timestamp
- * 16銆丣avaBean/鍏朵粬鍙疛SON鍖栫被鍨
- * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@SuppressWarnings("unchecked") -public interface DataSource { - - /** - * 鑾峰彇鏁版嵁婧愮被鍨 - * - * @return String - */ - public String getType(); - - /** - * - * 鎻愬彇棰勭紪璇慐ntity绫伙紝涓昏鐢ㄤ簬native-image浣跨敤 - * - * @param 娉涘瀷 - * @param clazz Entity瀹炰綋绫 - */ - public void compile(Class clazz); - - //----------------------insertAsync----------------------------- - //insert 鏆傛椂涓嶆敮鎸丆ollection銆丼tream锛 鍥犱负瀛樺湪@RpcCall闂 - /** - * 鏂板璁板綍锛 澶氬璞″繀椤绘槸鍚屼竴涓狤ntity绫讳笖蹇呴』鍦ㄥ悓涓寮犺〃涓
- * - * @param 娉涘瀷 - * @param entitys Entity瀵硅薄 - * - * @return 褰卞搷鐨勮褰曟潯鏁 - */ - public int insert(final T... entitys); - - /** - * 鏂板璁板綍锛 澶氬璞″繀椤绘槸鍚屼竴涓狤ntity绫讳笖蹇呴』鍦ㄥ悓涓寮犺〃涓
- * - * @param 娉涘瀷 - * @param entitys Entity瀵硅薄 - * - * @return 褰卞搷鐨勮褰曟潯鏁 - */ - default int insert(final Collection entitys) { - if (entitys == null || entitys.isEmpty()) return 0; - return insert(entitys.toArray()); - } - - /** - * 鏂板璁板綍锛 澶氬璞″繀椤绘槸鍚屼竴涓狤ntity绫讳笖蹇呴』鍦ㄥ悓涓寮犺〃涓
- * - * @param 娉涘瀷 - * @param entitys Entity瀵硅薄 - * - * @return 褰卞搷鐨勮褰曟潯鏁 - */ - default int insert(final Stream entitys) { - if (entitys == null) return 0; - return insert(entitys.toArray()); - } - - /** - * 鏂板璁板綍锛 澶氬璞″繀椤绘槸鍚屼竴涓狤ntity绫讳笖蹇呴』鍦ㄥ悓涓寮犺〃涓
- * - * @param 娉涘瀷 - * @param entitys Entity瀵硅薄 - * - * @return CompletableFuture - */ - public CompletableFuture insertAsync(final T... entitys); - - /** - * 鏂板璁板綍锛 澶氬璞″繀椤绘槸鍚屼竴涓狤ntity绫讳笖蹇呴』鍦ㄥ悓涓寮犺〃涓
- * - * @param 娉涘瀷 - * @param entitys Entity瀵硅薄 - * - * @return CompletableFuture - */ - default CompletableFuture insertAsync(final Collection entitys) { - if (entitys == null || entitys.isEmpty()) return CompletableFuture.completedFuture(0); - return insertAsync(entitys.toArray()); - } - - /** - * 鏂板璁板綍锛 澶氬璞″繀椤绘槸鍚屼竴涓狤ntity绫讳笖蹇呴』鍦ㄥ悓涓寮犺〃涓
- * - * @param 娉涘瀷 - * @param entitys Entity瀵硅薄 - * - * @return CompletableFuture - */ - default CompletableFuture insertAsync(final Stream entitys) { - if (entitys == null) return CompletableFuture.completedFuture(0); - return insertAsync(entitys.toArray()); - } - - //-------------------------deleteAsync-------------------------- - /** - * 鍒犻櫎鎸囧畾涓婚敭鍊肩殑璁板綍锛 澶氬璞″繀椤绘槸鍚屼竴涓狤ntity绫讳笖蹇呴』鍦ㄥ悓涓寮犺〃涓
- * 绛変环SQL: DELETE FROM {table} WHERE {primary} IN {values.id}
- * - * @param 娉涘瀷 - * @param entitys Entity瀵硅薄 - * - * @return 褰卞搷鐨勮褰曟潯鏁 - */ - public int delete(final T... entitys); - - /** - * 鍒犻櫎鎸囧畾涓婚敭鍊肩殑璁板綍锛 澶氬璞″繀椤绘槸鍚屼竴涓狤ntity绫讳笖蹇呴』鍦ㄥ悓涓寮犺〃涓
- * 绛変环SQL: DELETE FROM {table} WHERE {primary} IN {values.id}
- * - * @param 娉涘瀷 - * @param entitys Entity瀵硅薄 - * - * @return 褰卞搷鐨勮褰曟潯鏁 - */ - default int delete(final Collection entitys) { - if (entitys == null || entitys.isEmpty()) return 0; - return delete(entitys.toArray()); - } - - /** - * 鍒犻櫎鎸囧畾涓婚敭鍊肩殑璁板綍锛 澶氬璞″繀椤绘槸鍚屼竴涓狤ntity绫讳笖蹇呴』鍦ㄥ悓涓寮犺〃涓
- * 绛変环SQL: DELETE FROM {table} WHERE {primary} IN {values.id}
- * - * @param 娉涘瀷 - * @param entitys Entity瀵硅薄 - * - * @return 褰卞搷鐨勮褰曟潯鏁 - */ - default int delete(final Stream entitys) { - if (entitys == null) return 0; - return delete(entitys.toArray()); - } - - /** - * 鍒犻櫎鎸囧畾涓婚敭鍊肩殑璁板綍锛 澶氬璞″繀椤绘槸鍚屼竴涓狤ntity绫讳笖蹇呴』鍦ㄥ悓涓寮犺〃涓
- * 绛変环SQL: DELETE FROM {table} WHERE {primary} IN {values.id}
- * - * @param 娉涘瀷 - * @param entitys Entity瀵硅薄 - * - * @return 褰卞搷鐨勮褰曟潯鏁癈ompletableFuture - */ - public CompletableFuture deleteAsync(final T... entitys); - - /** - * 鍒犻櫎鎸囧畾涓婚敭鍊肩殑璁板綍锛 澶氬璞″繀椤绘槸鍚屼竴涓狤ntity绫讳笖蹇呴』鍦ㄥ悓涓寮犺〃涓
- * 绛変环SQL: DELETE FROM {table} WHERE {primary} IN {values.id}
- * - * @param 娉涘瀷 - * @param entitys Entity瀵硅薄 - * - * @return 褰卞搷鐨勮褰曟潯鏁癈ompletableFuture - */ - default CompletableFuture deleteAsync(final Collection entitys) { - if (entitys == null || entitys.isEmpty()) return CompletableFuture.completedFuture(0); - return deleteAsync(entitys.toArray()); - } - - /** - * 鍒犻櫎鎸囧畾涓婚敭鍊肩殑璁板綍锛 澶氬璞″繀椤绘槸鍚屼竴涓狤ntity绫讳笖蹇呴』鍦ㄥ悓涓寮犺〃涓
- * 绛変环SQL: DELETE FROM {table} WHERE {primary} IN {values.id}
- * - * @param 娉涘瀷 - * @param entitys Entity瀵硅薄 - * - * @return 褰卞搷鐨勮褰曟潯鏁癈ompletableFuture - */ - default CompletableFuture deleteAsync(final Stream entitys) { - if (entitys == null) return CompletableFuture.completedFuture(0); - return deleteAsync(entitys.toArray()); - } - - /** - * 鍒犻櫎鎸囧畾涓婚敭鍊肩殑璁板綍,澶氫富閿煎繀椤诲湪鍚屼竴寮犺〃涓
- * 绛変环SQL: DELETE FROM {table} WHERE {primary} IN {ids}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param pks 涓婚敭鍊 - * - * @return 褰卞搷鐨勮褰曟潯鏁 - */ - public int delete(final Class clazz, final Serializable... pks); - - /** - * 鍒犻櫎鎸囧畾涓婚敭鍊肩殑璁板綍,澶氫富閿煎繀椤诲湪鍚屼竴寮犺〃涓
- * 绛変环SQL: DELETE FROM {table} WHERE {primary} IN {ids}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param pks 涓婚敭鍊 - * - * @return 褰卞搷鐨勮褰曟潯鏁癈ompletableFuture - */ - public CompletableFuture deleteAsync(final Class clazz, final Serializable... pks); - - /** - * 鍒犻櫎绗﹀悎杩囨护鏉′欢鐨勮褰
- * 绛変环SQL: DELETE FROM {table} WHERE {filter node}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param node 杩囨护鏉′欢 - * - * @return 褰卞搷鐨勮褰曟潯鏁 - */ - default int delete(final Class clazz, final FilterNode node) { - return delete(clazz, (Flipper) null, node); - } - - /** - * 鍒犻櫎绗﹀悎杩囨护鏉′欢鐨勮褰
- * 绛変环SQL: DELETE FROM {table} WHERE {filter node}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param node 杩囨护鏉′欢 - * - * @return 褰卞搷鐨勮褰曟潯鏁癈ompletableFuture - */ - default CompletableFuture deleteAsync(final Class clazz, final FilterNode node) { - return deleteAsync(clazz, (Flipper) null, node); - } - - /** - * 鍒犻櫎绗﹀悎杩囨护鏉′欢涓旀寚瀹氭渶澶у奖鍝嶆潯鏁扮殑璁板綍
- * Flipper涓璷ffset瀛楁灏嗚蹇界暐
- * 绛変环SQL: DELETE FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param flipper 缈婚〉瀵硅薄 - * @param node 杩囨护鏉′欢 - * - * @return 褰卞搷鐨勮褰曟潯鏁 - */ - public int delete(final Class clazz, final Flipper flipper, final FilterNode node); - - /** - * 鍒犻櫎绗﹀悎杩囨护鏉′欢涓旀寚瀹氭渶澶у奖鍝嶆潯鏁扮殑璁板綍
- * Flipper涓璷ffset瀛楁灏嗚蹇界暐
- * 绛変环SQL: DELETE FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param flipper 缈婚〉瀵硅薄 - * @param node 杩囨护鏉′欢 - * - * @return 褰卞搷鐨勮褰曟潯鏁癈ompletableFuture - */ - public CompletableFuture deleteAsync(final Class clazz, final Flipper flipper, final FilterNode node); - - //------------------------clearAsync--------------------------- - /** - * 娓呯┖琛
- * 绛変环SQL: TRUNCATE TABLE {table}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * - * @return 褰卞搷鐨勮褰曟潯鏁 -1琛ㄧず琛ㄤ笉瀛樺湪 - */ - default int clearTable(final Class clazz) { - return clearTable(clazz, (FilterNode) null); - } - - /** - * 娓呯┖琛
- * 绛変环SQL: TRUNCATE TABLE {table}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * - * @return 褰卞搷鐨勮褰曟潯鏁癈ompletableFuture -1琛ㄧず琛ㄤ笉瀛樺湪 - */ - default CompletableFuture clearTableAsync(final Class clazz) { - return clearTableAsync(clazz, (FilterNode) null); - } - - /** - * 娓呯┖琛
- * 绛変环SQL: TRUNCATE TABLE {table}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param node 杩囨护鏉′欢 - * - * @return 褰卞搷鐨勮褰曟潯鏁 -1琛ㄧず琛ㄤ笉瀛樺湪 - */ - public int clearTable(final Class clazz, final FilterNode node); - - /** - * 娓呯┖琛
- * 绛変环SQL: TRUNCATE TABLE {table}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param node 杩囨护鏉′欢 - * - * @return 褰卞搷鐨勮褰曟潯鏁癈ompletableFuture -1琛ㄧず琛ㄤ笉瀛樺湪 - */ - public CompletableFuture clearTableAsync(final Class clazz, final FilterNode node); - - //------------------------dropAsync--------------------------- - /** - * 鍒犻櫎琛
- * 绛変环SQL: DROP TABLE {table}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * - * @return 褰卞搷鐨勮褰曟潯鏁 -1琛ㄧず琛ㄤ笉瀛樺湪 - */ - default int dropTable(final Class clazz) { - return dropTable(clazz, (FilterNode) null); - } - - /** - * 鍒犻櫎琛
- * 绛変环SQL: DROP TABLE {table}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * - * @return 褰卞搷鐨勮褰曟潯鏁癈ompletableFuture -1琛ㄧず琛ㄤ笉瀛樺湪 - */ - default CompletableFuture dropTableAsync(final Class clazz) { - return dropTableAsync(clazz, (FilterNode) null); - } - - /** - * 鍒犻櫎琛
- * 绛変环SQL: DROP TABLE {table}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param node 杩囨护鏉′欢 - * - * @return 褰卞搷鐨勮褰曟潯鏁 -1琛ㄧず琛ㄤ笉瀛樺湪 - */ - public int dropTable(final Class clazz, final FilterNode node); - - /** - * 鍒犻櫎琛
- * 绛変环SQL: DROP TABLE {table}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param node 杩囨护鏉′欢 - * - * @return 褰卞搷鐨勮褰曟潯鏁癈ompletableFuture -1琛ㄧず琛ㄤ笉瀛樺湪 - */ - public CompletableFuture dropTableAsync(final Class clazz, final FilterNode node); - - //------------------------updateAsync--------------------------- - /** - * 鏇存柊璁板綍锛 澶氬璞″繀椤绘槸鍚屼竴涓狤ntity绫讳笖蹇呴』鍦ㄥ悓涓寮犺〃涓
- * 绛変环SQL:
- * UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id1}
- * UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id2}
- * ···
- * - * @param 娉涘瀷 - * @param entitys Entity瀵硅薄 - * - * @return 褰卞搷鐨勮褰曟潯鏁 - */ - public int update(final T... entitys); - - /** - * 鏇存柊璁板綍锛 澶氬璞″繀椤绘槸鍚屼竴涓狤ntity绫讳笖蹇呴』鍦ㄥ悓涓寮犺〃涓
- * 绛変环SQL:
- * UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id1}
- * UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id2}
- * ···
- * - * @param 娉涘瀷 - * @param entitys Entity瀵硅薄 - * - * @return 褰卞搷鐨勮褰曟潯鏁 - */ - default int update(final Collection entitys) { - if (entitys == null || entitys.isEmpty()) return 0; - return update(entitys.toArray()); - } - - /** - * 鏇存柊璁板綍锛 澶氬璞″繀椤绘槸鍚屼竴涓狤ntity绫讳笖蹇呴』鍦ㄥ悓涓寮犺〃涓
- * 绛変环SQL:
- * UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id1}
- * UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id2}
- * ···
- * - * @param 娉涘瀷 - * @param entitys Entity瀵硅薄 - * - * @return 褰卞搷鐨勮褰曟潯鏁 - */ - default int update(final Stream entitys) { - if (entitys == null) return 0; - return update(entitys.toArray()); - } - - /** - * 鏇存柊璁板綍锛 澶氬璞″繀椤绘槸鍚屼竴涓狤ntity绫讳笖蹇呴』鍦ㄥ悓涓寮犺〃涓
- * 绛変环SQL:
- * UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id1}
- * UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id2}
- * ···
- * - * @param 娉涘瀷 - * @param entitys Entity瀵硅薄 - * - * @return 褰卞搷鐨勮褰曟潯鏁癈ompletableFuture - */ - public CompletableFuture updateAsync(final T... entitys); - - /** - * 鏇存柊璁板綍锛 澶氬璞″繀椤绘槸鍚屼竴涓狤ntity绫讳笖蹇呴』鍦ㄥ悓涓寮犺〃涓
- * 绛変环SQL:
- * UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id1}
- * UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id2}
- * ···
- * - * @param 娉涘瀷 - * @param entitys Entity瀵硅薄 - * - * @return 褰卞搷鐨勮褰曟潯鏁癈ompletableFuture - */ - default CompletableFuture updateAsync(final Collection entitys) { - if (entitys == null || entitys.isEmpty()) return CompletableFuture.completedFuture(0); - return updateAsync(entitys.toArray()); - } - - /** - * 鏇存柊璁板綍锛 澶氬璞″繀椤绘槸鍚屼竴涓狤ntity绫讳笖蹇呴』鍦ㄥ悓涓寮犺〃涓
- * 绛変环SQL:
- * UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id1}
- * UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id2}
- * ···
- * - * @param 娉涘瀷 - * @param entitys Entity瀵硅薄 - * - * @return 褰卞搷鐨勮褰曟潯鏁癈ompletableFuture - */ - default CompletableFuture updateAsync(final Stream entitys) { - if (entitys == null) return CompletableFuture.completedFuture(0); - return updateAsync(entitys.toArray()); - } - - /** - * 鏇存柊鍗曚釜璁板綍鐨勫崟涓瓧娈
- * 娉ㄦ剰锛氬嵆浣垮瓧娈垫爣璁颁负@Column(updatable=false)涔熶細琚洿鏂
- * 绛変环SQL: UPDATE {table} SET {column} = {value} WHERE {primary} = {id}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param pk 涓婚敭 - * @param column 寰呮洿鏂扮殑瀛楁鍚 - * @param value 鏇存柊鍊 - * - * @return 褰卞搷鐨勮褰曟潯鏁 - */ - public int updateColumn(final Class clazz, final Serializable pk, final String column, final Serializable value); - - /** - * 鏇存柊鍗曚釜璁板綍鐨勫崟涓瓧娈
- * 娉ㄦ剰锛氬嵆浣垮瓧娈垫爣璁颁负@Column(updatable=false)涔熶細琚洿鏂
- * 绛変环SQL: UPDATE {table} SET {column} = {value} WHERE {primary} = {id}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param pk 涓婚敭 - * @param column 寰呮洿鏂扮殑瀛楁鍚 - * @param value 鏇存柊鍊 - * - * @return 褰卞搷鐨勮褰曟潯鏁癈ompletableFuture - */ - public CompletableFuture updateColumnAsync(final Class clazz, final Serializable pk, final String column, final Serializable value); - - /** - * 鏇存柊绗﹀悎杩囨护鏉′欢璁板綍鐨勫崟涓瓧娈
- * 娉ㄦ剰锛氬嵆浣垮瓧娈垫爣璁颁负@Column(updatable=false)涔熶細琚洿鏂
- * 绛変环SQL: UPDATE {table} SET {column} = {value} WHERE {filter node}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param column 寰呮洿鏂扮殑瀛楁鍚 - * @param value 鏇存柊鍊 - * @param node 杩囨护鏉′欢 - * - * @return 褰卞搷鐨勮褰曟潯鏁 - */ - public int updateColumn(final Class clazz, final String column, final Serializable value, final FilterNode node); - - /** - * 鏇存柊绗﹀悎杩囨护鏉′欢璁板綍鐨勫崟涓瓧娈
- * 娉ㄦ剰锛氬嵆浣垮瓧娈垫爣璁颁负@Column(updatable=false)涔熶細琚洿鏂
- * 绛変环SQL: UPDATE {table} SET {column} = {value} WHERE {filter node}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param column 寰呮洿鏂扮殑瀛楁鍚 - * @param value 鏇存柊鍊 - * @param node 杩囨护鏉′欢 - * - * @return 褰卞搷鐨勮褰曟潯鏁癈ompletableFuture - */ - public CompletableFuture updateColumnAsync(final Class clazz, final String column, final Serializable value, final FilterNode node); - - /** - * 鏇存柊鎸囧畾涓婚敭鍊艰褰曠殑閮ㄥ垎瀛楁
- * 瀛楁璧嬪兼搷浣滈夐」瑙 ColumnExpress
- * 绛変环SQL: UPDATE {table} SET {column1} = {value1}, {column2} += {value2}, {column3} *= {value3}, ··· WHERE {filter node}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param pk 涓婚敭 - * @param values 鏇存柊瀛楁 - * - * @return 褰卞搷鐨勮褰曟潯鏁 - */ - public int updateColumn(final Class clazz, final Serializable pk, final ColumnValue... values); - - /** - * 鏇存柊鎸囧畾涓婚敭鍊艰褰曠殑閮ㄥ垎瀛楁
- * 瀛楁璧嬪兼搷浣滈夐」瑙 ColumnExpress
- * 绛変环SQL: UPDATE {table} SET {column1} = {value1}, {column2} += {value2}, {column3} *= {value3}, ··· WHERE {filter node}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param pk 涓婚敭 - * @param values 鏇存柊瀛楁 - * - * @return 褰卞搷鐨勮褰曟潯鏁癈ompletableFuture - */ - public CompletableFuture updateColumnAsync(final Class clazz, final Serializable pk, final ColumnValue... values); - - /** - * 鏇存柊绗﹀悎杩囨护鏉′欢璁板綍鐨勯儴鍒嗗瓧娈
- * 瀛楁璧嬪兼搷浣滈夐」瑙 ColumnExpress
- * 娉ㄦ剰锛欵ntity绫讳腑鏍囪涓@Column(updatable=false)涓嶄細琚洿鏂
- * 绛変环SQL: UPDATE {table} SET {column1} = {value1}, {column2} += {value2}, {column3} *= {value3}, ··· WHERE {filter node}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param node 杩囨护鏉′欢 - * @param values 鏇存柊瀛楁 - * - * @return 褰卞搷鐨勮褰曟潯鏁 - */ - default int updateColumn(final Class clazz, final FilterNode node, final ColumnValue... values) { - return updateColumn(clazz, node, (Flipper) null, values); - } - - /** - * 鏇存柊绗﹀悎杩囨护鏉′欢璁板綍鐨勯儴鍒嗗瓧娈
- * 瀛楁璧嬪兼搷浣滈夐」瑙 ColumnExpress
- * 娉ㄦ剰锛欵ntity绫讳腑鏍囪涓@Column(updatable=false)涓嶄細琚洿鏂
- * 绛変环SQL: UPDATE {table} SET {column1} = {value1}, {column2} += {value2}, {column3} *= {value3}, ··· WHERE {filter node}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param node 杩囨护鏉′欢 - * @param values 鏇存柊瀛楁 - * - * @return 褰卞搷鐨勮褰曟潯鏁癈ompletableFuture - */ - default CompletableFuture updateColumnAsync(final Class clazz, final FilterNode node, final ColumnValue... values) { - return updateColumnAsync(clazz, node, (Flipper) null, values); - } - - /** - * 鏇存柊绗﹀悎杩囨护鏉′欢鐨勮褰曠殑鎸囧畾瀛楁
- * Flipper涓璷ffset瀛楁灏嗚蹇界暐
- * 娉ㄦ剰锛欵ntity绫讳腑鏍囪涓@Column(updatable=false)涓嶄細琚洿鏂
- * 绛変环SQL: UPDATE {table} SET {column1} = {value1}, {column2} += {value2}, {column3} *= {value3}, ··· WHERE {filter node} ORDER BY {flipper.sort}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param node 杩囨护鏉′欢 - * @param flipper 缈婚〉瀵硅薄 - * @param values 鏇存柊瀛楁 - * - * @return 褰卞搷鐨勮褰曟潯鏁 - */ - public int updateColumn(final Class clazz, final FilterNode node, final Flipper flipper, final ColumnValue... values); - - /** - * 鏇存柊绗﹀悎杩囨护鏉′欢鐨勮褰曠殑鎸囧畾瀛楁
- * Flipper涓璷ffset瀛楁灏嗚蹇界暐
- * 娉ㄦ剰锛欵ntity绫讳腑鏍囪涓@Column(updatable=false)涓嶄細琚洿鏂
- * 绛変环SQL: UPDATE {table} SET {column1} = {value1}, {column2} += {value2}, {column3} *= {value3}, ··· WHERE {filter node} ORDER BY {flipper.sort}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param node 杩囨护鏉′欢 - * @param flipper 缈婚〉瀵硅薄 - * @param values 鏇存柊瀛楁 - * - * @return 褰卞搷鐨勮褰曟潯鏁癈ompletableFuture - */ - public CompletableFuture updateColumnAsync(final Class clazz, final FilterNode node, final Flipper flipper, final ColumnValue... values); - - /** - * 鏇存柊鍗曚釜璁板綍鐨勬寚瀹氬瓧娈
- * 娉ㄦ剰锛欵ntity绫讳腑鏍囪涓@Column(updatable=false)涓嶄細琚洿鏂
- * 绛変环SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· WHERE {primary} = {bean.id}
- * - * @param Entity娉涘瀷 - * @param entity 寰呮洿鏂扮殑Entity瀵硅薄 - * @param columns 闇鏇存柊鐨勫瓧娈靛悕 - * - * @return 褰卞搷鐨勮褰曟潯鏁 - */ - default int updateColumn(final T entity, final String... columns) { - return updateColumn(entity, (FilterNode) null, columns); - } - - /** - * 鏇存柊鍗曚釜璁板綍鐨勬寚瀹氬瓧娈
- * 娉ㄦ剰锛欵ntity绫讳腑鏍囪涓@Column(updatable=false)涓嶄細琚洿鏂
- * 绛変环SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· WHERE {primary} = {bean.id}
- * - * @param Entity娉涘瀷 - * @param entity 寰呮洿鏂扮殑Entity瀵硅薄 - * @param columns 闇鏇存柊鐨勫瓧娈靛悕 - * - * @return 褰卞搷鐨勮褰曟潯鏁癈ompletableFuture - */ - default CompletableFuture updateColumnAsync(final T entity, final String... columns) { - return updateColumnAsync(entity, (FilterNode) null, columns); - } - - /** - * 鏇存柊绗﹀悎杩囨护鏉′欢璁板綍鐨勬寚瀹氬瓧娈
- * 娉ㄦ剰锛欵ntity绫讳腑鏍囪涓@Column(updatable=false)涓嶄細琚洿鏂
- * 绛変环SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· WHERE {filter node}
- * - * @param Entity娉涘瀷 - * @param entity 寰呮洿鏂扮殑Entity瀵硅薄 - * @param node 杩囨护鏉′欢 - * @param columns 闇鏇存柊鐨勫瓧娈靛悕 - * - * @return 褰卞搷鐨勮褰曟潯鏁 - */ - public int updateColumn(final T entity, final FilterNode node, final String... columns); - - /** - * 鏇存柊绗﹀悎杩囨护鏉′欢璁板綍鐨勬寚瀹氬瓧娈
- * 娉ㄦ剰锛欵ntity绫讳腑鏍囪涓@Column(updatable=false)涓嶄細琚洿鏂
- * 绛変环SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· WHERE {filter node}
- * - * @param Entity娉涘瀷 - * @param entity 寰呮洿鏂扮殑Entity瀵硅薄 - * @param node 杩囨护鏉′欢 - * @param columns 闇鏇存柊鐨勫瓧娈靛悕 - * - * @return 褰卞搷鐨勮褰曟潯鏁癈ompletableFuture - */ - public CompletableFuture updateColumnAsync(final T entity, final FilterNode node, final String... columns); - - /** - * 鏇存柊鍗曚釜璁板綍鐨勬寚瀹氬瓧娈
- * 娉ㄦ剰锛欵ntity绫讳腑鏍囪涓@Column(updatable=false)涓嶄細琚洿鏂
- * 绛変环SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· WHERE {primary} = {bean.id}
- * - * @param Entity娉涘瀷 - * @param entity 寰呮洿鏂扮殑Entity瀵硅薄 - * @param selects 鎸囧畾瀛楁 - * - * @return 褰卞搷鐨勮褰曟潯鏁 - */ - default int updateColumn(final T entity, final SelectColumn selects) { - return updateColumn(entity, (FilterNode) null, selects); - } - - /** - * 鏇存柊鍗曚釜璁板綍鐨勬寚瀹氬瓧娈
- * 娉ㄦ剰锛欵ntity绫讳腑鏍囪涓@Column(updatable=false)涓嶄細琚洿鏂
- * 绛変环SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· WHERE {primary} = {bean.id}
- * - * @param Entity娉涘瀷 - * @param entity 寰呮洿鏂扮殑Entity瀵硅薄 - * @param selects 鎸囧畾瀛楁 - * - * @return 褰卞搷鐨勮褰曟潯鏁癈ompletableFuture - */ - default CompletableFuture updateColumnAsync(final T entity, final SelectColumn selects) { - return updateColumnAsync(entity, (FilterNode) null, selects); - } - - /** - * 鏇存柊绗﹀悎杩囨护鏉′欢璁板綍鐨勬寚瀹氬瓧娈
- * 娉ㄦ剰锛欵ntity绫讳腑鏍囪涓@Column(updatable=false)涓嶄細琚洿鏂
- * 绛変环SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· WHERE {filter node}
- * - * @param Entity娉涘瀷 - * @param entity 寰呮洿鏂扮殑Entity瀵硅薄 - * @param node 杩囨护鏉′欢 - * @param selects 鎸囧畾瀛楁 - * - * @return 褰卞搷鐨勮褰曟潯鏁 - */ - public int updateColumn(final T entity, final FilterNode node, final SelectColumn selects); - - /** - * 鏇存柊绗﹀悎杩囨护鏉′欢璁板綍鐨勬寚瀹氬瓧娈
- * 娉ㄦ剰锛欵ntity绫讳腑鏍囪涓@Column(updatable=false)涓嶄細琚洿鏂
- * 绛変环SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· WHERE {filter node}
- * - * @param Entity娉涘瀷 - * @param entity 寰呮洿鏂扮殑Entity瀵硅薄 - * @param node 杩囨护鏉′欢 - * @param selects 鎸囧畾瀛楁 - * - * @return 褰卞搷鐨勮褰曟潯鏁癈ompletableFuture - */ - public CompletableFuture updateColumnAsync(final T entity, final FilterNode node, final SelectColumn selects); - - //############################################# 鏌ヨ鎺ュ彛 ############################################# - //-----------------------getXXXXResult----------------------------- - /** - * 鑾峰彇绗﹀悎杩囨护鏉′欢璁板綍鐨勮仛鍚堢粨鏋, 鏃犵粨鏋滆繑鍥瀗ull
- * 绛変环SQL: SELECT FUNC{column} FROM {table}
- * 濡 getNumberResultAsync(User.class, FilterFunc.COUNT, null) 绛変环浜: SELECT COUNT(*) FROM {table}
- * - * @param entityClass Entity绫 - * @param func 鑱氬悎鍑芥暟 - * @param column 鎸囧畾瀛楁 - * - * @return 鑱氬悎缁撴灉 - */ - default Number getNumberResult(final Class entityClass, final FilterFunc func, final String column) { - return getNumberResult(entityClass, func, null, column, (FilterNode) null); - } - - /** - * 鑾峰彇绗﹀悎杩囨护鏉′欢璁板綍鐨勮仛鍚堢粨鏋, 鏃犵粨鏋滆繑鍥瀗ull
- * 绛変环SQL: SELECT FUNC{column} FROM {table}
- * 濡 getNumberResultAsync(User.class, FilterFunc.COUNT, null) 绛変环浜: SELECT COUNT(*) FROM {table}
- * - * @param entityClass Entity绫 - * @param func 鑱氬悎鍑芥暟 - * @param column 鎸囧畾瀛楁 - * - * @return 鑱氬悎缁撴灉CompletableFuture - */ - default CompletableFuture getNumberResultAsync(final Class entityClass, final FilterFunc func, final String column) { - return getNumberResultAsync(entityClass, func, null, column, (FilterNode) null); - } - - /** - * 鑾峰彇绗﹀悎杩囨护鏉′欢璁板綍鐨勮仛鍚堢粨鏋, 鏃犵粨鏋滆繑鍥瀗ull
- * 绛変环SQL: SELECT FUNC{column} FROM {table} WHERE {filter bean}
- * 濡 getNumberResultAsync(User.class, FilterFunc.COUNT, null, (FilterBean)null) 绛変环浜: SELECT COUNT(*) FROM {table}
- * - * @param entityClass Entity绫 - * @param func 鑱氬悎鍑芥暟 - * @param column 鎸囧畾瀛楁 - * @param bean 杩囨护鏉′欢 - * - * @return 鑱氬悎缁撴灉 - */ - default Number getNumberResult(final Class entityClass, final FilterFunc func, final String column, final FilterBean bean) { - return getNumberResult(entityClass, func, column, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鑾峰彇绗﹀悎杩囨护鏉′欢璁板綍鐨勮仛鍚堢粨鏋, 鏃犵粨鏋滆繑鍥瀗ull
- * 绛変环SQL: SELECT FUNC{column} FROM {table} WHERE {filter bean}
- * 濡 getNumberResultAsync(User.class, FilterFunc.COUNT, null, (FilterBean)null) 绛変环浜: SELECT COUNT(*) FROM {table}
- * - * @param entityClass Entity绫 - * @param func 鑱氬悎鍑芥暟 - * @param column 鎸囧畾瀛楁 - * @param bean 杩囨护鏉′欢 - * - * @return 鑱氬悎缁撴灉CompletableFuture - */ - default CompletableFuture getNumberResultAsync(final Class entityClass, final FilterFunc func, final String column, final FilterBean bean) { - return getNumberResultAsync(entityClass, func, column, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鑾峰彇绗﹀悎杩囨护鏉′欢璁板綍鐨勮仛鍚堢粨鏋, 鏃犵粨鏋滆繑鍥瀗ull
- * 绛変环SQL: SELECT FUNC{column} FROM {table} WHERE {filter node}
- * 濡 getNumberResultAsync(User.class, FilterFunc.MAX, "createtime", (FilterNode)null) 绛変环浜: SELECT MAX(createtime) FROM {table}
- * - * @param entityClass Entity绫 - * @param func 鑱氬悎鍑芥暟 - * @param column 鎸囧畾瀛楁 - * @param node 杩囨护鏉′欢 - * - * @return 鑱氬悎缁撴灉 - */ - default Number getNumberResult(final Class entityClass, final FilterFunc func, final String column, final FilterNode node) { - return getNumberResult(entityClass, func, null, column, node); - } - - /** - * 鑾峰彇绗﹀悎杩囨护鏉′欢璁板綍鐨勮仛鍚堢粨鏋, 鏃犵粨鏋滆繑鍥瀗ull
- * 绛変环SQL: SELECT FUNC{column} FROM {table} WHERE {filter node}
- * 濡 getNumberResultAsync(User.class, FilterFunc.MAX, "createtime", (FilterNode)null) 绛変环浜: SELECT MAX(createtime) FROM {table}
- * - * @param entityClass Entity绫 - * @param func 鑱氬悎鍑芥暟 - * @param column 鎸囧畾瀛楁 - * @param node 杩囨护鏉′欢 - * - * @return 鑱氬悎缁撴灉 - */ - default CompletableFuture getNumberResultAsync(final Class entityClass, final FilterFunc func, final String column, final FilterNode node) { - return getNumberResultAsync(entityClass, func, null, column, node); - } - - /** - * 鑾峰彇绗﹀悎杩囨护鏉′欢璁板綍鐨勮仛鍚堢粨鏋, 鏃犵粨鏋滆繑鍥為粯璁ゅ
- * 绛変环SQL: SELECT FUNC{column} FROM {table}
- * 濡 getNumberResultAsync(User.class, FilterFunc.MAX, "createtime") 绛変环浜: SELECT MAX(createtime) FROM {table}
- * - * @param entityClass Entity绫 - * @param func 鑱氬悎鍑芥暟 - * @param defVal 榛樿鍊 - * @param column 鎸囧畾瀛楁 - * - * @return 鑱氬悎缁撴灉 - */ - default Number getNumberResult(final Class entityClass, final FilterFunc func, final Number defVal, final String column) { - return getNumberResult(entityClass, func, defVal, column, (FilterNode) null); - } - - /** - * 鑾峰彇绗﹀悎杩囨护鏉′欢璁板綍鐨勮仛鍚堢粨鏋, 鏃犵粨鏋滆繑鍥為粯璁ゅ
- * 绛変环SQL: SELECT FUNC{column} FROM {table}
- * 濡 getNumberResultAsync(User.class, FilterFunc.MAX, "createtime") 绛変环浜: SELECT MAX(createtime) FROM {table}
- * - * @param entityClass Entity绫 - * @param func 鑱氬悎鍑芥暟 - * @param defVal 榛樿鍊 - * @param column 鎸囧畾瀛楁 - * - * @return 鑱氬悎缁撴灉CompletableFuture - */ - default CompletableFuture getNumberResultAsync(final Class entityClass, final FilterFunc func, final Number defVal, final String column) { - return getNumberResultAsync(entityClass, func, defVal, column, (FilterNode) null); - } - - /** - * 鑾峰彇绗﹀悎杩囨护鏉′欢璁板綍鐨勮仛鍚堢粨鏋, 鏃犵粨鏋滆繑鍥為粯璁ゅ
- * 绛変环SQL: SELECT FUNC{column} FROM {table} WHERE {filter bean}
- * 濡 getNumberResultAsync(User.class, FilterFunc.MAX, "createtime", (FilterNode)null) 绛変环浜: SELECT MAX(createtime) FROM {table}
- * - * @param entityClass Entity绫 - * @param func 鑱氬悎鍑芥暟 - * @param defVal 榛樿鍊 - * @param column 鎸囧畾瀛楁 - * @param bean 杩囨护鏉′欢 - * - * @return 鑱氬悎缁撴灉 - */ - default Number getNumberResult(final Class entityClass, final FilterFunc func, final Number defVal, final String column, final FilterBean bean) { - return getNumberResult(entityClass, func, defVal, column, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鑾峰彇绗﹀悎杩囨护鏉′欢璁板綍鐨勮仛鍚堢粨鏋, 鏃犵粨鏋滆繑鍥為粯璁ゅ
- * 绛変环SQL: SELECT FUNC{column} FROM {table} WHERE {filter bean}
- * 濡 getNumberResultAsync(User.class, FilterFunc.MAX, "createtime", (FilterNode)null) 绛変环浜: SELECT MAX(createtime) FROM {table}
- * - * @param entityClass Entity绫 - * @param func 鑱氬悎鍑芥暟 - * @param defVal 榛樿鍊 - * @param column 鎸囧畾瀛楁 - * @param bean 杩囨护鏉′欢 - * - * @return 鑱氬悎缁撴灉CompletableFuture - */ - default CompletableFuture getNumberResultAsync(final Class entityClass, final FilterFunc func, final Number defVal, final String column, final FilterBean bean) { - return getNumberResultAsync(entityClass, func, defVal, column, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鑾峰彇绗﹀悎杩囨护鏉′欢璁板綍鐨勮仛鍚堢粨鏋, 鏃犵粨鏋滆繑鍥為粯璁ゅ
- * 绛変环SQL: SELECT FUNC{column} FROM {table} WHERE {filter node}
- * 濡 getNumberResultAsync(User.class, FilterFunc.MAX, "createtime", (FilterNode)null) 绛変环浜: SELECT MAX(createtime) FROM {table}
- * - * @param entityClass Entity绫 - * @param func 鑱氬悎鍑芥暟 - * @param defVal 榛樿鍊 - * @param column 鎸囧畾瀛楁 - * @param node 杩囨护鏉′欢 - * - * @return 鑱氬悎缁撴灉 - */ - public Number getNumberResult(final Class entityClass, final FilterFunc func, final Number defVal, final String column, final FilterNode node); - - /** - * 鑾峰彇绗﹀悎杩囨护鏉′欢璁板綍鐨勮仛鍚堢粨鏋, 鏃犵粨鏋滆繑鍥為粯璁ゅ
- * 绛変环SQL: SELECT FUNC{column} FROM {table} WHERE {filter node}
- * 濡 getNumberResultAsync(User.class, FilterFunc.MAX, "createtime", (FilterNode)null) 绛変环浜: SELECT MAX(createtime) FROM {table}
- * - * @param entityClass Entity绫 - * @param func 鑱氬悎鍑芥暟 - * @param defVal 榛樿鍊 - * @param column 鎸囧畾瀛楁 - * @param node 杩囨护鏉′欢 - * - * @return 鑱氬悎缁撴灉CompletableFuture - */ - public CompletableFuture getNumberResultAsync(final Class entityClass, final FilterFunc func, final Number defVal, final String column, final FilterNode node); - - /** - * 鑾峰彇绗﹀悎杩囨护鏉′欢璁板綍鐨勮仛鍚堢粨鏋淢ap
- * 绛変环SQL: SELECT FUNC1{column1}, FUNC2{column2}, ··· FROM {table}
- * 濡 getNumberMapAsync(User.class, new FilterFuncColumn(FilterFunc.MAX, "createtime")) 绛変环浜: SELECT MAX(createtime) FROM {table}
- * - * @param Number - * @param entityClass Entity绫 - * @param columns 鑱氬悎瀛楁 - * - * @return 鑱氬悎缁撴灉Map - */ - default Map getNumberMap(final Class entityClass, final FilterFuncColumn... columns) { - return getNumberMap(entityClass, (FilterNode) null, columns); - } - - /** - * 鑾峰彇绗﹀悎杩囨护鏉′欢璁板綍鐨勮仛鍚堢粨鏋淢ap
- * 绛変环SQL: SELECT FUNC1{column1}, FUNC2{column2}, ··· FROM {table}
- * 濡 getNumberMapAsync(User.class, new FilterFuncColumn(FilterFunc.MAX, "createtime")) 绛変环浜: SELECT MAX(createtime) FROM {table}
- * - * @param Number - * @param entityClass Entity绫 - * @param columns 鑱氬悎瀛楁 - * - * @return 鑱氬悎缁撴灉Map CompletableFuture - */ - default CompletableFuture> getNumberMapAsync(final Class entityClass, final FilterFuncColumn... columns) { - return getNumberMapAsync(entityClass, (FilterNode) null, columns); - } - - /** - * 鑾峰彇绗﹀悎杩囨护鏉′欢璁板綍鐨勮仛鍚堢粨鏋淢ap
- * 绛変环SQL: SELECT FUNC1{column1}, FUNC2{column2}, ··· FROM {table} WHERE {filter bean}
- * 濡 getNumberMapAsync(User.class, (FilterBean)null, new FilterFuncColumn(FilterFunc.MAX, "createtime")) 绛変环浜: SELECT MAX(createtime) FROM {table}
- * - * @param Number - * @param entityClass Entity绫 - * @param bean 杩囨护鏉′欢 - * @param columns 鑱氬悎瀛楁 - * - * @return 鑱氬悎缁撴灉Map - */ - default Map getNumberMap(final Class entityClass, final FilterBean bean, final FilterFuncColumn... columns) { - return getNumberMap(entityClass, FilterNodeBean.createFilterNode(bean), columns); - } - - /** - * 鑾峰彇绗﹀悎杩囨护鏉′欢璁板綍鐨勮仛鍚堢粨鏋淢ap
- * 绛変环SQL: SELECT FUNC1{column1}, FUNC2{column2}, ··· FROM {table} WHERE {filter bean}
- * 濡 getNumberMapAsync(User.class, (FilterBean)null, new FilterFuncColumn(FilterFunc.MAX, "createtime")) 绛変环浜: SELECT MAX(createtime) FROM {table}
- * - * @param Number - * @param entityClass Entity绫 - * @param bean 杩囨护鏉′欢 - * @param columns 鑱氬悎瀛楁 - * - * @return 鑱氬悎缁撴灉Map CompletableFuture - */ - default CompletableFuture> getNumberMapAsync(final Class entityClass, final FilterBean bean, final FilterFuncColumn... columns) { - return getNumberMapAsync(entityClass, FilterNodeBean.createFilterNode(bean), columns); - } - - /** - * 鑾峰彇绗﹀悎杩囨护鏉′欢璁板綍鐨勮仛鍚堢粨鏋淢ap
- * 绛変环SQL: SELECT FUNC1{column1}, FUNC2{column2}, ··· FROM {table} WHERE {filter node}
- * 濡 getNumberMapAsync(User.class, (FilterNode)null, new FilterFuncColumn(FilterFunc.MAX, "createtime")) 绛変环浜: SELECT MAX(createtime) FROM {table}
- * - * @param Number - * @param entityClass Entity绫 - * @param node 杩囨护鏉′欢 - * @param columns 鑱氬悎瀛楁 - * - * @return 鑱氬悎缁撴灉Map - */ - public Map getNumberMap(final Class entityClass, final FilterNode node, final FilterFuncColumn... columns); - - /** - * 鑾峰彇绗﹀悎杩囨护鏉′欢璁板綍鐨勮仛鍚堢粨鏋淢ap
- * 绛変环SQL: SELECT FUNC1{column1}, FUNC2{column2}, ··· FROM {table} WHERE {filter node}
- * 濡 getNumberMapAsync(User.class, (FilterNode)null, new FilterFuncColumn(FilterFunc.MAX, "createtime")) 绛変环浜: SELECT MAX(createtime) FROM {table}
- * - * @param Number - * @param entityClass Entity绫 - * @param node 杩囨护鏉′欢 - * @param columns 鑱氬悎瀛楁 - * - * @return 鑱氬悎缁撴灉Map - */ - public CompletableFuture> getNumberMapAsync(final Class entityClass, final FilterNode node, final FilterFuncColumn... columns); - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凣ROUP BY鑱氬悎缁撴灉Map
- * 绛変环SQL: SELECT keyColumn, FUNC{funcColumn} FROM {table} GROUP BY {keyColumn}
- * 濡 queryColumnMapAsync(User.class, "name", FilterFunc.MAX, "createtime") 绛変环浜: SELECT name, MAX(createtime) FROM user GROUP BY name
- * - * @param Entity娉涘瀷 - * @param Key瀛楁鐨勬暟鎹被鍨 - * @param Number - * @param entityClass Entity绫 - * @param keyColumn Key瀛楁 - * @param func 鑱氬悎鍑芥暟 - * @param funcColumn 鑱氬悎瀛楁 - * - * @return 鑱氬悎缁撴灉Map - */ - default Map queryColumnMap(final Class entityClass, final String keyColumn, final FilterFunc func, final String funcColumn) { - return queryColumnMap(entityClass, keyColumn, func, funcColumn, (FilterNode) null); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凣ROUP BY鑱氬悎缁撴灉Map
- * 绛変环SQL: SELECT keyColumn, FUNC{funcColumn} FROM {table} GROUP BY {keyColumn}
- * 濡 queryColumnMapAsync(User.class, "name", FilterFunc.MAX, "createtime") 绛変环浜: SELECT name, MAX(createtime) FROM user GROUP BY name
- * - * @param Entity娉涘瀷 - * @param Key瀛楁鐨勬暟鎹被鍨 - * @param Number - * @param entityClass Entity绫 - * @param keyColumn Key瀛楁 - * @param func 鑱氬悎鍑芥暟 - * @param funcColumn 鑱氬悎瀛楁 - * - * @return 鑱氬悎缁撴灉Map CompletableFuture - */ - default CompletableFuture> queryColumnMapAsync(final Class entityClass, final String keyColumn, final FilterFunc func, final String funcColumn) { - return queryColumnMapAsync(entityClass, keyColumn, func, funcColumn, (FilterNode) null); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凣ROUP BY鑱氬悎缁撴灉Map
- * 绛変环SQL: SELECT keyColumn, FUNC{funcColumn} FROM {table} WHERE {filter bean} GROUP BY {keyColumn}
- * 濡 queryColumnMapAsync(User.class, "name", FilterFunc.MAX, "createtime", (FilterBean)null) 绛変环浜: SELECT name, MAX(createtime) FROM user GROUP BY name
- * - * @param Entity娉涘瀷 - * @param Key瀛楁鐨勬暟鎹被鍨 - * @param Number - * @param entityClass Entity绫 - * @param keyColumn Key瀛楁 - * @param func 鑱氬悎鍑芥暟 - * @param funcColumn 鑱氬悎瀛楁 - * @param bean 杩囨护鏉′欢 - * - * @return 鑱氬悎缁撴灉Map - */ - default Map queryColumnMap(final Class entityClass, final String keyColumn, final FilterFunc func, final String funcColumn, final FilterBean bean) { - return queryColumnMap(entityClass, keyColumn, func, funcColumn, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凣ROUP BY鑱氬悎缁撴灉Map
- * 绛変环SQL: SELECT keyColumn, FUNC{funcColumn} FROM {table} WHERE {filter bean} GROUP BY {keyColumn}
- * 濡 queryColumnMapAsync(User.class, "name", FilterFunc.MAX, "createtime", (FilterBean)null) 绛変环浜: SELECT name, MAX(createtime) FROM user GROUP BY name
- * - * @param Entity娉涘瀷 - * @param Key瀛楁鐨勬暟鎹被鍨 - * @param Number - * @param entityClass Entity绫 - * @param keyColumn Key瀛楁 - * @param func 鑱氬悎鍑芥暟 - * @param funcColumn 鑱氬悎瀛楁 - * @param bean 杩囨护鏉′欢 - * - * @return 鑱氬悎缁撴灉Map CompletableFuture - */ - default CompletableFuture> queryColumnMapAsync(final Class entityClass, final String keyColumn, final FilterFunc func, final String funcColumn, final FilterBean bean) { - return queryColumnMapAsync(entityClass, keyColumn, func, funcColumn, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凣ROUP BY鑱氬悎缁撴灉Map
- * 绛変环SQL: SELECT keyColumn, FUNC{funcColumn} FROM {table} WHERE {filter node} GROUP BY {keyColumn}
- * 濡 queryColumnMapAsync(User.class, "name", FilterFunc.MAX, "createtime", (FilterNode)null) 绛変环浜: SELECT name, MAX(createtime) FROM user GROUP BY name
- * - * @param Entity娉涘瀷 - * @param Key瀛楁鐨勬暟鎹被鍨 - * @param Number - * @param entityClass Entity绫 - * @param keyColumn Key瀛楁 - * @param func 鑱氬悎鍑芥暟 - * @param funcColumn 鑱氬悎瀛楁 - * @param node 杩囨护鏉′欢 - * - * @return 鑱氬悎缁撴灉Map - */ - public Map queryColumnMap(final Class entityClass, final String keyColumn, final FilterFunc func, final String funcColumn, final FilterNode node); - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凣ROUP BY鑱氬悎缁撴灉Map
- * 绛変环SQL: SELECT keyColumn, FUNC{funcColumn} FROM {table} WHERE {filter node} GROUP BY {keyColumn}
- * 濡 queryColumnMapAsync(User.class, "name", FilterFunc.MAX, "createtime", (FilterNode)null) 绛変环浜: SELECT name, MAX(createtime) FROM user GROUP BY name
- * - * @param Entity娉涘瀷 - * @param Key瀛楁鐨勬暟鎹被鍨 - * @param Number - * @param entityClass Entity绫 - * @param keyColumn Key瀛楁 - * @param func 鑱氬悎鍑芥暟 - * @param funcColumn 鑱氬悎瀛楁 - * @param node 杩囨护鏉′欢 - * - * @return 鑱氬悎缁撴灉Map CompletableFuture - */ - public CompletableFuture> queryColumnMapAsync(final Class entityClass, final String keyColumn, final FilterFunc func, final String funcColumn, final FilterNode node); - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凣ROUP BY鑱氬悎缁撴灉Map
- * 绛変环SQL: SELECT col1, FUNC{funcColumn1}, FUNC{funcColumn2} FROM {table} WHERE GROUP BY {col1}
- * 濡 queryColumnMapAsync(OrderRecord.class, Utility.ofArray(ColumnNodeValue.div(ColumnFuncNode.sum("money"), 100), ColumnFuncNode.avg(ColumnNodeValue.dec("money", 20)))), "targetid") - * 绛変环浜: SELECT targetid, SUM(money) / 100, AVG(money - 20) FROM orderrecord GROUP BY targetid
- * - * @param Entity娉涘瀷 - * @param Key瀛楁鐨勬暟鎹被鍨 - * @param Number - * @param entityClass Entity绫 - * @param funcNodes ColumnNode[] - * @param groupByColumn GROUP BY瀛楁 - * - * @return 鑱氬悎缁撴灉Map CompletableFuture - */ - default Map queryColumnMap(final Class entityClass, final ColumnNode[] funcNodes, final String groupByColumn) { - return queryColumnMap(entityClass, funcNodes, groupByColumn, (FilterNode) null); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凣ROUP BY鑱氬悎缁撴灉Map
- * 绛変环SQL: SELECT col1, FUNC{funcColumn1}, FUNC{funcColumn2} FROM {table} GROUP BY {col1}
- * 濡 queryColumnMapAsync(OrderRecord.class, Utility.ofArray(ColumnNodeValue.div(ColumnFuncNode.sum("money"), 100), ColumnFuncNode.avg(ColumnNodeValue.dec("money", 20)))), "targetid") - * 绛変环浜: SELECT targetid, SUM(money) / 100, AVG(money - 20) FROM orderrecord GROUP BY targetid
- * - * @param Entity娉涘瀷 - * @param Key瀛楁鐨勬暟鎹被鍨 - * @param Number - * @param entityClass Entity绫 - * @param funcNodes ColumnNode[] - * @param groupByColumn GROUP BY瀛楁 - * - * @return 鑱氬悎缁撴灉Map CompletableFuture - */ - default CompletableFuture> queryColumnMapAsync(final Class entityClass, final ColumnNode[] funcNodes, final String groupByColumn) { - return queryColumnMapAsync(entityClass, funcNodes, groupByColumn, (FilterNode) null); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凣ROUP BY鑱氬悎缁撴灉Map
- * 绛変环SQL: SELECT col1, FUNC{funcColumn1}, FUNC{funcColumn2} FROM {table} WHERE {filter bean} GROUP BY {col1}
- * 濡 queryColumnMapAsync(OrderRecord.class, Utility.ofArray(ColumnNodeValue.div(ColumnFuncNode.sum("money"), 100), ColumnFuncNode.avg(ColumnNodeValue.dec("money", 20)))), "targetid", (FilterBean)null) - * 绛変环浜: SELECT targetid, SUM(money) / 100, AVG(money - 20) FROM orderrecord GROUP BY targetid
- * - * @param Entity娉涘瀷 - * @param Key瀛楁鐨勬暟鎹被鍨 - * @param Number - * @param entityClass Entity绫 - * @param funcNodes ColumnNode[] - * @param groupByColumn GROUP BY瀛楁 - * @param bean 杩囨护鏉′欢 - * - * @return 鑱氬悎缁撴灉Map CompletableFuture - */ - default Map queryColumnMap(final Class entityClass, final ColumnNode[] funcNodes, final String groupByColumn, final FilterBean bean) { - return queryColumnMap(entityClass, funcNodes, groupByColumn, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凣ROUP BY鑱氬悎缁撴灉Map
- * 绛変环SQL: SELECT col1, FUNC{funcColumn1}, FUNC{funcColumn2} FROM {table} WHERE {filter bean} GROUP BY {col1}
- * 濡 queryColumnMapAsync(OrderRecord.class, Utility.ofArray(ColumnNodeValue.div(ColumnFuncNode.sum("money"), 100), ColumnFuncNode.avg(ColumnNodeValue.dec("money", 20)))), "targetid", (FilterBean)null) - * 绛変环浜: SELECT targetid, SUM(money) / 100, AVG(money - 20) FROM orderrecord GROUP BY targetid
- * - * @param Entity娉涘瀷 - * @param Key瀛楁鐨勬暟鎹被鍨 - * @param Number - * @param entityClass Entity绫 - * @param funcNodes ColumnNode[] - * @param groupByColumn GROUP BY瀛楁 - * @param bean 杩囨护鏉′欢 - * - * @return 鑱氬悎缁撴灉Map CompletableFuture - */ - default CompletableFuture> queryColumnMapAsync(final Class entityClass, final ColumnNode[] funcNodes, final String groupByColumn, final FilterBean bean) { - return queryColumnMapAsync(entityClass, funcNodes, groupByColumn, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凣ROUP BY鑱氬悎缁撴灉Map
- * 绛変环SQL: SELECT col1, FUNC{funcColumn1}, FUNC{funcColumn2} FROM {table} WHERE {filter node} GROUP BY {col1}
- * 濡 queryColumnMapAsync(OrderRecord.class, Utility.ofArray(ColumnNodeValue.div(ColumnFuncNode.sum("money"), 100), ColumnFuncNode.avg(ColumnNodeValue.dec("money", 20)))), "targetid", (FilterNode)null) - * 绛変环浜: SELECT targetid, SUM(money) / 100, AVG(money - 20) FROM orderrecord GROUP BY targetid
- * - * @param Entity娉涘瀷 - * @param Key瀛楁鐨勬暟鎹被鍨 - * @param Number - * @param entityClass Entity绫 - * @param funcNodes ColumnNode[] - * @param groupByColumn GROUP BY瀛楁 - * @param node 杩囨护鏉′欢 - * - * @return 鑱氬悎缁撴灉Map CompletableFuture - */ - public Map queryColumnMap(final Class entityClass, final ColumnNode[] funcNodes, final String groupByColumn, final FilterNode node); - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凣ROUP BY鑱氬悎缁撴灉Map
- * 绛変环SQL: SELECT col1, FUNC{funcColumn1}, FUNC{funcColumn2} FROM {table} WHERE {filter node} GROUP BY {col1}
- * 濡 queryColumnMapAsync(OrderRecord.class, Utility.ofArray(ColumnNodeValue.div(ColumnFuncNode.sum("money"), 100), ColumnFuncNode.avg(ColumnNodeValue.dec("money", 20)))), "targetid", (FilterNode)null) - * 绛変环浜: SELECT targetid, SUM(money) / 100, AVG(money - 20) FROM orderrecord GROUP BY targetid
- * - * @param Entity娉涘瀷 - * @param Key瀛楁鐨勬暟鎹被鍨 - * @param Number - * @param entityClass Entity绫 - * @param funcNodes ColumnNode[] - * @param groupByColumn GROUP BY瀛楁 - * @param node 杩囨护鏉′欢 - * - * @return 鑱氬悎缁撴灉Map CompletableFuture - */ - public CompletableFuture> queryColumnMapAsync(final Class entityClass, final ColumnNode[] funcNodes, final String groupByColumn, final FilterNode node); - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凣ROUP BY鑱氬悎缁撴灉Map
- * 绛変环SQL: SELECT col1, col2, FUNC{funcColumn1}, FUNC{funcColumn2} FROM {table} GROUP BY {col1}, {col2}
- * 濡 queryColumnMapAsync(OrderRecord.class, Utility.ofArray(ColumnNodeValue.div(ColumnFuncNode.sum("money"), 100), ColumnFuncNode.avg(ColumnNodeValue.dec("money", 20)))), Utility.ofArray("fromid", "targetid")) - * 绛変环浜: SELECT fromid, targetid, SUM(money) / 100, AVG(money - 20) FROM orderrecord GROUP BY fromid, targetid
- * - * @param Entity娉涘瀷 - * @param Key瀛楁鐨勬暟鎹被鍨 - * @param Number - * @param entityClass Entity绫 - * @param funcNodes ColumnNode[] - * @param groupByColumns GROUP BY瀛楁 - * - * @return 鑱氬悎缁撴灉Map CompletableFuture - */ - default Map queryColumnMap(final Class entityClass, final ColumnNode[] funcNodes, final String[] groupByColumns) { - return queryColumnMap(entityClass, funcNodes, groupByColumns, (FilterNode) null); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凣ROUP BY鑱氬悎缁撴灉Map
- * 绛変环SQL: SELECT col1, col2, FUNC{funcColumn1}, FUNC{funcColumn2} FROM {table} GROUP BY {col1}, {col2}
- * 濡 queryColumnMapAsync(OrderRecord.class, Utility.ofArray(ColumnNodeValue.div(ColumnFuncNode.sum("money"), 100), ColumnFuncNode.avg(ColumnNodeValue.dec("money", 20)))), Utility.ofArray("fromid", "targetid")) - * 绛変环浜: SELECT fromid, targetid, SUM(money) / 100, AVG(money - 20) FROM orderrecord GROUP BY fromid, targetid
- * - * @param Entity娉涘瀷 - * @param Key瀛楁鐨勬暟鎹被鍨 - * @param Number - * @param entityClass Entity绫 - * @param funcNodes ColumnNode[] - * @param groupByColumns GROUP BY瀛楁 - * - * @return 鑱氬悎缁撴灉Map CompletableFuture - */ - default CompletableFuture> queryColumnMapAsync(final Class entityClass, final ColumnNode[] funcNodes, final String[] groupByColumns) { - return queryColumnMapAsync(entityClass, funcNodes, groupByColumns, (FilterNode) null); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凣ROUP BY鑱氬悎缁撴灉Map
- * 绛変环SQL: SELECT col1, col2, FUNC{funcColumn1}, FUNC{funcColumn2} FROM {table} WHERE {filter bean} GROUP BY {col1}, {col2}
- * 濡 queryColumnMapAsync(OrderRecord.class, Utility.ofArray(ColumnNodeValue.div(ColumnFuncNode.sum("money"), 100), ColumnFuncNode.avg(ColumnNodeValue.dec("money", 20)))), Utility.ofArray("fromid", "targetid"), (FilterBean)null) - * 绛変环浜: SELECT fromid, targetid, SUM(money) / 100, AVG(money - 20) FROM orderrecord GROUP BY fromid, targetid
- * - * @param Entity娉涘瀷 - * @param Key瀛楁鐨勬暟鎹被鍨 - * @param Number - * @param entityClass Entity绫 - * @param funcNodes ColumnNode[] - * @param groupByColumns GROUP BY瀛楁 - * @param bean 杩囨护鏉′欢 - * - * @return 鑱氬悎缁撴灉Map CompletableFuture - */ - default Map queryColumnMap(final Class entityClass, final ColumnNode[] funcNodes, final String[] groupByColumns, final FilterBean bean) { - return queryColumnMap(entityClass, funcNodes, groupByColumns, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凣ROUP BY鑱氬悎缁撴灉Map
- * 绛変环SQL: SELECT col1, col2, FUNC{funcColumn1}, FUNC{funcColumn2} FROM {table} WHERE {filter bean} GROUP BY {col1}, {col2}
- * 濡 queryColumnMapAsync(OrderRecord.class, Utility.ofArray(ColumnNodeValue.div(ColumnFuncNode.sum("money"), 100), ColumnFuncNode.avg(ColumnNodeValue.dec("money", 20)))), Utility.ofArray("fromid", "targetid"), (FilterBean)null) - * 绛変环浜: SELECT fromid, targetid, SUM(money) / 100, AVG(money - 20) FROM orderrecord GROUP BY fromid, targetid
- * - * @param Entity娉涘瀷 - * @param Key瀛楁鐨勬暟鎹被鍨 - * @param Number - * @param entityClass Entity绫 - * @param funcNodes ColumnNode[] - * @param groupByColumns GROUP BY瀛楁 - * @param bean 杩囨护鏉′欢 - * - * @return 鑱氬悎缁撴灉Map CompletableFuture - */ - default CompletableFuture> queryColumnMapAsync(final Class entityClass, final ColumnNode[] funcNodes, final String[] groupByColumns, final FilterBean bean) { - return queryColumnMapAsync(entityClass, funcNodes, groupByColumns, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凣ROUP BY鑱氬悎缁撴灉Map
- * 绛変环SQL: SELECT col1, col2, FUNC{funcColumn1}, FUNC{funcColumn2} FROM {table} WHERE {filter node} GROUP BY {col1}, {col2}
- * 濡 queryColumnMapAsync(OrderRecord.class, Utility.ofArray(ColumnNodeValue.div(ColumnFuncNode.sum("money"), 100), ColumnFuncNode.avg(ColumnNodeValue.dec("money", 20)))), Utility.ofArray("fromid", "targetid"), (FilterNode)null) - * 绛変环浜: SELECT fromid, targetid, SUM(money) / 100, AVG(money - 20) FROM orderrecord GROUP BY fromid, targetid
- * - * @param Entity娉涘瀷 - * @param Key瀛楁鐨勬暟鎹被鍨 - * @param Number - * @param entityClass Entity绫 - * @param funcNodes ColumnNode[] - * @param groupByColumns GROUP BY瀛楁 - * @param node 杩囨护鏉′欢 - * - * @return 鑱氬悎缁撴灉Map - */ - public Map queryColumnMap(final Class entityClass, final ColumnNode[] funcNodes, final String[] groupByColumns, final FilterNode node); - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凣ROUP BY鑱氬悎缁撴灉Map
- * 绛変环SQL: SELECT col1, col2, FUNC{funcColumn1}, FUNC{funcColumn2} FROM {table} WHERE {filter node} GROUP BY {col1}, {col2}
- * 濡 queryColumnMapAsync(OrderRecord.class, Utility.ofArray(ColumnNodeValue.div(ColumnFuncNode.sum("money"), 100), ColumnFuncNode.avg(ColumnNodeValue.dec("money", 20)))), Utility.ofArray("fromid", "targetid"), (FilterNode)null) - * 绛変环浜: SELECT fromid, targetid, SUM(money) / 100, AVG(money - 20) FROM orderrecord GROUP BY fromid, targetid
- * - * @param Entity娉涘瀷 - * @param Key瀛楁鐨勬暟鎹被鍨 - * @param Number - * @param entityClass Entity绫 - * @param funcNodes ColumnNode[] - * @param groupByColumns GROUP BY瀛楁 - * @param node 杩囨护鏉′欢 - * - * @return 鑱氬悎缁撴灉Map CompletableFuture - */ - public CompletableFuture> queryColumnMapAsync(final Class entityClass, final ColumnNode[] funcNodes, final String[] groupByColumns, final FilterNode node); - - //-----------------------findAsync---------------------------- - /** - * 鑾峰彇鎸囧畾涓婚敭鍊肩殑鍗曚釜璁板綍, 杩斿洖null琛ㄧず涓嶅瓨鍦ㄥ
- * 绛変环SQL: SELECT * FROM {table} WHERE {primary} = {id}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param pk 涓婚敭鍊 - * - * @return Entity瀵硅薄 - */ - default T find(final Class clazz, final Serializable pk) { - return find(clazz, (SelectColumn) null, pk); - } - - /** - * 鑾峰彇鎸囧畾涓婚敭鍊肩殑鍗曚釜璁板綍, 杩斿洖null琛ㄧず涓嶅瓨鍦ㄥ
- * 绛変环SQL: SELECT * FROM {table} WHERE {primary} = {id}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param pk 涓婚敭鍊 - * - * @return Entity瀵硅薄 CompletableFuture - */ - public CompletableFuture findAsync(final Class clazz, final Serializable pk); - - /** - * 鑾峰彇鎸囧畾涓婚敭鍊肩殑鍗曚釜璁板綍, 杩斿洖null琛ㄧず涓嶅瓨鍦ㄥ
- * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {primary} = {id}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param selects 鎸囧畾瀛楁 - * @param pk 涓婚敭鍊 - * - * @return Entity瀵硅薄 - */ - public T find(final Class clazz, final SelectColumn selects, final Serializable pk); - - /** - * 鑾峰彇鎸囧畾涓婚敭鍊肩殑鍗曚釜璁板綍, 杩斿洖null琛ㄧず涓嶅瓨鍦ㄥ
- * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {primary} = {id}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param selects 鎸囧畾瀛楁 - * @param pk 涓婚敭鍊 - * - * @return Entity瀵硅薄CompletableFuture - */ - public CompletableFuture findAsync(final Class clazz, final SelectColumn selects, final Serializable pk); - - /** - * 鑾峰彇鎸囧畾涓婚敭鍊肩殑澶氫釜璁板綍, 杩斿洖鏁扮粍锛屾暟缁勯暱搴︿笌pks涓鏍
- * 绛変环SQL: SELECT * FROM {table} WHERE {primary} = {id1,id2, ···}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param pks 涓婚敭鍊奸泦鍚 - * - * @return Entity瀵硅薄 - */ - default T[] finds(final Class clazz, final Serializable... pks) { - return finds(clazz, (SelectColumn) null, pks); - } - - /** - * 鑾峰彇鎸囧畾涓婚敭鍊肩殑澶氫釜璁板綍, 杩斿洖鏁扮粍锛屾暟缁勯暱搴︿笌pks涓鏍
- * 绛変环SQL: SELECT * FROM {table} WHERE {primary} = {id1,id2, ···}
- * - * @param 涓婚敭娉涘瀷 - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param pks 涓婚敭鍊奸泦鍚 - * - * @return Entity瀵硅薄 - */ - default T[] finds(final Class clazz, final Stream pks) { - return finds(clazz, (SelectColumn) null, pks.toArray(v -> new Serializable[v])); - } - - /** - * 鑾峰彇鎸囧畾涓婚敭鍊肩殑澶氫釜璁板綍, 杩斿洖鏁扮粍锛屾暟缁勯暱搴︿笌pks涓鏍
- * 绛変环SQL: SELECT * FROM {table} WHERE {primary} = {id1,id2, ···}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param pks 涓婚敭鍊奸泦鍚 - * - * @return Entity瀵硅薄 CompletableFuture - */ - default CompletableFuture findsAsync(final Class clazz, final Serializable... pks) { - return findsAsync(clazz, (SelectColumn) null, pks); - } - - /** - * 鑾峰彇鎸囧畾涓婚敭鍊肩殑澶氫釜璁板綍, 杩斿洖鏁扮粍锛屾暟缁勯暱搴︿笌pks涓鏍
- * 绛変环SQL: SELECT * FROM {table} WHERE {primary} = {id1,id2, ···}
- * - * @param 涓婚敭娉涘瀷 - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param pks 涓婚敭鍊奸泦鍚 - * - * @return Entity瀵硅薄 CompletableFuture - */ - default CompletableFuture findsAsync(final Class clazz, final Stream pks) { - return findsAsync(clazz, (SelectColumn) null, pks.toArray(v -> new Serializable[v])); - } - - /** - * 鑾峰彇鎸囧畾涓婚敭鍊肩殑澶氫釜璁板綍, 杩斿洖鏁扮粍锛屾暟缁勯暱搴︿笌pks涓鏍
- * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {primary} = {id1,id2, ···}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param selects 鎸囧畾瀛楁 - * @param pks 涓婚敭鍊奸泦鍚 - * - * @return Entity瀵硅薄 - */ - public T[] finds(final Class clazz, final SelectColumn selects, final Serializable... pks); - - /** - * 鑾峰彇鎸囧畾涓婚敭鍊肩殑澶氫釜璁板綍, 杩斿洖鏁扮粍锛屾暟缁勯暱搴︿笌pks涓鏍
- * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {primary} = {id1,id2, ···}
- * - * @param 涓婚敭娉涘瀷 - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param selects 鎸囧畾瀛楁 - * @param pks 涓婚敭鍊奸泦鍚 - * - * @return Entity瀵硅薄 - */ - default T[] finds(final Class clazz, final SelectColumn selects, final Stream pks) { - return finds(clazz, selects, pks.toArray(v -> new Serializable[v])); - } - - /** - * 鑾峰彇鎸囧畾涓婚敭鍊肩殑澶氫釜璁板綍, 杩斿洖鏁扮粍锛屾暟缁勯暱搴︿笌pks涓鏍
- * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {primary} = {id1,id2, ···}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param selects 鎸囧畾瀛楁 - * @param pks 涓婚敭鍊奸泦鍚 - * - * @return Entity瀵硅薄CompletableFuture - */ - public CompletableFuture findsAsync(final Class clazz, final SelectColumn selects, final Serializable... pks); - - /** - * 鑾峰彇鎸囧畾涓婚敭鍊肩殑澶氫釜璁板綍, 杩斿洖鏁扮粍锛屾暟缁勯暱搴︿笌pks涓鏍
- * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {primary} = {id1,id2, ···}
- * - * @param 涓婚敭娉涘瀷 - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param selects 鎸囧畾瀛楁 - * @param pks 涓婚敭鍊奸泦鍚 - * - * @return Entity瀵硅薄 - */ - default CompletableFuture findsAsync(final Class clazz, final SelectColumn selects, final Stream pks) { - return findsAsync(clazz, selects, pks.toArray(v -> new Serializable[v])); - } - - /** - * 鑾峰彇绗﹀悎杩囨护鏉′欢鍗曚釜璁板綍, 杩斿洖null琛ㄧず涓嶅瓨鍦ㄥ
- * 绛変环SQL: SELECT * FROM {table} WHERE {column} = {key}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param column 杩囨护瀛楁鍚 - * @param colval 杩囨护瀛楁鍊 - * - * @return Entity瀵硅薄 - */ - public T find(final Class clazz, final String column, final Serializable colval); - - /** - * 鑾峰彇绗﹀悎杩囨护鏉′欢鍗曚釜璁板綍, 杩斿洖null琛ㄧず涓嶅瓨鍦ㄥ
- * 绛変环SQL: SELECT * FROM {table} WHERE {column} = {key}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param column 杩囨护瀛楁鍚 - * @param colval 杩囨护瀛楁鍊 - * - * @return Entity瀵硅薄CompletableFuture - */ - public CompletableFuture findAsync(final Class clazz, final String column, final Serializable colval); - - /** - * 鑾峰彇绗﹀悎杩囨护鏉′欢鍗曚釜璁板綍, 杩斿洖null琛ㄧず涓嶅瓨鍦ㄥ
- * 绛変环SQL: SELECT * FROM {table} WHERE {filter bean}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param bean 杩囨护鏉′欢 - * - * @return Entity瀵硅薄 - */ - default T find(final Class clazz, final FilterBean bean) { - return find(clazz, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鑾峰彇绗﹀悎杩囨护鏉′欢鍗曚釜璁板綍, 杩斿洖null琛ㄧず涓嶅瓨鍦ㄥ
- * 绛変环SQL: SELECT * FROM {table} WHERE {filter bean}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param bean 杩囨护鏉′欢 - * - * @return Entity瀵硅薄CompletableFuture - */ - default CompletableFuture findAsync(final Class clazz, final FilterBean bean) { - return findAsync(clazz, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鑾峰彇绗﹀悎杩囨护鏉′欢鍗曚釜璁板綍, 杩斿洖null琛ㄧず涓嶅瓨鍦ㄥ
- * 绛変环SQL: SELECT * FROM {table} WHERE {filter node}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param node 杩囨护鏉′欢 - * - * @return Entity瀵硅薄 - */ - default T find(final Class clazz, final FilterNode node) { - return find(clazz, (SelectColumn) null, node); - } - - /** - * 鑾峰彇绗﹀悎杩囨护鏉′欢鍗曚釜璁板綍, 杩斿洖null琛ㄧず涓嶅瓨鍦ㄥ
- * 绛変环SQL: SELECT * FROM {table} WHERE {filter node}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param node 杩囨护鏉′欢 - * - * @return Entity瀵硅薄CompletableFuture - */ - default CompletableFuture findAsync(final Class clazz, final FilterNode node) { - return findAsync(clazz, (SelectColumn) null, node); - } - - /** - * 鑾峰彇绗﹀悎杩囨护鏉′欢鍗曚釜璁板綍, 杩斿洖null琛ㄧず涓嶅瓨鍦ㄥ
- * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter bean}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param selects 鎸囧畾瀛楁 - * @param bean 杩囨护鏉′欢 - * - * @return Entity瀵硅薄 - */ - default T find(final Class clazz, final SelectColumn selects, final FilterBean bean) { - return find(clazz, selects, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鑾峰彇绗﹀悎杩囨护鏉′欢鍗曚釜璁板綍, 杩斿洖null琛ㄧず涓嶅瓨鍦ㄥ
- * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter bean}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param selects 鎸囧畾瀛楁 - * @param bean 杩囨护鏉′欢 - * - * @return Entity瀵硅薄 CompletableFuture - */ - default CompletableFuture findAsync(final Class clazz, final SelectColumn selects, final FilterBean bean) { - return findAsync(clazz, selects, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鑾峰彇绗﹀悎杩囨护鏉′欢鍗曚釜璁板綍, 杩斿洖null琛ㄧず涓嶅瓨鍦ㄥ
- * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter node}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param selects 鎸囧畾瀛楁 - * @param node 杩囨护鏉′欢 - * - * @return Entity瀵硅薄 - */ - public T find(final Class clazz, final SelectColumn selects, final FilterNode node); - - /** - * 鑾峰彇绗﹀悎杩囨护鏉′欢鍗曚釜璁板綍, 杩斿洖null琛ㄧず涓嶅瓨鍦ㄥ
- * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter node}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param selects 鎸囧畾瀛楁 - * @param node 杩囨护鏉′欢 - * - * @return Entity瀵硅薄 CompletableFuture - */ - public CompletableFuture findAsync(final Class clazz, final SelectColumn selects, final FilterNode node); - - /** - * 鑾峰彇绗﹀悎杩囨护鏉′欢鍗曚釜璁板綍鐨勫崟涓瓧娈靛, 杩斿洖null琛ㄧず涓嶅瓨鍦ㄥ
- * 绛変环SQL: SELECT {column} FROM {table} WHERE {primary} = {id}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param column 瀛楁鍚 - * @param pk 涓婚敭鍊 - * - * @return Entity瀵硅薄 - */ - public Serializable findColumn(final Class clazz, final String column, final Serializable pk); - - /** - * 鑾峰彇绗﹀悎杩囨护鏉′欢鍗曚釜璁板綍鐨勫崟涓瓧娈靛, 杩斿洖null琛ㄧず涓嶅瓨鍦ㄥ
- * 绛変环SQL: SELECT {column} FROM {table} WHERE {primary} = {id}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param column 瀛楁鍚 - * @param pk 涓婚敭鍊 - * - * @return Entity瀵硅薄 CompletableFuture - */ - public CompletableFuture findColumnAsync(final Class clazz, final String column, final Serializable pk); - - /** - * 鑾峰彇绗﹀悎杩囨护鏉′欢鍗曚釜璁板綍鐨勫崟涓瓧娈靛, 杩斿洖null琛ㄧず涓嶅瓨鍦ㄥ
- * 绛変环SQL: SELECT {column} FROM {table} WHERE {filter bean}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param column 瀛楁鍚 - * @param bean 杩囨护鏉′欢 - * - * @return 瀛楁鍊 - */ - default Serializable findColumn(final Class clazz, final String column, final FilterBean bean) { - return findColumn(clazz, column, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鑾峰彇绗﹀悎杩囨护鏉′欢鍗曚釜璁板綍鐨勫崟涓瓧娈靛, 杩斿洖null琛ㄧず涓嶅瓨鍦ㄥ
- * 绛変环SQL: SELECT {column} FROM {table} WHERE {filter bean}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param column 瀛楁鍚 - * @param bean 杩囨护鏉′欢 - * - * @return 瀛楁鍊 CompletableFuture - */ - default CompletableFuture findColumnAsync(final Class clazz, final String column, final FilterBean bean) { - return findColumnAsync(clazz, column, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鑾峰彇绗﹀悎杩囨护鏉′欢鍗曚釜璁板綍鐨勫崟涓瓧娈靛, 杩斿洖null琛ㄧず涓嶅瓨鍦ㄥ
- * 绛変环SQL: SELECT {column} FROM {table} WHERE {filter node}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param column 瀛楁鍚 - * @param node 杩囨护鏉′欢 - * - * @return 瀛楁鍊 - */ - default Serializable findColumn(final Class clazz, final String column, final FilterNode node) { - return findColumn(clazz, column, null, node); - } - - /** - * 鑾峰彇绗﹀悎杩囨护鏉′欢鍗曚釜璁板綍鐨勫崟涓瓧娈靛, 杩斿洖null琛ㄧず涓嶅瓨鍦ㄥ
- * 绛変环SQL: SELECT {column} FROM {table} WHERE {filter node}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param column 瀛楁鍚 - * @param node 杩囨护鏉′欢 - * - * @return 瀛楁鍊 CompletableFuture - */ - default CompletableFuture findColumnAsync(final Class clazz, final String column, final FilterNode node) { - return findColumnAsync(clazz, column, null, node); - } - - /** - * 鑾峰彇绗﹀悎杩囨护鏉′欢鍗曚釜璁板綍鐨勫崟涓瓧娈靛, 涓嶅瓨鍦ㄥ煎垯杩斿洖榛樿鍊
- * 绛変环SQL: SELECT {column} FROM {table} WHERE {primary} = {id}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param column 瀛楁鍚 - * @param defValue 榛樿鍊 - * @param pk 涓婚敭鍊 - * - * @return 瀛楁鍊 - */ - public Serializable findColumn(final Class clazz, final String column, final Serializable defValue, final Serializable pk); - - /** - * 鑾峰彇绗﹀悎杩囨护鏉′欢鍗曚釜璁板綍鐨勫崟涓瓧娈靛, 涓嶅瓨鍦ㄥ煎垯杩斿洖榛樿鍊
- * 绛変环SQL: SELECT {column} FROM {table} WHERE {primary} = {id}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param column 瀛楁鍚 - * @param defValue 榛樿鍊 - * @param pk 涓婚敭鍊 - * - * @return 瀛楁鍊 CompletableFuture - */ - public CompletableFuture findColumnAsync(final Class clazz, final String column, final Serializable defValue, final Serializable pk); - - /** - * 鑾峰彇绗﹀悎杩囨护鏉′欢鍗曚釜璁板綍鐨勫崟涓瓧娈靛, 涓嶅瓨鍦ㄥ煎垯杩斿洖榛樿鍊
- * 绛変环SQL: SELECT {column} FROM {table} WHERE {filter bean}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param column 瀛楁鍚 - * @param defValue 榛樿鍊 - * @param bean 杩囨护鏉′欢 - * - * @return 瀛楁鍊 - */ - default Serializable findColumn(final Class clazz, final String column, final Serializable defValue, final FilterBean bean) { - return findColumn(clazz, column, defValue, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鑾峰彇绗﹀悎杩囨护鏉′欢鍗曚釜璁板綍鐨勫崟涓瓧娈靛, 涓嶅瓨鍦ㄥ煎垯杩斿洖榛樿鍊
- * 绛変环SQL: SELECT {column} FROM {table} WHERE {filter bean}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param column 瀛楁鍚 - * @param defValue 榛樿鍊 - * @param bean 杩囨护鏉′欢 - * - * @return 瀛楁鍊 CompletableFuture - */ - default CompletableFuture findColumnAsync(final Class clazz, final String column, final Serializable defValue, final FilterBean bean) { - return findColumnAsync(clazz, column, defValue, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鑾峰彇绗﹀悎杩囨护鏉′欢鍗曚釜璁板綍鐨勫崟涓瓧娈靛, 涓嶅瓨鍦ㄥ煎垯杩斿洖榛樿鍊
- * 绛変环SQL: SELECT {column} FROM {table} WHERE {filter node}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param column 瀛楁鍚 - * @param defValue 榛樿鍊 - * @param node 杩囨护鏉′欢 - * - * @return 瀛楁鍊 - */ - public Serializable findColumn(final Class clazz, final String column, final Serializable defValue, final FilterNode node); - - /** - * 鑾峰彇绗﹀悎杩囨护鏉′欢鍗曚釜璁板綍鐨勫崟涓瓧娈靛, 涓嶅瓨鍦ㄥ煎垯杩斿洖榛樿鍊
- * 绛変环SQL: SELECT {column} FROM {table} WHERE {filter node}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param column 瀛楁鍚 - * @param defValue 榛樿鍊 - * @param node 杩囨护鏉′欢 - * - * @return 瀛楁鍊 CompletableFuture - */ - public CompletableFuture findColumnAsync(final Class clazz, final String column, final Serializable defValue, final FilterNode node); - - /** - * 鍒ゆ柇鏄惁瀛樺湪涓婚敭鍊肩殑璁板綍
- * 绛変环SQL: SELECT COUNT(*) FROM {table} WHERE {primary} = {id}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param pk 涓婚敭鍊 - * - * @return 鏄惁瀛樺湪 - */ - public boolean exists(final Class clazz, final Serializable pk); - - /** - * 鍒ゆ柇鏄惁瀛樺湪涓婚敭鍊肩殑璁板綍
- * 绛変环SQL: SELECT COUNT(*) FROM {table} WHERE {primary} = {id}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param pk 涓婚敭鍊 - * - * @return 鏄惁瀛樺湪CompletableFuture - */ - public CompletableFuture existsAsync(final Class clazz, final Serializable pk); - - /** - * 鍒ゆ柇鏄惁瀛樺湪绗﹀悎杩囨护鏉′欢鐨勮褰
- * 绛変环SQL: SELECT COUNT(*) FROM {table} WHERE {filter bean}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param bean 杩囨护鏉′欢 - * - * @return 鏄惁瀛樺湪 - */ - default boolean exists(final Class clazz, final FilterBean bean) { - return exists(clazz, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鍒ゆ柇鏄惁瀛樺湪绗﹀悎杩囨护鏉′欢鐨勮褰
- * 绛変环SQL: SELECT COUNT(*) FROM {table} WHERE {filter bean}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param bean 杩囨护鏉′欢 - * - * @return 鏄惁瀛樺湪CompletableFuture - */ - default CompletableFuture existsAsync(final Class clazz, final FilterBean bean) { - return existsAsync(clazz, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鍒ゆ柇鏄惁瀛樺湪绗﹀悎杩囨护鏉′欢鐨勮褰
- * 绛変环SQL: SELECT COUNT(*) FROM {table} WHERE {filter node}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param node 杩囨护鏉′欢 - * - * @return 鏄惁瀛樺湪 - */ - public boolean exists(final Class clazz, final FilterNode node); - - /** - * 鍒ゆ柇鏄惁瀛樺湪绗﹀悎杩囨护鏉′欢鐨勮褰
- * 绛変环SQL: SELECT COUNT(*) FROM {table} WHERE {filter node}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param node 杩囨护鏉′欢 - * - * @return 鏄惁瀛樺湪CompletableFuture - */ - public CompletableFuture existsAsync(final Class clazz, final FilterNode node); - - //-----------------------list set---------------------------- - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨勬煇涓瓧娈礢et闆嗗悎
- * 绛変环SQL: SELECT DISTINCT {selectedColumn} FROM {table} WHERE {column} = {key}
- * - * @param Entity娉涘瀷 - * @param 瀛楁绫诲瀷 - * @param selectedColumn 鎸囧畾瀛楁 - * @param clazz Entity绫 - * @param column 杩囨护瀛楁鍚 - * @param colval 杩囨护瀛楁鍊 - * - * @return 瀛楁鍊肩殑闆嗗悎 - */ - public Set queryColumnSet(final String selectedColumn, final Class clazz, final String column, final Serializable colval); - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨勬煇涓瓧娈礢et闆嗗悎
- * 绛変环SQL: SELECT DISTINCT {selectedColumn} FROM {table} WHERE {column} = {key}
- * - * @param Entity娉涘瀷 - * @param 瀛楁绫诲瀷 - * @param selectedColumn 鎸囧畾瀛楁 - * @param clazz Entity绫 - * @param column 杩囨护瀛楁鍚 - * @param colval 杩囨护瀛楁鍊 - * - * @return 瀛楁鍊肩殑闆嗗悎CompletableFuture - */ - public CompletableFuture> queryColumnSetAsync(final String selectedColumn, final Class clazz, final String column, final Serializable colval); - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨勬煇涓瓧娈礢et闆嗗悎
- * 绛変环SQL: SELECT DISTINCT {selectedColumn} FROM {table} WHERE {filter bean}
- * - * @param Entity娉涘瀷 - * @param 瀛楁绫诲瀷 - * @param selectedColumn 鎸囧畾瀛楁 - * @param clazz Entity绫 - * @param bean 杩囨护鏉′欢 - * - * @return 瀛楁鍊肩殑闆嗗悎 - */ - default Set queryColumnSet(final String selectedColumn, final Class clazz, final FilterBean bean) { - return queryColumnSet(selectedColumn, clazz, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨勬煇涓瓧娈礢et闆嗗悎
- * 绛変环SQL: SELECT DISTINCT {selectedColumn} FROM {table} WHERE {filter bean}
- * - * @param Entity娉涘瀷 - * @param 瀛楁绫诲瀷 - * @param selectedColumn 鎸囧畾瀛楁 - * @param clazz Entity绫 - * @param bean 杩囨护鏉′欢 - * - * @return 瀛楁鍊肩殑闆嗗悎CompletableFuture - */ - default CompletableFuture> queryColumnSetAsync(final String selectedColumn, final Class clazz, final FilterBean bean) { - return queryColumnSetAsync(selectedColumn, clazz, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨勬煇涓瓧娈礢et闆嗗悎
- * 绛変环SQL: SELECT DISTINCT {selectedColumn} FROM {table} WHERE {filter node}
- * - * @param Entity娉涘瀷 - * @param 瀛楁绫诲瀷 - * @param selectedColumn 鎸囧畾瀛楁 - * @param clazz Entity绫 - * @param node 杩囨护鏉′欢 - * - * @return 瀛楁鍊肩殑闆嗗悎 - */ - default Set queryColumnSet(final String selectedColumn, final Class clazz, final FilterNode node) { - return queryColumnSet(selectedColumn, clazz, (Flipper) null, node); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨勬煇涓瓧娈礢et闆嗗悎
- * 绛変环SQL: SELECT DISTINCT {selectedColumn} FROM {table} WHERE {filter node}
- * - * @param Entity娉涘瀷 - * @param 瀛楁绫诲瀷 - * @param selectedColumn 鎸囧畾瀛楁 - * @param clazz Entity绫 - * @param node 杩囨护鏉′欢 - * - * @return 瀛楁鍊肩殑闆嗗悎CompletableFuture - */ - default CompletableFuture> queryColumnSetAsync(final String selectedColumn, final Class clazz, final FilterNode node) { - return queryColumnSetAsync(selectedColumn, clazz, (Flipper) null, node); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨勬煇涓瓧娈礢et闆嗗悎
- * 绛変环SQL: SELECT DISTINCT {selectedColumn} FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param 瀛楁绫诲瀷 - * @param selectedColumn 鎸囧畾瀛楁 - * @param clazz Entity绫 - * @param flipper 缈婚〉瀵硅薄 - * @param bean 杩囨护鏉′欢 - * - * @return 瀛楁鍊肩殑闆嗗悎 - */ - default Set queryColumnSet(final String selectedColumn, final Class clazz, final Flipper flipper, final FilterBean bean) { - return queryColumnSet(selectedColumn, clazz, flipper, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨勬煇涓瓧娈礢et闆嗗悎
- * 绛変环SQL: SELECT DISTINCT {selectedColumn} FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param 瀛楁绫诲瀷 - * @param selectedColumn 鎸囧畾瀛楁 - * @param clazz Entity绫 - * @param flipper 缈婚〉瀵硅薄 - * @param bean 杩囨护鏉′欢 - * - * @return 瀛楁鍊肩殑闆嗗悎CompletableFuture - */ - default CompletableFuture> queryColumnSetAsync(final String selectedColumn, final Class clazz, final Flipper flipper, final FilterBean bean) { - return queryColumnSetAsync(selectedColumn, clazz, flipper, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨勬煇涓瓧娈礢et闆嗗悎
- * 绛変环SQL: SELECT DISTINCT {selectedColumn} FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param 瀛楁绫诲瀷 - * @param selectedColumn 鎸囧畾瀛楁 - * @param clazz Entity绫 - * @param flipper 缈婚〉瀵硅薄 - * @param node 杩囨护鏉′欢 - * - * @return 瀛楁鍊肩殑闆嗗悎 - */ - public Set queryColumnSet(final String selectedColumn, final Class clazz, final Flipper flipper, final FilterNode node); - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨勬煇涓瓧娈礢et闆嗗悎
- * 绛変环SQL: SELECT DISTINCT {selectedColumn} FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param 瀛楁绫诲瀷 - * @param selectedColumn 鎸囧畾瀛楁 - * @param clazz Entity绫 - * @param flipper 缈婚〉瀵硅薄 - * @param node 杩囨护鏉′欢 - * - * @return 瀛楁鍊肩殑闆嗗悎CompletableFuture - */ - public CompletableFuture> queryColumnSetAsync(final String selectedColumn, final Class clazz, final Flipper flipper, final FilterNode node); - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨勬煇涓瓧娈礚ist闆嗗悎
- * 绛変环SQL: SELECT {selectedColumn} FROM {table} WHERE {column} = {key}
- * - * @param Entity娉涘瀷 - * @param 瀛楁绫诲瀷 - * @param selectedColumn 鎸囧畾瀛楁 - * @param clazz Entity绫 - * @param column 杩囨护瀛楁鍚 - * @param colval 杩囨护瀛楁鍊 - * - * @return 瀛楁鍊肩殑闆嗗悎 - */ - public List queryColumnList(final String selectedColumn, final Class clazz, final String column, final Serializable colval); - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨勬煇涓瓧娈礚ist闆嗗悎
- * 绛変环SQL: SELECT {selectedColumn} FROM {table} WHERE {column} = {key}
- * - * @param Entity娉涘瀷 - * @param 瀛楁绫诲瀷 - * @param selectedColumn 鎸囧畾瀛楁 - * @param clazz Entity绫 - * @param column 杩囨护瀛楁鍚 - * @param colval 杩囨护瀛楁鍊 - * - * @return 瀛楁鍊肩殑闆嗗悎CompletableFuture - */ - public CompletableFuture> queryColumnListAsync(final String selectedColumn, final Class clazz, final String column, final Serializable colval); - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨勬煇涓瓧娈礚ist闆嗗悎
- * 绛変环SQL: SELECT {selectedColumn} FROM {table} WHERE {filter bean}
- * - * @param Entity娉涘瀷 - * @param 瀛楁绫诲瀷 - * @param selectedColumn 鎸囧畾瀛楁 - * @param clazz Entity绫 - * @param bean 杩囨护鏉′欢 - * - * @return 瀛楁鍊肩殑闆嗗悎 - */ - default List queryColumnList(final String selectedColumn, final Class clazz, final FilterBean bean) { - return queryColumnList(selectedColumn, clazz, (Flipper) null, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨勬煇涓瓧娈礚ist闆嗗悎
- * 绛変环SQL: SELECT {selectedColumn} FROM {table} WHERE {filter bean}
- * - * @param Entity娉涘瀷 - * @param 瀛楁绫诲瀷 - * @param selectedColumn 鎸囧畾瀛楁 - * @param clazz Entity绫 - * @param bean 杩囨护鏉′欢 - * - * @return 瀛楁鍊肩殑闆嗗悎CompletableFuture - */ - default CompletableFuture> queryColumnListAsync(final String selectedColumn, final Class clazz, final FilterBean bean) { - return queryColumnListAsync(selectedColumn, clazz, (Flipper) null, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨勬煇涓瓧娈礚ist闆嗗悎
- * 绛変环SQL: SELECT {selectedColumn} FROM {table} WHERE {filter node}
- * - * @param Entity娉涘瀷 - * @param 瀛楁绫诲瀷 - * @param selectedColumn 鎸囧畾瀛楁 - * @param clazz Entity绫 - * @param node 杩囨护鏉′欢 - * - * @return 瀛楁鍊肩殑闆嗗悎 - */ - default List queryColumnList(final String selectedColumn, final Class clazz, final FilterNode node) { - return queryColumnList(selectedColumn, clazz, (Flipper) null, node); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨勬煇涓瓧娈礚ist闆嗗悎
- * 绛変环SQL: SELECT {selectedColumn} FROM {table} WHERE {filter node}
- * - * @param Entity娉涘瀷 - * @param 瀛楁绫诲瀷 - * @param selectedColumn 鎸囧畾瀛楁 - * @param clazz Entity绫 - * @param node 杩囨护鏉′欢 - * - * @return 瀛楁鍊肩殑闆嗗悎CompletableFuture - */ - default CompletableFuture> queryColumnListAsync(final String selectedColumn, final Class clazz, final FilterNode node) { - return queryColumnListAsync(selectedColumn, clazz, (Flipper) null, node); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨勬煇涓瓧娈礚ist闆嗗悎
- * 绛変环SQL: SELECT {selectedColumn} FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param 瀛楁绫诲瀷 - * @param selectedColumn 鎸囧畾瀛楁 - * @param clazz Entity绫 - * @param flipper 缈婚〉瀵硅薄 - * @param bean 杩囨护鏉′欢 - * - * @return 瀛楁鍊肩殑闆嗗悎 - */ - default List queryColumnList(final String selectedColumn, final Class clazz, final Flipper flipper, final FilterBean bean) { - return queryColumnList(selectedColumn, clazz, flipper, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨勬煇涓瓧娈礚ist闆嗗悎
- * 绛変环SQL: SELECT {selectedColumn} FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param 瀛楁绫诲瀷 - * @param selectedColumn 鎸囧畾瀛楁 - * @param clazz Entity绫 - * @param flipper 缈婚〉瀵硅薄 - * @param bean 杩囨护鏉′欢 - * - * @return 瀛楁鍊肩殑闆嗗悎CompletableFuture - */ - default CompletableFuture> queryColumnListAsync(final String selectedColumn, final Class clazz, final Flipper flipper, final FilterBean bean) { - return queryColumnListAsync(selectedColumn, clazz, flipper, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨勬煇涓瓧娈礚ist闆嗗悎
- * 绛変环SQL: SELECT {selectedColumn} FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param 瀛楁绫诲瀷 - * @param selectedColumn 鎸囧畾瀛楁 - * @param clazz Entity绫 - * @param flipper 缈婚〉瀵硅薄 - * @param node 杩囨护鏉′欢 - * - * @return 瀛楁鍊肩殑闆嗗悎 - */ - public List queryColumnList(final String selectedColumn, final Class clazz, final Flipper flipper, final FilterNode node); - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨勬煇涓瓧娈礚ist闆嗗悎
- * 绛変环SQL: SELECT {selectedColumn} FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param 瀛楁绫诲瀷 - * @param selectedColumn 鎸囧畾瀛楁 - * @param clazz Entity绫 - * @param flipper 缈婚〉瀵硅薄 - * @param node 杩囨护鏉′欢 - * - * @return 瀛楁鍊肩殑闆嗗悎CompletableFuture - */ - public CompletableFuture> queryColumnListAsync(final String selectedColumn, final Class clazz, final Flipper flipper, final FilterNode node); - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨勬煇涓瓧娈礢heet闆嗗悎
- * 绛変环SQL: SELECT {selectedColumn} FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param 瀛楁绫诲瀷 - * @param selectedColumn 鎸囧畾瀛楁 - * @param clazz Entity绫 - * @param flipper 缈婚〉瀵硅薄 - * @param bean 杩囨护鏉′欢 - * - * @return 瀛楁鍊肩殑闆嗗悎 - */ - default Sheet queryColumnSheet(final String selectedColumn, final Class clazz, final Flipper flipper, final FilterBean bean) { - return queryColumnSheet(selectedColumn, clazz, flipper, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨勬煇涓瓧娈礢heet闆嗗悎
- * 绛変环SQL: SELECT {selectedColumn} FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param 瀛楁绫诲瀷 - * @param selectedColumn 鎸囧畾瀛楁 - * @param clazz Entity绫 - * @param flipper 缈婚〉瀵硅薄 - * @param bean 杩囨护鏉′欢 - * - * @return 瀛楁鍊肩殑闆嗗悎CompletableFuture - */ - default CompletableFuture> queryColumnSheetAsync(final String selectedColumn, final Class clazz, final Flipper flipper, final FilterBean bean) { - return queryColumnSheetAsync(selectedColumn, clazz, flipper, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨勬煇涓瓧娈礢heet闆嗗悎
- * 绛変环SQL: SELECT {selectedColumn} FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param 瀛楁绫诲瀷 - * @param selectedColumn 鎸囧畾瀛楁 - * @param clazz Entity绫 - * @param flipper 缈婚〉瀵硅薄 - * @param node 杩囨护鏉′欢 - * - * @return 瀛楁鍊肩殑闆嗗悎 - */ - public Sheet queryColumnSheet(final String selectedColumn, final Class clazz, final Flipper flipper, final FilterNode node); - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨勬煇涓瓧娈礢heet闆嗗悎
- * 绛変环SQL: SELECT {selectedColumn} FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param 瀛楁绫诲瀷 - * @param selectedColumn 鎸囧畾瀛楁 - * @param clazz Entity绫 - * @param flipper 缈婚〉瀵硅薄 - * @param node 杩囨护鏉′欢 - * - * @return 瀛楁鍊肩殑闆嗗悎CompletableFuture - */ - public CompletableFuture> queryColumnSheetAsync(final String selectedColumn, final Class clazz, final Flipper flipper, final FilterNode node); - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist杞琈ap闆嗗悎锛 key=涓婚敭鍊, value=Entity瀵硅薄
- * 绛変环SQL: SELECT * FROM {table} WHERE id IN {ids}
- * - * @param 涓婚敭娉涘瀷 - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param keyStream 涓婚敭Stream - * - * @return Entity鐨勯泦鍚 - */ - default Map queryMap(final Class clazz, final Stream keyStream) { - return queryMap(clazz, (SelectColumn) null, keyStream); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist杞琈ap闆嗗悎锛 key=涓婚敭鍊, value=Entity瀵硅薄
- * 绛変环SQL: SELECT * FROM {table} WHERE id IN {ids}
- * - * @param 涓婚敭娉涘瀷 - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param keyStream 涓婚敭Stream - * - * @return Entity鐨勯泦鍚圕ompletableFuture - */ - default CompletableFuture> queryMapAsync(final Class clazz, final Stream keyStream) { - return queryMapAsync(clazz, (SelectColumn) null, keyStream); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist杞琈ap闆嗗悎锛 key=涓婚敭鍊, value=Entity瀵硅薄
- * 绛変环SQL: SELECT * FROM {table} WHERE {filter node}
- * - * @param 涓婚敭娉涘瀷 - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param bean FilterBean - * - * @return Entity鐨勯泦鍚 - */ - default Map queryMap(final Class clazz, final FilterBean bean) { - return queryMap(clazz, (SelectColumn) null, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist杞琈ap闆嗗悎锛 key=涓婚敭鍊, value=Entity瀵硅薄
- * 绛変环SQL: SELECT * FROM {table} WHERE {filter node}
- * - * @param 涓婚敭娉涘瀷 - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param bean FilterBean - * - * @return Entity鐨勯泦鍚圕ompletableFuture - */ - default CompletableFuture> queryMapAsync(final Class clazz, final FilterBean bean) { - return queryMapAsync(clazz, (SelectColumn) null, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist杞琈ap闆嗗悎锛 key=涓婚敭鍊, value=Entity瀵硅薄
- * 绛変环SQL: SELECT * FROM {table} WHERE {filter node}
- * - * @param 涓婚敭娉涘瀷 - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param node FilterNode - * - * @return Entity鐨勯泦鍚 - */ - default Map queryMap(final Class clazz, final FilterNode node) { - return queryMap(clazz, (SelectColumn) null, node); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist杞琈ap闆嗗悎锛 key=涓婚敭鍊, value=Entity瀵硅薄
- * 绛変环SQL: SELECT * FROM {table} WHERE {filter node}
- * - * @param 涓婚敭娉涘瀷 - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param node FilterNode - * - * @return Entity鐨勯泦鍚圕ompletableFuture - */ - default CompletableFuture> queryMapAsync(final Class clazz, final FilterNode node) { - return queryMapAsync(clazz, (SelectColumn) null, node); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist杞琈ap闆嗗悎锛 key=涓婚敭鍊, value=Entity瀵硅薄
- * 绛変环SQL: SELECT * FROM {table} WHERE id IN {ids}
- * - * @param 涓婚敭娉涘瀷 - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param selects 鎸囧畾瀛楁 - * @param keyStream 涓婚敭Stream - * - * @return Entity鐨勯泦鍚 - */ - public Map queryMap(final Class clazz, final SelectColumn selects, final Stream keyStream); - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist杞琈ap闆嗗悎锛 key=涓婚敭鍊, value=Entity瀵硅薄
- * 绛変环SQL: SELECT * FROM {table} WHERE id IN {ids}
- * - * @param 涓婚敭娉涘瀷 - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param selects 鎸囧畾瀛楁 - * @param keyStream 涓婚敭Stream - * - * @return Entity鐨勯泦鍚圕ompletableFuture - */ - public CompletableFuture> queryMapAsync(final Class clazz, final SelectColumn selects, final Stream keyStream); - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist杞琈ap闆嗗悎锛 key=涓婚敭鍊, value=Entity瀵硅薄
- * 绛変环SQL: SELECT * FROM {table} WHERE {filter node}
- * - * @param 涓婚敭娉涘瀷 - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param selects 鎸囧畾瀛楁 - * @param bean FilterBean - * - * @return Entity鐨勯泦鍚 - */ - default Map queryMap(final Class clazz, final SelectColumn selects, final FilterBean bean) { - return queryMap(clazz, selects, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist杞琈ap闆嗗悎锛 key=涓婚敭鍊, value=Entity瀵硅薄
- * 绛変环SQL: SELECT * FROM {table} WHERE {filter node}
- * - * @param 涓婚敭娉涘瀷 - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param selects 鎸囧畾瀛楁 - * @param bean FilterBean - * - * @return Entity鐨勯泦鍚圕ompletableFuture - */ - default CompletableFuture> queryMapAsync(final Class clazz, final SelectColumn selects, FilterBean bean) { - return queryMapAsync(clazz, selects, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist杞琈ap闆嗗悎锛 key=涓婚敭鍊, value=Entity瀵硅薄
- * 绛変环SQL: SELECT * FROM {table} WHERE {filter node}
- * - * @param 涓婚敭娉涘瀷 - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param selects 鎸囧畾瀛楁 - * @param node FilterNode - * - * @return Entity鐨勯泦鍚 - */ - public Map queryMap(final Class clazz, final SelectColumn selects, final FilterNode node); - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist杞琈ap闆嗗悎锛 key=涓婚敭鍊, value=Entity瀵硅薄
- * 绛変环SQL: SELECT * FROM {table} WHERE {filter node}
- * - * @param 涓婚敭娉涘瀷 - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param selects 鎸囧畾瀛楁 - * @param node FilterNode - * - * @return Entity鐨勯泦鍚圕ompletableFuture - */ - public CompletableFuture> queryMapAsync(final Class clazz, final SelectColumn selects, final FilterNode node); - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷et闆嗗悎
- * 绛変环SQL: SELECT DISTINCT * FROM {table} WHERE {column} = {key} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param column 杩囨护瀛楁鍚 - * @param colval 杩囨护瀛楁鍊 - * - * @return Entity鐨勯泦鍚 - */ - default Set querySet(final Class clazz, final String column, final Serializable colval) { - return querySet(clazz, (Flipper) null, column, colval); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷et闆嗗悎
- * 绛変环SQL: SELECT DISTINCT * FROM {table} WHERE {column} = {key} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param column 杩囨护瀛楁鍚 - * @param colval 杩囨护瀛楁鍊 - * - * @return Entity鐨勯泦鍚圕ompletableFuture - */ - default CompletableFuture> querySetAsync(final Class clazz, final String column, final Serializable colval) { - return querySetAsync(clazz, (Flipper) null, column, colval); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷et闆嗗悎
- * 绛変环SQL: SELECT DISTINCT * FROM {table} WHERE {filter bean}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param bean 杩囨护鏉′欢 - * - * @return Entity鐨勯泦鍚 - */ - default Set querySet(final Class clazz, final FilterBean bean) { - return querySet(clazz, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷et闆嗗悎
- * 绛変环SQL: SELECT DISTINCT * FROM {table} WHERE {filter bean}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param bean 杩囨护鏉′欢 - * - * @return Entity鐨勯泦鍚圕ompletableFuture - */ - default CompletableFuture> querySetAsync(final Class clazz, final FilterBean bean) { - return querySetAsync(clazz, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鏌ヨ璁板綍鐨凷et闆嗗悎
- * 绛変环SQL: SELECT DISTINCT * FROM {table}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * - * @return Entity鐨勯泦鍚 - */ - default Set querySet(final Class clazz) { - return querySet(clazz, (SelectColumn) null, (Flipper) null, (FilterNode) null); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷et闆嗗悎
- * 绛変环SQL: SELECT DISTINCT * FROM {table} WHERE {filter node}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param node 杩囨护鏉′欢 - * - * @return Entity鐨勯泦鍚 - */ - default Set querySet(final Class clazz, final FilterNode node) { - return querySet(clazz, (SelectColumn) null, (Flipper) null, node); - } - - /** - * 鏌ヨ璁板綍鐨凷et闆嗗悎
- * 绛変环SQL: SELECT DISTINCT * FROM {table}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * - * @return Entity鐨勯泦鍚圕ompletableFuture - */ - default CompletableFuture> querySetAsync(final Class clazz) { - return querySetAsync(clazz, (SelectColumn) null, (Flipper) null, (FilterNode) null); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷et闆嗗悎
- * 绛変环SQL: SELECT DISTINCT * FROM {table} WHERE {filter node}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param node 杩囨护鏉′欢 - * - * @return Entity鐨勯泦鍚圕ompletableFuture - */ - default CompletableFuture> querySetAsync(final Class clazz, final FilterNode node) { - return querySetAsync(clazz, (SelectColumn) null, (Flipper) null, node); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷et闆嗗悎
- * 绛変环SQL: SELECT DISTINCT {column1},{column2}, ··· FROM {table} WHERE {filter bean}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param selects 鎸囧畾瀛楁 - * @param bean 杩囨护鏉′欢 - * - * @return Entity鐨勯泦鍚 - */ - default Set querySet(final Class clazz, final SelectColumn selects, final FilterBean bean) { - return querySet(clazz, selects, (Flipper) null, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷et闆嗗悎
- * 绛変环SQL: SELECT DISTINCT {column1},{column2}, ··· FROM {table} WHERE {filter bean}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param selects 鎸囧畾瀛楁 - * @param bean 杩囨护鏉′欢 - * - * @return Entity鐨勯泦鍚圕ompletableFuture - */ - default CompletableFuture> querySetAsync(final Class clazz, final SelectColumn selects, final FilterBean bean) { - return querySetAsync(clazz, selects, (Flipper) null, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷et闆嗗悎
- * 绛変环SQL: SELECT DISTINCT {column1},{column2}, ··· FROM {table} WHERE {filter node}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param selects 鎸囧畾瀛楁 - * @param node 杩囨护鏉′欢 - * - * @return Entity鐨勯泦鍚 - */ - default Set querySet(final Class clazz, final SelectColumn selects, final FilterNode node) { - return querySet(clazz, selects, (Flipper) null, node); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷et闆嗗悎
- * 绛変环SQL: SELECT DISTINCT {column1},{column2}, ··· FROM {table} WHERE {filter node}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param selects 鎸囧畾瀛楁 - * @param node 杩囨护鏉′欢 - * - * @return Entity鐨勯泦鍚圕ompletableFuture - */ - default CompletableFuture> querySetAsync(final Class clazz, final SelectColumn selects, final FilterNode node) { - return querySetAsync(clazz, selects, (Flipper) null, node); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷et闆嗗悎
- * 绛変环SQL: SELECT DISTINCT * FROM {table} WHERE {column} = {key} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param flipper 缈婚〉瀵硅薄 - * @param column 杩囨护瀛楁鍚 - * @param colval 杩囨护瀛楁鍊 - * - * @return Entity鐨勯泦鍚 - */ - public Set querySet(final Class clazz, final Flipper flipper, final String column, final Serializable colval); - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷et闆嗗悎
- * 绛変环SQL: SELECT DISTINCT * FROM {table} WHERE {column} = {key} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param flipper 缈婚〉瀵硅薄 - * @param column 杩囨护瀛楁鍚 - * @param colval 杩囨护瀛楁鍊 - * - * @return Entity鐨勯泦鍚圕ompletableFuture - */ - public CompletableFuture> querySetAsync(final Class clazz, final Flipper flipper, final String column, final Serializable colval); - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷et闆嗗悎
- * 绛変环SQL: SELECT DISTINCT * FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param flipper 缈婚〉瀵硅薄 - * @param bean 杩囨护鏉′欢 - * - * @return Entity鐨勯泦鍚 - */ - default Set querySet(final Class clazz, final Flipper flipper, final FilterBean bean) { - return querySet(clazz, (SelectColumn) null, flipper, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷et闆嗗悎
- * 绛変环SQL: SELECT DISTINCT * FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param flipper 缈婚〉瀵硅薄 - * @param bean 杩囨护鏉′欢 - * - * @return Entity鐨勯泦鍚圕ompletableFuture - */ - default CompletableFuture> querySetAsync(final Class clazz, final Flipper flipper, final FilterBean bean) { - return querySetAsync(clazz, (SelectColumn) null, flipper, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷et闆嗗悎
- * 绛変环SQL: SELECT DISTINCT * FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param flipper 缈婚〉瀵硅薄 - * @param node 杩囨护鏉′欢 - * - * @return Entity鐨勯泦鍚 - * - */ - default Set querySet(final Class clazz, final Flipper flipper, final FilterNode node) { - return querySet(clazz, (SelectColumn) null, flipper, node); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷et闆嗗悎
- * 绛変环SQL: SELECT DISTINCT * FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param flipper 缈婚〉瀵硅薄 - * @param node 杩囨护鏉′欢 - * - * @return Entity鐨勯泦鍚 - * - */ - default CompletableFuture> querySetAsync(final Class clazz, final Flipper flipper, final FilterNode node) { - return querySetAsync(clazz, (SelectColumn) null, flipper, node); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷et闆嗗悎
- * 绛変环SQL: SELECT DISTINCT {column1},{column2}, ··· FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param selects 鎸囧畾瀛楁 - * @param flipper 缈婚〉瀵硅薄 - * @param bean 杩囨护鏉′欢 - * - * @return Entity鐨勯泦鍚 - */ - default Set querySet(final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean) { - return querySet(clazz, selects, flipper, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷et闆嗗悎
- * 绛変环SQL: SELECT DISTINCT {column1},{column2}, ··· FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param selects 鎸囧畾瀛楁 - * @param flipper 缈婚〉瀵硅薄 - * @param bean 杩囨护鏉′欢 - * - * @return Entity鐨勯泦鍚圕ompletableFuture - */ - default CompletableFuture> querySetAsync(final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean) { - return querySetAsync(clazz, selects, flipper, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷et闆嗗悎
- * 绛変环SQL: SELECT DISTINCT {column1},{column2}, ··· FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param selects 鎸囧畾瀛楁 - * @param flipper 缈婚〉瀵硅薄 - * @param node 杩囨护鏉′欢 - * - * @return Entity鐨勯泦鍚 - */ - public Set querySet(final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node); - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷et闆嗗悎
- * 绛変环SQL: SELECT DISTINCT {column1},{column2}, ··· FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param selects 鎸囧畾瀛楁 - * @param flipper 缈婚〉瀵硅薄 - * @param node 杩囨护鏉′欢 - * - * @return Entity鐨勯泦鍚圕ompletableFuture - */ - public CompletableFuture> querySetAsync(final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node); - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist闆嗗悎
- * 绛変环SQL: SELECT * FROM {table} WHERE {column} = {key} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param column 杩囨护瀛楁鍚 - * @param colval 杩囨护瀛楁鍊 - * - * @return Entity鐨勯泦鍚 - */ - default List queryList(final Class clazz, final String column, final Serializable colval) { - return queryList(clazz, (Flipper) null, column, colval); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist闆嗗悎
- * 绛変环SQL: SELECT * FROM {table} WHERE {column} = {key} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param column 杩囨护瀛楁鍚 - * @param colval 杩囨护瀛楁鍊 - * - * @return Entity鐨勯泦鍚圕ompletableFuture - */ - default CompletableFuture> queryListAsync(final Class clazz, final String column, final Serializable colval) { - return queryListAsync(clazz, (Flipper) null, column, colval); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist闆嗗悎
- * 绛変环SQL: SELECT * FROM {table} WHERE {filter bean}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param bean 杩囨护鏉′欢 - * - * @return Entity鐨勯泦鍚 - */ - default List queryList(final Class clazz, final FilterBean bean) { - return queryList(clazz, (SelectColumn) null, (Flipper) null, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist闆嗗悎
- * 绛変环SQL: SELECT * FROM {table} WHERE {filter bean}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param bean 杩囨护鏉′欢 - * - * @return Entity鐨勯泦鍚圕ompletableFuture - */ - default CompletableFuture> queryListAsync(final Class clazz, final FilterBean bean) { - return queryListAsync(clazz, (SelectColumn) null, (Flipper) null, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鏌ヨ璁板綍鐨凩ist闆嗗悎
- * 绛変环SQL: SELECT * FROM {table}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * - * @return Entity鐨勯泦鍚 - */ - default List queryList(final Class clazz) { - return queryList(clazz, (SelectColumn) null, (Flipper) null, (FilterNode) null); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist闆嗗悎
- * 绛変环SQL: SELECT * FROM {table} WHERE {filter node}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param node 杩囨护鏉′欢 - * - * @return Entity鐨勯泦鍚 - */ - default List queryList(final Class clazz, final FilterNode node) { - return queryList(clazz, (SelectColumn) null, (Flipper) null, node); - } - - /** - * 鏌ヨ璁板綍鐨凩ist闆嗗悎
- * 绛変环SQL: SELECT * FROM {table}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * - * @return Entity鐨勯泦鍚圕ompletableFuture - */ - default CompletableFuture> queryListAsync(final Class clazz) { - return queryListAsync(clazz, (SelectColumn) null, (Flipper) null, (FilterNode) null); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist闆嗗悎
- * 绛変环SQL: SELECT * FROM {table} WHERE {filter node}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param node 杩囨护鏉′欢 - * - * @return Entity鐨勯泦鍚圕ompletableFuture - */ - default CompletableFuture> queryListAsync(final Class clazz, final FilterNode node) { - return queryListAsync(clazz, (SelectColumn) null, (Flipper) null, node); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist闆嗗悎
- * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter bean}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param selects 鎸囧畾瀛楁 - * @param bean 杩囨护鏉′欢 - * - * @return Entity鐨勯泦鍚 - */ - default List queryList(final Class clazz, final SelectColumn selects, final FilterBean bean) { - return queryList(clazz, selects, (Flipper) null, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist闆嗗悎
- * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter bean}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param selects 鎸囧畾瀛楁 - * @param bean 杩囨护鏉′欢 - * - * @return Entity鐨勯泦鍚圕ompletableFuture - */ - default CompletableFuture> queryListAsync(final Class clazz, final SelectColumn selects, final FilterBean bean) { - return queryListAsync(clazz, selects, (Flipper) null, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist闆嗗悎
- * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter node}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param selects 鎸囧畾瀛楁 - * @param node 杩囨护鏉′欢 - * - * @return Entity鐨勯泦鍚 - */ - default List queryList(final Class clazz, final SelectColumn selects, final FilterNode node) { - return queryList(clazz, selects, (Flipper) null, node); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist闆嗗悎
- * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter node}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param selects 鎸囧畾瀛楁 - * @param node 杩囨护鏉′欢 - * - * @return Entity鐨勯泦鍚圕ompletableFuture - */ - default CompletableFuture> queryListAsync(final Class clazz, final SelectColumn selects, final FilterNode node) { - return queryListAsync(clazz, selects, (Flipper) null, node); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist闆嗗悎
- * 绛変环SQL: SELECT * FROM {table} WHERE {column} = {key} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param flipper 缈婚〉瀵硅薄 - * @param column 杩囨护瀛楁鍚 - * @param colval 杩囨护瀛楁鍊 - * - * @return Entity鐨勯泦鍚 - */ - public List queryList(final Class clazz, final Flipper flipper, final String column, final Serializable colval); - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist闆嗗悎
- * 绛変环SQL: SELECT * FROM {table} WHERE {column} = {key} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param flipper 缈婚〉瀵硅薄 - * @param column 杩囨护瀛楁鍚 - * @param colval 杩囨护瀛楁鍊 - * - * @return Entity鐨勯泦鍚圕ompletableFuture - */ - public CompletableFuture> queryListAsync(final Class clazz, final Flipper flipper, final String column, final Serializable colval); - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist闆嗗悎
- * 绛変环SQL: SELECT * FROM {table} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param flipper 缈婚〉瀵硅薄 - * - * @return Entity鐨勯泦鍚 - */ - default List queryList(final Class clazz, final Flipper flipper) { - return queryList(clazz, (SelectColumn) null, flipper, (FilterNode) null); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist闆嗗悎
- * 绛変环SQL: SELECT * FROM {table} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param flipper 缈婚〉瀵硅薄 - * - * @return Entity鐨勯泦鍚圕ompletableFuture - */ - default CompletableFuture> queryListAsync(final Class clazz, final Flipper flipper) { - return queryListAsync(clazz, (SelectColumn) null, flipper, (FilterNode) null); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist闆嗗悎
- * 绛変环SQL: SELECT * FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param flipper 缈婚〉瀵硅薄 - * @param bean 杩囨护鏉′欢 - * - * @return Entity鐨勯泦鍚 - */ - default List queryList(final Class clazz, final Flipper flipper, final FilterBean bean) { - return queryList(clazz, (SelectColumn) null, flipper, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist闆嗗悎
- * 绛変环SQL: SELECT * FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param flipper 缈婚〉瀵硅薄 - * @param bean 杩囨护鏉′欢 - * - * @return Entity鐨勯泦鍚圕ompletableFuture - */ - default CompletableFuture> queryListAsync(final Class clazz, final Flipper flipper, final FilterBean bean) { - return queryListAsync(clazz, (SelectColumn) null, flipper, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist闆嗗悎
- * 绛変环SQL: SELECT * FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param flipper 缈婚〉瀵硅薄 - * @param node 杩囨护鏉′欢 - * - * @return Entity鐨勯泦鍚 - * - */ - default List queryList(final Class clazz, final Flipper flipper, final FilterNode node) { - return queryList(clazz, (SelectColumn) null, flipper, node); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist闆嗗悎
- * 绛変环SQL: SELECT * FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param flipper 缈婚〉瀵硅薄 - * @param node 杩囨护鏉′欢 - * - * @return Entity鐨勯泦鍚 - * - */ - default CompletableFuture> queryListAsync(final Class clazz, final Flipper flipper, final FilterNode node) { - return queryListAsync(clazz, (SelectColumn) null, flipper, node); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist闆嗗悎
- * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param selects 鎸囧畾瀛楁 - * @param flipper 缈婚〉瀵硅薄 - * - * @return Entity鐨勯泦鍚 - */ - default List queryList(final Class clazz, final SelectColumn selects, final Flipper flipper) { - return queryList(clazz, selects, flipper, (FilterNode) null); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist闆嗗悎
- * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param selects 鎸囧畾瀛楁 - * @param flipper 缈婚〉瀵硅薄 - * - * @return Entity鐨勯泦鍚圕ompletableFuture - */ - default CompletableFuture> queryListAsync(final Class clazz, final SelectColumn selects, final Flipper flipper) { - return queryListAsync(clazz, selects, flipper, (FilterNode) null); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist闆嗗悎
- * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param selects 鎸囧畾瀛楁 - * @param flipper 缈婚〉瀵硅薄 - * @param bean 杩囨护鏉′欢 - * - * @return Entity鐨勯泦鍚 - */ - default List queryList(final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean) { - return queryList(clazz, selects, flipper, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist闆嗗悎
- * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param selects 鎸囧畾瀛楁 - * @param flipper 缈婚〉瀵硅薄 - * @param bean 杩囨护鏉′欢 - * - * @return Entity鐨勯泦鍚圕ompletableFuture - */ - default CompletableFuture> queryListAsync(final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean) { - return queryListAsync(clazz, selects, flipper, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist闆嗗悎
- * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param selects 鎸囧畾瀛楁 - * @param flipper 缈婚〉瀵硅薄 - * @param node 杩囨护鏉′欢 - * - * @return Entity鐨勯泦鍚 - */ - public List queryList(final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node); - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist闆嗗悎
- * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param selects 鎸囧畾瀛楁 - * @param flipper 缈婚〉瀵硅薄 - * @param node 杩囨护鏉′欢 - * - * @return Entity鐨勯泦鍚圕ompletableFuture - */ - public CompletableFuture> queryListAsync(final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node); - - //-----------------------sheet---------------------------- - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷heet闆嗗悎
- * 绛変环SQL: SELECT * FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param flipper 缈婚〉瀵硅薄 - * @param bean 杩囨护鏉′欢 - * - * @return Entity鐨勯泦鍚 - */ - default Sheet querySheet(final Class clazz, final Flipper flipper, final FilterBean bean) { - return querySheet(clazz, (SelectColumn) null, flipper, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷heet闆嗗悎
- * 绛変环SQL: SELECT * FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param flipper 缈婚〉瀵硅薄 - * @param bean 杩囨护鏉′欢 - * - * @return Entity鐨勯泦鍚圕ompletableFuture - */ - default CompletableFuture> querySheetAsync(final Class clazz, final Flipper flipper, final FilterBean bean) { - return querySheetAsync(clazz, (SelectColumn) null, flipper, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷heet闆嗗悎
- * 绛変环SQL: SELECT * FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param flipper 缈婚〉瀵硅薄 - * @param node 杩囨护鏉′欢 - * - * @return Entity鐨勯泦鍚 - */ - default Sheet querySheet(final Class clazz, final Flipper flipper, final FilterNode node) { - return querySheet(clazz, (SelectColumn) null, flipper, node); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷heet闆嗗悎
- * 绛変环SQL: SELECT * FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param flipper 缈婚〉瀵硅薄 - * @param node 杩囨护鏉′欢 - * - * @return Entity鐨勯泦鍚圕ompletableFuture - */ - default CompletableFuture> querySheetAsync(final Class clazz, final Flipper flipper, final FilterNode node) { - return querySheetAsync(clazz, (SelectColumn) null, flipper, node); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷heet闆嗗悎
- * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param selects 鎸囧畾瀛楁 - * @param flipper 缈婚〉瀵硅薄 - * @param bean 杩囨护鏉′欢 - * - * @return Entity鐨勯泦鍚 - */ - default Sheet querySheet(final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean) { - return querySheet(clazz, selects, flipper, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷heet闆嗗悎
- * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param selects 鎸囧畾瀛楁 - * @param flipper 缈婚〉瀵硅薄 - * @param bean 杩囨护鏉′欢 - * - * @return Entity鐨勯泦鍚圕ompletableFuture - */ - default CompletableFuture> querySheetAsync(final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean) { - return querySheetAsync(clazz, selects, flipper, FilterNodeBean.createFilterNode(bean)); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷heet闆嗗悎
- * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param selects 鎸囧畾瀛楁 - * @param flipper 缈婚〉瀵硅薄 - * @param node 杩囨护鏉′欢 - * - * @return Entity鐨勯泦鍚 - */ - public Sheet querySheet(final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node); - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷heet闆嗗悎
- * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param selects 鎸囧畾瀛楁 - * @param flipper 缈婚〉瀵硅薄 - * @param node 杩囨护鏉′欢 - * - * @return Entity鐨勯泦鍚圕ompletableFuture - */ - public CompletableFuture> querySheetAsync(final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node); - -} +/* + * 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.source; + +import java.io.Serializable; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Stream; +import org.redkale.util.*; + +/** + * + * DataSource 涓烘暟鎹簱鎴栧唴瀛樻暟鎹簱鐨勬暟鎹簮锛屾彁渚涚被浼糐PA銆丠ibernate鐨勬帴鍙d笌鍔熻兘銆
+ * 杩斿洖绫诲瀷涓篊ompletableFuture鐨勬帴鍙d负寮傛鎺ュ彛
+ *
+ * 瀛楁绫诲瀷鏀寔锛
+ * 1銆乥oolean/Boolean
+ * 2銆乥yte/Byte
+ * 3銆乻hort/Short
+ * 4銆乧har/Character
+ * 5銆乮nt/Integer/AtomicInteger
+ * 6銆乴ong/Long/AtomicLong/LongAdder
+ * 7銆乫loat/Float
+ * 8銆乨ouble/Double
+ * 9銆乯ava.math.BigInteger
+ * 10銆乯ava.math.BigDecimal
+ * 11銆丼tring
+ * 12銆乥yte[]
+ * 13銆乯ava.time.LocalDate/java.sql.Date/java.util.Date
+ * 14銆乯ava.time.LocalTime/java.sql.Time
+ * 15銆乯ava.time.LocalDateTime/java.sql.Timestamp
+ * 16銆丣avaBean/鍏朵粬鍙疛SON鍖栫被鍨
+ * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@SuppressWarnings("unchecked") +public interface DataSource { + + /** + * 鑾峰彇鏁版嵁婧愮被鍨 + * + * @return String + */ + public String getType(); + + /** + * + * 鎻愬彇棰勭紪璇慐ntity绫伙紝涓昏鐢ㄤ簬native-image浣跨敤 + * + * @param 娉涘瀷 + * @param clazz Entity瀹炰綋绫 + */ + public void compile(Class clazz); + + //----------------------insertAsync----------------------------- + //insert 鏆傛椂涓嶆敮鎸丆ollection銆丼tream锛 鍥犱负瀛樺湪@RpcCall闂 + /** + * 鏂板璁板綍锛 澶氬璞″繀椤绘槸鍚屼竴涓狤ntity绫讳笖蹇呴』鍦ㄥ悓涓寮犺〃涓
+ * + * @param 娉涘瀷 + * @param entitys Entity瀵硅薄 + * + * @return 褰卞搷鐨勮褰曟潯鏁 + */ + public int insert(final T... entitys); + + /** + * 鏂板璁板綍锛 澶氬璞″繀椤绘槸鍚屼竴涓狤ntity绫讳笖蹇呴』鍦ㄥ悓涓寮犺〃涓
+ * + * @param 娉涘瀷 + * @param entitys Entity瀵硅薄 + * + * @return 褰卞搷鐨勮褰曟潯鏁 + */ + default int insert(final Collection entitys) { + if (entitys == null || entitys.isEmpty()) return 0; + return insert(entitys.toArray()); + } + + /** + * 鏂板璁板綍锛 澶氬璞″繀椤绘槸鍚屼竴涓狤ntity绫讳笖蹇呴』鍦ㄥ悓涓寮犺〃涓
+ * + * @param 娉涘瀷 + * @param entitys Entity瀵硅薄 + * + * @return 褰卞搷鐨勮褰曟潯鏁 + */ + default int insert(final Stream entitys) { + if (entitys == null) return 0; + return insert(entitys.toArray()); + } + + /** + * 鏂板璁板綍锛 澶氬璞″繀椤绘槸鍚屼竴涓狤ntity绫讳笖蹇呴』鍦ㄥ悓涓寮犺〃涓
+ * + * @param 娉涘瀷 + * @param entitys Entity瀵硅薄 + * + * @return CompletableFuture + */ + public CompletableFuture insertAsync(final T... entitys); + + /** + * 鏂板璁板綍锛 澶氬璞″繀椤绘槸鍚屼竴涓狤ntity绫讳笖蹇呴』鍦ㄥ悓涓寮犺〃涓
+ * + * @param 娉涘瀷 + * @param entitys Entity瀵硅薄 + * + * @return CompletableFuture + */ + default CompletableFuture insertAsync(final Collection entitys) { + if (entitys == null || entitys.isEmpty()) return CompletableFuture.completedFuture(0); + return insertAsync(entitys.toArray()); + } + + /** + * 鏂板璁板綍锛 澶氬璞″繀椤绘槸鍚屼竴涓狤ntity绫讳笖蹇呴』鍦ㄥ悓涓寮犺〃涓
+ * + * @param 娉涘瀷 + * @param entitys Entity瀵硅薄 + * + * @return CompletableFuture + */ + default CompletableFuture insertAsync(final Stream entitys) { + if (entitys == null) return CompletableFuture.completedFuture(0); + return insertAsync(entitys.toArray()); + } + + //-------------------------deleteAsync-------------------------- + /** + * 鍒犻櫎鎸囧畾涓婚敭鍊肩殑璁板綍锛 澶氬璞″繀椤绘槸鍚屼竴涓狤ntity绫讳笖蹇呴』鍦ㄥ悓涓寮犺〃涓
+ * 绛変环SQL: DELETE FROM {table} WHERE {primary} IN {values.id}
+ * + * @param 娉涘瀷 + * @param entitys Entity瀵硅薄 + * + * @return 褰卞搷鐨勮褰曟潯鏁 + */ + public int delete(final T... entitys); + + /** + * 鍒犻櫎鎸囧畾涓婚敭鍊肩殑璁板綍锛 澶氬璞″繀椤绘槸鍚屼竴涓狤ntity绫讳笖蹇呴』鍦ㄥ悓涓寮犺〃涓
+ * 绛変环SQL: DELETE FROM {table} WHERE {primary} IN {values.id}
+ * + * @param 娉涘瀷 + * @param entitys Entity瀵硅薄 + * + * @return 褰卞搷鐨勮褰曟潯鏁 + */ + default int delete(final Collection entitys) { + if (entitys == null || entitys.isEmpty()) return 0; + return delete(entitys.toArray()); + } + + /** + * 鍒犻櫎鎸囧畾涓婚敭鍊肩殑璁板綍锛 澶氬璞″繀椤绘槸鍚屼竴涓狤ntity绫讳笖蹇呴』鍦ㄥ悓涓寮犺〃涓
+ * 绛変环SQL: DELETE FROM {table} WHERE {primary} IN {values.id}
+ * + * @param 娉涘瀷 + * @param entitys Entity瀵硅薄 + * + * @return 褰卞搷鐨勮褰曟潯鏁 + */ + default int delete(final Stream entitys) { + if (entitys == null) return 0; + return delete(entitys.toArray()); + } + + /** + * 鍒犻櫎鎸囧畾涓婚敭鍊肩殑璁板綍锛 澶氬璞″繀椤绘槸鍚屼竴涓狤ntity绫讳笖蹇呴』鍦ㄥ悓涓寮犺〃涓
+ * 绛変环SQL: DELETE FROM {table} WHERE {primary} IN {values.id}
+ * + * @param 娉涘瀷 + * @param entitys Entity瀵硅薄 + * + * @return 褰卞搷鐨勮褰曟潯鏁癈ompletableFuture + */ + public CompletableFuture deleteAsync(final T... entitys); + + /** + * 鍒犻櫎鎸囧畾涓婚敭鍊肩殑璁板綍锛 澶氬璞″繀椤绘槸鍚屼竴涓狤ntity绫讳笖蹇呴』鍦ㄥ悓涓寮犺〃涓
+ * 绛変环SQL: DELETE FROM {table} WHERE {primary} IN {values.id}
+ * + * @param 娉涘瀷 + * @param entitys Entity瀵硅薄 + * + * @return 褰卞搷鐨勮褰曟潯鏁癈ompletableFuture + */ + default CompletableFuture deleteAsync(final Collection entitys) { + if (entitys == null || entitys.isEmpty()) return CompletableFuture.completedFuture(0); + return deleteAsync(entitys.toArray()); + } + + /** + * 鍒犻櫎鎸囧畾涓婚敭鍊肩殑璁板綍锛 澶氬璞″繀椤绘槸鍚屼竴涓狤ntity绫讳笖蹇呴』鍦ㄥ悓涓寮犺〃涓
+ * 绛変环SQL: DELETE FROM {table} WHERE {primary} IN {values.id}
+ * + * @param 娉涘瀷 + * @param entitys Entity瀵硅薄 + * + * @return 褰卞搷鐨勮褰曟潯鏁癈ompletableFuture + */ + default CompletableFuture deleteAsync(final Stream entitys) { + if (entitys == null) return CompletableFuture.completedFuture(0); + return deleteAsync(entitys.toArray()); + } + + /** + * 鍒犻櫎鎸囧畾涓婚敭鍊肩殑璁板綍,澶氫富閿煎繀椤诲湪鍚屼竴寮犺〃涓
+ * 绛変环SQL: DELETE FROM {table} WHERE {primary} IN {ids}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param pks 涓婚敭鍊 + * + * @return 褰卞搷鐨勮褰曟潯鏁 + */ + public int delete(final Class clazz, final Serializable... pks); + + /** + * 鍒犻櫎鎸囧畾涓婚敭鍊肩殑璁板綍,澶氫富閿煎繀椤诲湪鍚屼竴寮犺〃涓
+ * 绛変环SQL: DELETE FROM {table} WHERE {primary} IN {ids}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param pks 涓婚敭鍊 + * + * @return 褰卞搷鐨勮褰曟潯鏁癈ompletableFuture + */ + public CompletableFuture deleteAsync(final Class clazz, final Serializable... pks); + + /** + * 鍒犻櫎绗﹀悎杩囨护鏉′欢鐨勮褰
+ * 绛変环SQL: DELETE FROM {table} WHERE {filter node}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param node 杩囨护鏉′欢 + * + * @return 褰卞搷鐨勮褰曟潯鏁 + */ + default int delete(final Class clazz, final FilterNode node) { + return delete(clazz, (Flipper) null, node); + } + + /** + * 鍒犻櫎绗﹀悎杩囨护鏉′欢鐨勮褰
+ * 绛変环SQL: DELETE FROM {table} WHERE {filter node}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param node 杩囨护鏉′欢 + * + * @return 褰卞搷鐨勮褰曟潯鏁癈ompletableFuture + */ + default CompletableFuture deleteAsync(final Class clazz, final FilterNode node) { + return deleteAsync(clazz, (Flipper) null, node); + } + + /** + * 鍒犻櫎绗﹀悎杩囨护鏉′欢涓旀寚瀹氭渶澶у奖鍝嶆潯鏁扮殑璁板綍
+ * Flipper涓璷ffset瀛楁灏嗚蹇界暐
+ * 绛変环SQL: DELETE FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param flipper 缈婚〉瀵硅薄 + * @param node 杩囨护鏉′欢 + * + * @return 褰卞搷鐨勮褰曟潯鏁 + */ + public int delete(final Class clazz, final Flipper flipper, final FilterNode node); + + /** + * 鍒犻櫎绗﹀悎杩囨护鏉′欢涓旀寚瀹氭渶澶у奖鍝嶆潯鏁扮殑璁板綍
+ * Flipper涓璷ffset瀛楁灏嗚蹇界暐
+ * 绛変环SQL: DELETE FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param flipper 缈婚〉瀵硅薄 + * @param node 杩囨护鏉′欢 + * + * @return 褰卞搷鐨勮褰曟潯鏁癈ompletableFuture + */ + public CompletableFuture deleteAsync(final Class clazz, final Flipper flipper, final FilterNode node); + + //------------------------clearAsync--------------------------- + /** + * 娓呯┖琛
+ * 绛変环SQL: TRUNCATE TABLE {table}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * + * @return 褰卞搷鐨勮褰曟潯鏁 -1琛ㄧず琛ㄤ笉瀛樺湪 + */ + default int clearTable(final Class clazz) { + return clearTable(clazz, (FilterNode) null); + } + + /** + * 娓呯┖琛
+ * 绛変环SQL: TRUNCATE TABLE {table}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * + * @return 褰卞搷鐨勮褰曟潯鏁癈ompletableFuture -1琛ㄧず琛ㄤ笉瀛樺湪 + */ + default CompletableFuture clearTableAsync(final Class clazz) { + return clearTableAsync(clazz, (FilterNode) null); + } + + /** + * 娓呯┖琛
+ * 绛変环SQL: TRUNCATE TABLE {table}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param node 杩囨护鏉′欢 + * + * @return 褰卞搷鐨勮褰曟潯鏁 -1琛ㄧず琛ㄤ笉瀛樺湪 + */ + public int clearTable(final Class clazz, final FilterNode node); + + /** + * 娓呯┖琛
+ * 绛変环SQL: TRUNCATE TABLE {table}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param node 杩囨护鏉′欢 + * + * @return 褰卞搷鐨勮褰曟潯鏁癈ompletableFuture -1琛ㄧず琛ㄤ笉瀛樺湪 + */ + public CompletableFuture clearTableAsync(final Class clazz, final FilterNode node); + + //------------------------dropAsync--------------------------- + /** + * 鍒犻櫎琛
+ * 绛変环SQL: DROP TABLE {table}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * + * @return 褰卞搷鐨勮褰曟潯鏁 -1琛ㄧず琛ㄤ笉瀛樺湪 + */ + default int dropTable(final Class clazz) { + return dropTable(clazz, (FilterNode) null); + } + + /** + * 鍒犻櫎琛
+ * 绛変环SQL: DROP TABLE {table}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * + * @return 褰卞搷鐨勮褰曟潯鏁癈ompletableFuture -1琛ㄧず琛ㄤ笉瀛樺湪 + */ + default CompletableFuture dropTableAsync(final Class clazz) { + return dropTableAsync(clazz, (FilterNode) null); + } + + /** + * 鍒犻櫎琛
+ * 绛変环SQL: DROP TABLE {table}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param node 杩囨护鏉′欢 + * + * @return 褰卞搷鐨勮褰曟潯鏁 -1琛ㄧず琛ㄤ笉瀛樺湪 + */ + public int dropTable(final Class clazz, final FilterNode node); + + /** + * 鍒犻櫎琛
+ * 绛変环SQL: DROP TABLE {table}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param node 杩囨护鏉′欢 + * + * @return 褰卞搷鐨勮褰曟潯鏁癈ompletableFuture -1琛ㄧず琛ㄤ笉瀛樺湪 + */ + public CompletableFuture dropTableAsync(final Class clazz, final FilterNode node); + + //------------------------updateAsync--------------------------- + /** + * 鏇存柊璁板綍锛 澶氬璞″繀椤绘槸鍚屼竴涓狤ntity绫讳笖蹇呴』鍦ㄥ悓涓寮犺〃涓
+ * 绛変环SQL:
+ * UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id1}
+ * UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id2}
+ * ···
+ * + * @param 娉涘瀷 + * @param entitys Entity瀵硅薄 + * + * @return 褰卞搷鐨勮褰曟潯鏁 + */ + public int update(final T... entitys); + + /** + * 鏇存柊璁板綍锛 澶氬璞″繀椤绘槸鍚屼竴涓狤ntity绫讳笖蹇呴』鍦ㄥ悓涓寮犺〃涓
+ * 绛変环SQL:
+ * UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id1}
+ * UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id2}
+ * ···
+ * + * @param 娉涘瀷 + * @param entitys Entity瀵硅薄 + * + * @return 褰卞搷鐨勮褰曟潯鏁 + */ + default int update(final Collection entitys) { + if (entitys == null || entitys.isEmpty()) return 0; + return update(entitys.toArray()); + } + + /** + * 鏇存柊璁板綍锛 澶氬璞″繀椤绘槸鍚屼竴涓狤ntity绫讳笖蹇呴』鍦ㄥ悓涓寮犺〃涓
+ * 绛変环SQL:
+ * UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id1}
+ * UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id2}
+ * ···
+ * + * @param 娉涘瀷 + * @param entitys Entity瀵硅薄 + * + * @return 褰卞搷鐨勮褰曟潯鏁 + */ + default int update(final Stream entitys) { + if (entitys == null) return 0; + return update(entitys.toArray()); + } + + /** + * 鏇存柊璁板綍锛 澶氬璞″繀椤绘槸鍚屼竴涓狤ntity绫讳笖蹇呴』鍦ㄥ悓涓寮犺〃涓
+ * 绛変环SQL:
+ * UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id1}
+ * UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id2}
+ * ···
+ * + * @param 娉涘瀷 + * @param entitys Entity瀵硅薄 + * + * @return 褰卞搷鐨勮褰曟潯鏁癈ompletableFuture + */ + public CompletableFuture updateAsync(final T... entitys); + + /** + * 鏇存柊璁板綍锛 澶氬璞″繀椤绘槸鍚屼竴涓狤ntity绫讳笖蹇呴』鍦ㄥ悓涓寮犺〃涓
+ * 绛変环SQL:
+ * UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id1}
+ * UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id2}
+ * ···
+ * + * @param 娉涘瀷 + * @param entitys Entity瀵硅薄 + * + * @return 褰卞搷鐨勮褰曟潯鏁癈ompletableFuture + */ + default CompletableFuture updateAsync(final Collection entitys) { + if (entitys == null || entitys.isEmpty()) return CompletableFuture.completedFuture(0); + return updateAsync(entitys.toArray()); + } + + /** + * 鏇存柊璁板綍锛 澶氬璞″繀椤绘槸鍚屼竴涓狤ntity绫讳笖蹇呴』鍦ㄥ悓涓寮犺〃涓
+ * 绛変环SQL:
+ * UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id1}
+ * UPDATE {table} SET column1 = value1, column2 = value2, ··· WHERE {primary} = {id2}
+ * ···
+ * + * @param 娉涘瀷 + * @param entitys Entity瀵硅薄 + * + * @return 褰卞搷鐨勮褰曟潯鏁癈ompletableFuture + */ + default CompletableFuture updateAsync(final Stream entitys) { + if (entitys == null) return CompletableFuture.completedFuture(0); + return updateAsync(entitys.toArray()); + } + + /** + * 鏇存柊鍗曚釜璁板綍鐨勫崟涓瓧娈
+ * 娉ㄦ剰锛氬嵆浣垮瓧娈垫爣璁颁负@Column(updatable=false)涔熶細琚洿鏂
+ * 绛変环SQL: UPDATE {table} SET {column} = {value} WHERE {primary} = {id}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param pk 涓婚敭 + * @param column 寰呮洿鏂扮殑瀛楁鍚 + * @param value 鏇存柊鍊 + * + * @return 褰卞搷鐨勮褰曟潯鏁 + */ + public int updateColumn(final Class clazz, final Serializable pk, final String column, final Serializable value); + + /** + * 鏇存柊鍗曚釜璁板綍鐨勫崟涓瓧娈
+ * 娉ㄦ剰锛氬嵆浣垮瓧娈垫爣璁颁负@Column(updatable=false)涔熶細琚洿鏂
+ * 绛変环SQL: UPDATE {table} SET {column} = {value} WHERE {primary} = {id}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param pk 涓婚敭 + * @param column 寰呮洿鏂扮殑瀛楁鍚 + * @param value 鏇存柊鍊 + * + * @return 褰卞搷鐨勮褰曟潯鏁癈ompletableFuture + */ + public CompletableFuture updateColumnAsync(final Class clazz, final Serializable pk, final String column, final Serializable value); + + /** + * 鏇存柊绗﹀悎杩囨护鏉′欢璁板綍鐨勫崟涓瓧娈
+ * 娉ㄦ剰锛氬嵆浣垮瓧娈垫爣璁颁负@Column(updatable=false)涔熶細琚洿鏂
+ * 绛変环SQL: UPDATE {table} SET {column} = {value} WHERE {filter node}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param column 寰呮洿鏂扮殑瀛楁鍚 + * @param value 鏇存柊鍊 + * @param node 杩囨护鏉′欢 + * + * @return 褰卞搷鐨勮褰曟潯鏁 + */ + public int updateColumn(final Class clazz, final String column, final Serializable value, final FilterNode node); + + /** + * 鏇存柊绗﹀悎杩囨护鏉′欢璁板綍鐨勫崟涓瓧娈
+ * 娉ㄦ剰锛氬嵆浣垮瓧娈垫爣璁颁负@Column(updatable=false)涔熶細琚洿鏂
+ * 绛変环SQL: UPDATE {table} SET {column} = {value} WHERE {filter node}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param column 寰呮洿鏂扮殑瀛楁鍚 + * @param value 鏇存柊鍊 + * @param node 杩囨护鏉′欢 + * + * @return 褰卞搷鐨勮褰曟潯鏁癈ompletableFuture + */ + public CompletableFuture updateColumnAsync(final Class clazz, final String column, final Serializable value, final FilterNode node); + + /** + * 鏇存柊鎸囧畾涓婚敭鍊艰褰曠殑閮ㄥ垎瀛楁
+ * 瀛楁璧嬪兼搷浣滈夐」瑙 ColumnExpress
+ * 绛変环SQL: UPDATE {table} SET {column1} = {value1}, {column2} += {value2}, {column3} *= {value3}, ··· WHERE {filter node}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param pk 涓婚敭 + * @param values 鏇存柊瀛楁 + * + * @return 褰卞搷鐨勮褰曟潯鏁 + */ + public int updateColumn(final Class clazz, final Serializable pk, final ColumnValue... values); + + /** + * 鏇存柊鎸囧畾涓婚敭鍊艰褰曠殑閮ㄥ垎瀛楁
+ * 瀛楁璧嬪兼搷浣滈夐」瑙 ColumnExpress
+ * 绛変环SQL: UPDATE {table} SET {column1} = {value1}, {column2} += {value2}, {column3} *= {value3}, ··· WHERE {filter node}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param pk 涓婚敭 + * @param values 鏇存柊瀛楁 + * + * @return 褰卞搷鐨勮褰曟潯鏁癈ompletableFuture + */ + public CompletableFuture updateColumnAsync(final Class clazz, final Serializable pk, final ColumnValue... values); + + /** + * 鏇存柊绗﹀悎杩囨护鏉′欢璁板綍鐨勯儴鍒嗗瓧娈
+ * 瀛楁璧嬪兼搷浣滈夐」瑙 ColumnExpress
+ * 娉ㄦ剰锛欵ntity绫讳腑鏍囪涓@Column(updatable=false)涓嶄細琚洿鏂
+ * 绛変环SQL: UPDATE {table} SET {column1} = {value1}, {column2} += {value2}, {column3} *= {value3}, ··· WHERE {filter node}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param node 杩囨护鏉′欢 + * @param values 鏇存柊瀛楁 + * + * @return 褰卞搷鐨勮褰曟潯鏁 + */ + default int updateColumn(final Class clazz, final FilterNode node, final ColumnValue... values) { + return updateColumn(clazz, node, (Flipper) null, values); + } + + /** + * 鏇存柊绗﹀悎杩囨护鏉′欢璁板綍鐨勯儴鍒嗗瓧娈
+ * 瀛楁璧嬪兼搷浣滈夐」瑙 ColumnExpress
+ * 娉ㄦ剰锛欵ntity绫讳腑鏍囪涓@Column(updatable=false)涓嶄細琚洿鏂
+ * 绛変环SQL: UPDATE {table} SET {column1} = {value1}, {column2} += {value2}, {column3} *= {value3}, ··· WHERE {filter node}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param node 杩囨护鏉′欢 + * @param values 鏇存柊瀛楁 + * + * @return 褰卞搷鐨勮褰曟潯鏁癈ompletableFuture + */ + default CompletableFuture updateColumnAsync(final Class clazz, final FilterNode node, final ColumnValue... values) { + return updateColumnAsync(clazz, node, (Flipper) null, values); + } + + /** + * 鏇存柊绗﹀悎杩囨护鏉′欢鐨勮褰曠殑鎸囧畾瀛楁
+ * Flipper涓璷ffset瀛楁灏嗚蹇界暐
+ * 娉ㄦ剰锛欵ntity绫讳腑鏍囪涓@Column(updatable=false)涓嶄細琚洿鏂
+ * 绛変环SQL: UPDATE {table} SET {column1} = {value1}, {column2} += {value2}, {column3} *= {value3}, ··· WHERE {filter node} ORDER BY {flipper.sort}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param node 杩囨护鏉′欢 + * @param flipper 缈婚〉瀵硅薄 + * @param values 鏇存柊瀛楁 + * + * @return 褰卞搷鐨勮褰曟潯鏁 + */ + public int updateColumn(final Class clazz, final FilterNode node, final Flipper flipper, final ColumnValue... values); + + /** + * 鏇存柊绗﹀悎杩囨护鏉′欢鐨勮褰曠殑鎸囧畾瀛楁
+ * Flipper涓璷ffset瀛楁灏嗚蹇界暐
+ * 娉ㄦ剰锛欵ntity绫讳腑鏍囪涓@Column(updatable=false)涓嶄細琚洿鏂
+ * 绛変环SQL: UPDATE {table} SET {column1} = {value1}, {column2} += {value2}, {column3} *= {value3}, ··· WHERE {filter node} ORDER BY {flipper.sort}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param node 杩囨护鏉′欢 + * @param flipper 缈婚〉瀵硅薄 + * @param values 鏇存柊瀛楁 + * + * @return 褰卞搷鐨勮褰曟潯鏁癈ompletableFuture + */ + public CompletableFuture updateColumnAsync(final Class clazz, final FilterNode node, final Flipper flipper, final ColumnValue... values); + + /** + * 鏇存柊鍗曚釜璁板綍鐨勬寚瀹氬瓧娈
+ * 娉ㄦ剰锛欵ntity绫讳腑鏍囪涓@Column(updatable=false)涓嶄細琚洿鏂
+ * 绛変环SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· WHERE {primary} = {bean.id}
+ * + * @param Entity娉涘瀷 + * @param entity 寰呮洿鏂扮殑Entity瀵硅薄 + * @param columns 闇鏇存柊鐨勫瓧娈靛悕 + * + * @return 褰卞搷鐨勮褰曟潯鏁 + */ + default int updateColumn(final T entity, final String... columns) { + return updateColumn(entity, (FilterNode) null, columns); + } + + /** + * 鏇存柊鍗曚釜璁板綍鐨勬寚瀹氬瓧娈
+ * 娉ㄦ剰锛欵ntity绫讳腑鏍囪涓@Column(updatable=false)涓嶄細琚洿鏂
+ * 绛変环SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· WHERE {primary} = {bean.id}
+ * + * @param Entity娉涘瀷 + * @param entity 寰呮洿鏂扮殑Entity瀵硅薄 + * @param columns 闇鏇存柊鐨勫瓧娈靛悕 + * + * @return 褰卞搷鐨勮褰曟潯鏁癈ompletableFuture + */ + default CompletableFuture updateColumnAsync(final T entity, final String... columns) { + return updateColumnAsync(entity, (FilterNode) null, columns); + } + + /** + * 鏇存柊绗﹀悎杩囨护鏉′欢璁板綍鐨勬寚瀹氬瓧娈
+ * 娉ㄦ剰锛欵ntity绫讳腑鏍囪涓@Column(updatable=false)涓嶄細琚洿鏂
+ * 绛変环SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· WHERE {filter node}
+ * + * @param Entity娉涘瀷 + * @param entity 寰呮洿鏂扮殑Entity瀵硅薄 + * @param node 杩囨护鏉′欢 + * @param columns 闇鏇存柊鐨勫瓧娈靛悕 + * + * @return 褰卞搷鐨勮褰曟潯鏁 + */ + public int updateColumn(final T entity, final FilterNode node, final String... columns); + + /** + * 鏇存柊绗﹀悎杩囨护鏉′欢璁板綍鐨勬寚瀹氬瓧娈
+ * 娉ㄦ剰锛欵ntity绫讳腑鏍囪涓@Column(updatable=false)涓嶄細琚洿鏂
+ * 绛変环SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· WHERE {filter node}
+ * + * @param Entity娉涘瀷 + * @param entity 寰呮洿鏂扮殑Entity瀵硅薄 + * @param node 杩囨护鏉′欢 + * @param columns 闇鏇存柊鐨勫瓧娈靛悕 + * + * @return 褰卞搷鐨勮褰曟潯鏁癈ompletableFuture + */ + public CompletableFuture updateColumnAsync(final T entity, final FilterNode node, final String... columns); + + /** + * 鏇存柊鍗曚釜璁板綍鐨勬寚瀹氬瓧娈
+ * 娉ㄦ剰锛欵ntity绫讳腑鏍囪涓@Column(updatable=false)涓嶄細琚洿鏂
+ * 绛変环SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· WHERE {primary} = {bean.id}
+ * + * @param Entity娉涘瀷 + * @param entity 寰呮洿鏂扮殑Entity瀵硅薄 + * @param selects 鎸囧畾瀛楁 + * + * @return 褰卞搷鐨勮褰曟潯鏁 + */ + default int updateColumn(final T entity, final SelectColumn selects) { + return updateColumn(entity, (FilterNode) null, selects); + } + + /** + * 鏇存柊鍗曚釜璁板綍鐨勬寚瀹氬瓧娈
+ * 娉ㄦ剰锛欵ntity绫讳腑鏍囪涓@Column(updatable=false)涓嶄細琚洿鏂
+ * 绛変环SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· WHERE {primary} = {bean.id}
+ * + * @param Entity娉涘瀷 + * @param entity 寰呮洿鏂扮殑Entity瀵硅薄 + * @param selects 鎸囧畾瀛楁 + * + * @return 褰卞搷鐨勮褰曟潯鏁癈ompletableFuture + */ + default CompletableFuture updateColumnAsync(final T entity, final SelectColumn selects) { + return updateColumnAsync(entity, (FilterNode) null, selects); + } + + /** + * 鏇存柊绗﹀悎杩囨护鏉′欢璁板綍鐨勬寚瀹氬瓧娈
+ * 娉ㄦ剰锛欵ntity绫讳腑鏍囪涓@Column(updatable=false)涓嶄細琚洿鏂
+ * 绛変环SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· WHERE {filter node}
+ * + * @param Entity娉涘瀷 + * @param entity 寰呮洿鏂扮殑Entity瀵硅薄 + * @param node 杩囨护鏉′欢 + * @param selects 鎸囧畾瀛楁 + * + * @return 褰卞搷鐨勮褰曟潯鏁 + */ + public int updateColumn(final T entity, final FilterNode node, final SelectColumn selects); + + /** + * 鏇存柊绗﹀悎杩囨护鏉′欢璁板綍鐨勬寚瀹氬瓧娈
+ * 娉ㄦ剰锛欵ntity绫讳腑鏍囪涓@Column(updatable=false)涓嶄細琚洿鏂
+ * 绛変环SQL: UPDATE {table} SET {column1} = {value1}, {column2} = {value2}, {column3} = {value3}, ··· WHERE {filter node}
+ * + * @param Entity娉涘瀷 + * @param entity 寰呮洿鏂扮殑Entity瀵硅薄 + * @param node 杩囨护鏉′欢 + * @param selects 鎸囧畾瀛楁 + * + * @return 褰卞搷鐨勮褰曟潯鏁癈ompletableFuture + */ + public CompletableFuture updateColumnAsync(final T entity, final FilterNode node, final SelectColumn selects); + + //############################################# 鏌ヨ鎺ュ彛 ############################################# + //-----------------------getXXXXResult----------------------------- + /** + * 鑾峰彇绗﹀悎杩囨护鏉′欢璁板綍鐨勮仛鍚堢粨鏋, 鏃犵粨鏋滆繑鍥瀗ull
+ * 绛変环SQL: SELECT FUNC{column} FROM {table}
+ * 濡 getNumberResultAsync(User.class, FilterFunc.COUNT, null) 绛変环浜: SELECT COUNT(*) FROM {table}
+ * + * @param entityClass Entity绫 + * @param func 鑱氬悎鍑芥暟 + * @param column 鎸囧畾瀛楁 + * + * @return 鑱氬悎缁撴灉 + */ + default Number getNumberResult(final Class entityClass, final FilterFunc func, final String column) { + return getNumberResult(entityClass, func, null, column, (FilterNode) null); + } + + /** + * 鑾峰彇绗﹀悎杩囨护鏉′欢璁板綍鐨勮仛鍚堢粨鏋, 鏃犵粨鏋滆繑鍥瀗ull
+ * 绛変环SQL: SELECT FUNC{column} FROM {table}
+ * 濡 getNumberResultAsync(User.class, FilterFunc.COUNT, null) 绛変环浜: SELECT COUNT(*) FROM {table}
+ * + * @param entityClass Entity绫 + * @param func 鑱氬悎鍑芥暟 + * @param column 鎸囧畾瀛楁 + * + * @return 鑱氬悎缁撴灉CompletableFuture + */ + default CompletableFuture getNumberResultAsync(final Class entityClass, final FilterFunc func, final String column) { + return getNumberResultAsync(entityClass, func, null, column, (FilterNode) null); + } + + /** + * 鑾峰彇绗﹀悎杩囨护鏉′欢璁板綍鐨勮仛鍚堢粨鏋, 鏃犵粨鏋滆繑鍥瀗ull
+ * 绛変环SQL: SELECT FUNC{column} FROM {table} WHERE {filter bean}
+ * 濡 getNumberResultAsync(User.class, FilterFunc.COUNT, null, (FilterBean)null) 绛変环浜: SELECT COUNT(*) FROM {table}
+ * + * @param entityClass Entity绫 + * @param func 鑱氬悎鍑芥暟 + * @param column 鎸囧畾瀛楁 + * @param bean 杩囨护鏉′欢 + * + * @return 鑱氬悎缁撴灉 + */ + default Number getNumberResult(final Class entityClass, final FilterFunc func, final String column, final FilterBean bean) { + return getNumberResult(entityClass, func, column, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鑾峰彇绗﹀悎杩囨护鏉′欢璁板綍鐨勮仛鍚堢粨鏋, 鏃犵粨鏋滆繑鍥瀗ull
+ * 绛変环SQL: SELECT FUNC{column} FROM {table} WHERE {filter bean}
+ * 濡 getNumberResultAsync(User.class, FilterFunc.COUNT, null, (FilterBean)null) 绛変环浜: SELECT COUNT(*) FROM {table}
+ * + * @param entityClass Entity绫 + * @param func 鑱氬悎鍑芥暟 + * @param column 鎸囧畾瀛楁 + * @param bean 杩囨护鏉′欢 + * + * @return 鑱氬悎缁撴灉CompletableFuture + */ + default CompletableFuture getNumberResultAsync(final Class entityClass, final FilterFunc func, final String column, final FilterBean bean) { + return getNumberResultAsync(entityClass, func, column, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鑾峰彇绗﹀悎杩囨护鏉′欢璁板綍鐨勮仛鍚堢粨鏋, 鏃犵粨鏋滆繑鍥瀗ull
+ * 绛変环SQL: SELECT FUNC{column} FROM {table} WHERE {filter node}
+ * 濡 getNumberResultAsync(User.class, FilterFunc.MAX, "createtime", (FilterNode)null) 绛変环浜: SELECT MAX(createtime) FROM {table}
+ * + * @param entityClass Entity绫 + * @param func 鑱氬悎鍑芥暟 + * @param column 鎸囧畾瀛楁 + * @param node 杩囨护鏉′欢 + * + * @return 鑱氬悎缁撴灉 + */ + default Number getNumberResult(final Class entityClass, final FilterFunc func, final String column, final FilterNode node) { + return getNumberResult(entityClass, func, null, column, node); + } + + /** + * 鑾峰彇绗﹀悎杩囨护鏉′欢璁板綍鐨勮仛鍚堢粨鏋, 鏃犵粨鏋滆繑鍥瀗ull
+ * 绛変环SQL: SELECT FUNC{column} FROM {table} WHERE {filter node}
+ * 濡 getNumberResultAsync(User.class, FilterFunc.MAX, "createtime", (FilterNode)null) 绛変环浜: SELECT MAX(createtime) FROM {table}
+ * + * @param entityClass Entity绫 + * @param func 鑱氬悎鍑芥暟 + * @param column 鎸囧畾瀛楁 + * @param node 杩囨护鏉′欢 + * + * @return 鑱氬悎缁撴灉 + */ + default CompletableFuture getNumberResultAsync(final Class entityClass, final FilterFunc func, final String column, final FilterNode node) { + return getNumberResultAsync(entityClass, func, null, column, node); + } + + /** + * 鑾峰彇绗﹀悎杩囨护鏉′欢璁板綍鐨勮仛鍚堢粨鏋, 鏃犵粨鏋滆繑鍥為粯璁ゅ
+ * 绛変环SQL: SELECT FUNC{column} FROM {table}
+ * 濡 getNumberResultAsync(User.class, FilterFunc.MAX, "createtime") 绛変环浜: SELECT MAX(createtime) FROM {table}
+ * + * @param entityClass Entity绫 + * @param func 鑱氬悎鍑芥暟 + * @param defVal 榛樿鍊 + * @param column 鎸囧畾瀛楁 + * + * @return 鑱氬悎缁撴灉 + */ + default Number getNumberResult(final Class entityClass, final FilterFunc func, final Number defVal, final String column) { + return getNumberResult(entityClass, func, defVal, column, (FilterNode) null); + } + + /** + * 鑾峰彇绗﹀悎杩囨护鏉′欢璁板綍鐨勮仛鍚堢粨鏋, 鏃犵粨鏋滆繑鍥為粯璁ゅ
+ * 绛変环SQL: SELECT FUNC{column} FROM {table}
+ * 濡 getNumberResultAsync(User.class, FilterFunc.MAX, "createtime") 绛変环浜: SELECT MAX(createtime) FROM {table}
+ * + * @param entityClass Entity绫 + * @param func 鑱氬悎鍑芥暟 + * @param defVal 榛樿鍊 + * @param column 鎸囧畾瀛楁 + * + * @return 鑱氬悎缁撴灉CompletableFuture + */ + default CompletableFuture getNumberResultAsync(final Class entityClass, final FilterFunc func, final Number defVal, final String column) { + return getNumberResultAsync(entityClass, func, defVal, column, (FilterNode) null); + } + + /** + * 鑾峰彇绗﹀悎杩囨护鏉′欢璁板綍鐨勮仛鍚堢粨鏋, 鏃犵粨鏋滆繑鍥為粯璁ゅ
+ * 绛変环SQL: SELECT FUNC{column} FROM {table} WHERE {filter bean}
+ * 濡 getNumberResultAsync(User.class, FilterFunc.MAX, "createtime", (FilterNode)null) 绛変环浜: SELECT MAX(createtime) FROM {table}
+ * + * @param entityClass Entity绫 + * @param func 鑱氬悎鍑芥暟 + * @param defVal 榛樿鍊 + * @param column 鎸囧畾瀛楁 + * @param bean 杩囨护鏉′欢 + * + * @return 鑱氬悎缁撴灉 + */ + default Number getNumberResult(final Class entityClass, final FilterFunc func, final Number defVal, final String column, final FilterBean bean) { + return getNumberResult(entityClass, func, defVal, column, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鑾峰彇绗﹀悎杩囨护鏉′欢璁板綍鐨勮仛鍚堢粨鏋, 鏃犵粨鏋滆繑鍥為粯璁ゅ
+ * 绛変环SQL: SELECT FUNC{column} FROM {table} WHERE {filter bean}
+ * 濡 getNumberResultAsync(User.class, FilterFunc.MAX, "createtime", (FilterNode)null) 绛変环浜: SELECT MAX(createtime) FROM {table}
+ * + * @param entityClass Entity绫 + * @param func 鑱氬悎鍑芥暟 + * @param defVal 榛樿鍊 + * @param column 鎸囧畾瀛楁 + * @param bean 杩囨护鏉′欢 + * + * @return 鑱氬悎缁撴灉CompletableFuture + */ + default CompletableFuture getNumberResultAsync(final Class entityClass, final FilterFunc func, final Number defVal, final String column, final FilterBean bean) { + return getNumberResultAsync(entityClass, func, defVal, column, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鑾峰彇绗﹀悎杩囨护鏉′欢璁板綍鐨勮仛鍚堢粨鏋, 鏃犵粨鏋滆繑鍥為粯璁ゅ
+ * 绛変环SQL: SELECT FUNC{column} FROM {table} WHERE {filter node}
+ * 濡 getNumberResultAsync(User.class, FilterFunc.MAX, "createtime", (FilterNode)null) 绛変环浜: SELECT MAX(createtime) FROM {table}
+ * + * @param entityClass Entity绫 + * @param func 鑱氬悎鍑芥暟 + * @param defVal 榛樿鍊 + * @param column 鎸囧畾瀛楁 + * @param node 杩囨护鏉′欢 + * + * @return 鑱氬悎缁撴灉 + */ + public Number getNumberResult(final Class entityClass, final FilterFunc func, final Number defVal, final String column, final FilterNode node); + + /** + * 鑾峰彇绗﹀悎杩囨护鏉′欢璁板綍鐨勮仛鍚堢粨鏋, 鏃犵粨鏋滆繑鍥為粯璁ゅ
+ * 绛変环SQL: SELECT FUNC{column} FROM {table} WHERE {filter node}
+ * 濡 getNumberResultAsync(User.class, FilterFunc.MAX, "createtime", (FilterNode)null) 绛変环浜: SELECT MAX(createtime) FROM {table}
+ * + * @param entityClass Entity绫 + * @param func 鑱氬悎鍑芥暟 + * @param defVal 榛樿鍊 + * @param column 鎸囧畾瀛楁 + * @param node 杩囨护鏉′欢 + * + * @return 鑱氬悎缁撴灉CompletableFuture + */ + public CompletableFuture getNumberResultAsync(final Class entityClass, final FilterFunc func, final Number defVal, final String column, final FilterNode node); + + /** + * 鑾峰彇绗﹀悎杩囨护鏉′欢璁板綍鐨勮仛鍚堢粨鏋淢ap
+ * 绛変环SQL: SELECT FUNC1{column1}, FUNC2{column2}, ··· FROM {table}
+ * 濡 getNumberMapAsync(User.class, new FilterFuncColumn(FilterFunc.MAX, "createtime")) 绛変环浜: SELECT MAX(createtime) FROM {table}
+ * + * @param Number + * @param entityClass Entity绫 + * @param columns 鑱氬悎瀛楁 + * + * @return 鑱氬悎缁撴灉Map + */ + default Map getNumberMap(final Class entityClass, final FilterFuncColumn... columns) { + return getNumberMap(entityClass, (FilterNode) null, columns); + } + + /** + * 鑾峰彇绗﹀悎杩囨护鏉′欢璁板綍鐨勮仛鍚堢粨鏋淢ap
+ * 绛変环SQL: SELECT FUNC1{column1}, FUNC2{column2}, ··· FROM {table}
+ * 濡 getNumberMapAsync(User.class, new FilterFuncColumn(FilterFunc.MAX, "createtime")) 绛変环浜: SELECT MAX(createtime) FROM {table}
+ * + * @param Number + * @param entityClass Entity绫 + * @param columns 鑱氬悎瀛楁 + * + * @return 鑱氬悎缁撴灉Map CompletableFuture + */ + default CompletableFuture> getNumberMapAsync(final Class entityClass, final FilterFuncColumn... columns) { + return getNumberMapAsync(entityClass, (FilterNode) null, columns); + } + + /** + * 鑾峰彇绗﹀悎杩囨护鏉′欢璁板綍鐨勮仛鍚堢粨鏋淢ap
+ * 绛変环SQL: SELECT FUNC1{column1}, FUNC2{column2}, ··· FROM {table} WHERE {filter bean}
+ * 濡 getNumberMapAsync(User.class, (FilterBean)null, new FilterFuncColumn(FilterFunc.MAX, "createtime")) 绛変环浜: SELECT MAX(createtime) FROM {table}
+ * + * @param Number + * @param entityClass Entity绫 + * @param bean 杩囨护鏉′欢 + * @param columns 鑱氬悎瀛楁 + * + * @return 鑱氬悎缁撴灉Map + */ + default Map getNumberMap(final Class entityClass, final FilterBean bean, final FilterFuncColumn... columns) { + return getNumberMap(entityClass, FilterNodeBean.createFilterNode(bean), columns); + } + + /** + * 鑾峰彇绗﹀悎杩囨护鏉′欢璁板綍鐨勮仛鍚堢粨鏋淢ap
+ * 绛変环SQL: SELECT FUNC1{column1}, FUNC2{column2}, ··· FROM {table} WHERE {filter bean}
+ * 濡 getNumberMapAsync(User.class, (FilterBean)null, new FilterFuncColumn(FilterFunc.MAX, "createtime")) 绛変环浜: SELECT MAX(createtime) FROM {table}
+ * + * @param Number + * @param entityClass Entity绫 + * @param bean 杩囨护鏉′欢 + * @param columns 鑱氬悎瀛楁 + * + * @return 鑱氬悎缁撴灉Map CompletableFuture + */ + default CompletableFuture> getNumberMapAsync(final Class entityClass, final FilterBean bean, final FilterFuncColumn... columns) { + return getNumberMapAsync(entityClass, FilterNodeBean.createFilterNode(bean), columns); + } + + /** + * 鑾峰彇绗﹀悎杩囨护鏉′欢璁板綍鐨勮仛鍚堢粨鏋淢ap
+ * 绛変环SQL: SELECT FUNC1{column1}, FUNC2{column2}, ··· FROM {table} WHERE {filter node}
+ * 濡 getNumberMapAsync(User.class, (FilterNode)null, new FilterFuncColumn(FilterFunc.MAX, "createtime")) 绛変环浜: SELECT MAX(createtime) FROM {table}
+ * + * @param Number + * @param entityClass Entity绫 + * @param node 杩囨护鏉′欢 + * @param columns 鑱氬悎瀛楁 + * + * @return 鑱氬悎缁撴灉Map + */ + public Map getNumberMap(final Class entityClass, final FilterNode node, final FilterFuncColumn... columns); + + /** + * 鑾峰彇绗﹀悎杩囨护鏉′欢璁板綍鐨勮仛鍚堢粨鏋淢ap
+ * 绛変环SQL: SELECT FUNC1{column1}, FUNC2{column2}, ··· FROM {table} WHERE {filter node}
+ * 濡 getNumberMapAsync(User.class, (FilterNode)null, new FilterFuncColumn(FilterFunc.MAX, "createtime")) 绛変环浜: SELECT MAX(createtime) FROM {table}
+ * + * @param Number + * @param entityClass Entity绫 + * @param node 杩囨护鏉′欢 + * @param columns 鑱氬悎瀛楁 + * + * @return 鑱氬悎缁撴灉Map + */ + public CompletableFuture> getNumberMapAsync(final Class entityClass, final FilterNode node, final FilterFuncColumn... columns); + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凣ROUP BY鑱氬悎缁撴灉Map
+ * 绛変环SQL: SELECT keyColumn, FUNC{funcColumn} FROM {table} GROUP BY {keyColumn}
+ * 濡 queryColumnMapAsync(User.class, "name", FilterFunc.MAX, "createtime") 绛変环浜: SELECT name, MAX(createtime) FROM user GROUP BY name
+ * + * @param Entity娉涘瀷 + * @param Key瀛楁鐨勬暟鎹被鍨 + * @param Number + * @param entityClass Entity绫 + * @param keyColumn Key瀛楁 + * @param func 鑱氬悎鍑芥暟 + * @param funcColumn 鑱氬悎瀛楁 + * + * @return 鑱氬悎缁撴灉Map + */ + default Map queryColumnMap(final Class entityClass, final String keyColumn, final FilterFunc func, final String funcColumn) { + return queryColumnMap(entityClass, keyColumn, func, funcColumn, (FilterNode) null); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凣ROUP BY鑱氬悎缁撴灉Map
+ * 绛変环SQL: SELECT keyColumn, FUNC{funcColumn} FROM {table} GROUP BY {keyColumn}
+ * 濡 queryColumnMapAsync(User.class, "name", FilterFunc.MAX, "createtime") 绛変环浜: SELECT name, MAX(createtime) FROM user GROUP BY name
+ * + * @param Entity娉涘瀷 + * @param Key瀛楁鐨勬暟鎹被鍨 + * @param Number + * @param entityClass Entity绫 + * @param keyColumn Key瀛楁 + * @param func 鑱氬悎鍑芥暟 + * @param funcColumn 鑱氬悎瀛楁 + * + * @return 鑱氬悎缁撴灉Map CompletableFuture + */ + default CompletableFuture> queryColumnMapAsync(final Class entityClass, final String keyColumn, final FilterFunc func, final String funcColumn) { + return queryColumnMapAsync(entityClass, keyColumn, func, funcColumn, (FilterNode) null); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凣ROUP BY鑱氬悎缁撴灉Map
+ * 绛変环SQL: SELECT keyColumn, FUNC{funcColumn} FROM {table} WHERE {filter bean} GROUP BY {keyColumn}
+ * 濡 queryColumnMapAsync(User.class, "name", FilterFunc.MAX, "createtime", (FilterBean)null) 绛変环浜: SELECT name, MAX(createtime) FROM user GROUP BY name
+ * + * @param Entity娉涘瀷 + * @param Key瀛楁鐨勬暟鎹被鍨 + * @param Number + * @param entityClass Entity绫 + * @param keyColumn Key瀛楁 + * @param func 鑱氬悎鍑芥暟 + * @param funcColumn 鑱氬悎瀛楁 + * @param bean 杩囨护鏉′欢 + * + * @return 鑱氬悎缁撴灉Map + */ + default Map queryColumnMap(final Class entityClass, final String keyColumn, final FilterFunc func, final String funcColumn, final FilterBean bean) { + return queryColumnMap(entityClass, keyColumn, func, funcColumn, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凣ROUP BY鑱氬悎缁撴灉Map
+ * 绛変环SQL: SELECT keyColumn, FUNC{funcColumn} FROM {table} WHERE {filter bean} GROUP BY {keyColumn}
+ * 濡 queryColumnMapAsync(User.class, "name", FilterFunc.MAX, "createtime", (FilterBean)null) 绛変环浜: SELECT name, MAX(createtime) FROM user GROUP BY name
+ * + * @param Entity娉涘瀷 + * @param Key瀛楁鐨勬暟鎹被鍨 + * @param Number + * @param entityClass Entity绫 + * @param keyColumn Key瀛楁 + * @param func 鑱氬悎鍑芥暟 + * @param funcColumn 鑱氬悎瀛楁 + * @param bean 杩囨护鏉′欢 + * + * @return 鑱氬悎缁撴灉Map CompletableFuture + */ + default CompletableFuture> queryColumnMapAsync(final Class entityClass, final String keyColumn, final FilterFunc func, final String funcColumn, final FilterBean bean) { + return queryColumnMapAsync(entityClass, keyColumn, func, funcColumn, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凣ROUP BY鑱氬悎缁撴灉Map
+ * 绛変环SQL: SELECT keyColumn, FUNC{funcColumn} FROM {table} WHERE {filter node} GROUP BY {keyColumn}
+ * 濡 queryColumnMapAsync(User.class, "name", FilterFunc.MAX, "createtime", (FilterNode)null) 绛変环浜: SELECT name, MAX(createtime) FROM user GROUP BY name
+ * + * @param Entity娉涘瀷 + * @param Key瀛楁鐨勬暟鎹被鍨 + * @param Number + * @param entityClass Entity绫 + * @param keyColumn Key瀛楁 + * @param func 鑱氬悎鍑芥暟 + * @param funcColumn 鑱氬悎瀛楁 + * @param node 杩囨护鏉′欢 + * + * @return 鑱氬悎缁撴灉Map + */ + public Map queryColumnMap(final Class entityClass, final String keyColumn, final FilterFunc func, final String funcColumn, final FilterNode node); + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凣ROUP BY鑱氬悎缁撴灉Map
+ * 绛変环SQL: SELECT keyColumn, FUNC{funcColumn} FROM {table} WHERE {filter node} GROUP BY {keyColumn}
+ * 濡 queryColumnMapAsync(User.class, "name", FilterFunc.MAX, "createtime", (FilterNode)null) 绛変环浜: SELECT name, MAX(createtime) FROM user GROUP BY name
+ * + * @param Entity娉涘瀷 + * @param Key瀛楁鐨勬暟鎹被鍨 + * @param Number + * @param entityClass Entity绫 + * @param keyColumn Key瀛楁 + * @param func 鑱氬悎鍑芥暟 + * @param funcColumn 鑱氬悎瀛楁 + * @param node 杩囨护鏉′欢 + * + * @return 鑱氬悎缁撴灉Map CompletableFuture + */ + public CompletableFuture> queryColumnMapAsync(final Class entityClass, final String keyColumn, final FilterFunc func, final String funcColumn, final FilterNode node); + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凣ROUP BY鑱氬悎缁撴灉Map
+ * 绛変环SQL: SELECT col1, FUNC{funcColumn1}, FUNC{funcColumn2} FROM {table} WHERE GROUP BY {col1}
+ * 濡 queryColumnMapAsync(OrderRecord.class, Utility.ofArray(ColumnNodeValue.div(ColumnFuncNode.sum("money"), 100), ColumnFuncNode.avg(ColumnNodeValue.dec("money", 20)))), "targetid") + * 绛変环浜: SELECT targetid, SUM(money) / 100, AVG(money - 20) FROM orderrecord GROUP BY targetid
+ * + * @param Entity娉涘瀷 + * @param Key瀛楁鐨勬暟鎹被鍨 + * @param Number + * @param entityClass Entity绫 + * @param funcNodes ColumnNode[] + * @param groupByColumn GROUP BY瀛楁 + * + * @return 鑱氬悎缁撴灉Map CompletableFuture + */ + default Map queryColumnMap(final Class entityClass, final ColumnNode[] funcNodes, final String groupByColumn) { + return queryColumnMap(entityClass, funcNodes, groupByColumn, (FilterNode) null); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凣ROUP BY鑱氬悎缁撴灉Map
+ * 绛変环SQL: SELECT col1, FUNC{funcColumn1}, FUNC{funcColumn2} FROM {table} GROUP BY {col1}
+ * 濡 queryColumnMapAsync(OrderRecord.class, Utility.ofArray(ColumnNodeValue.div(ColumnFuncNode.sum("money"), 100), ColumnFuncNode.avg(ColumnNodeValue.dec("money", 20)))), "targetid") + * 绛変环浜: SELECT targetid, SUM(money) / 100, AVG(money - 20) FROM orderrecord GROUP BY targetid
+ * + * @param Entity娉涘瀷 + * @param Key瀛楁鐨勬暟鎹被鍨 + * @param Number + * @param entityClass Entity绫 + * @param funcNodes ColumnNode[] + * @param groupByColumn GROUP BY瀛楁 + * + * @return 鑱氬悎缁撴灉Map CompletableFuture + */ + default CompletableFuture> queryColumnMapAsync(final Class entityClass, final ColumnNode[] funcNodes, final String groupByColumn) { + return queryColumnMapAsync(entityClass, funcNodes, groupByColumn, (FilterNode) null); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凣ROUP BY鑱氬悎缁撴灉Map
+ * 绛変环SQL: SELECT col1, FUNC{funcColumn1}, FUNC{funcColumn2} FROM {table} WHERE {filter bean} GROUP BY {col1}
+ * 濡 queryColumnMapAsync(OrderRecord.class, Utility.ofArray(ColumnNodeValue.div(ColumnFuncNode.sum("money"), 100), ColumnFuncNode.avg(ColumnNodeValue.dec("money", 20)))), "targetid", (FilterBean)null) + * 绛変环浜: SELECT targetid, SUM(money) / 100, AVG(money - 20) FROM orderrecord GROUP BY targetid
+ * + * @param Entity娉涘瀷 + * @param Key瀛楁鐨勬暟鎹被鍨 + * @param Number + * @param entityClass Entity绫 + * @param funcNodes ColumnNode[] + * @param groupByColumn GROUP BY瀛楁 + * @param bean 杩囨护鏉′欢 + * + * @return 鑱氬悎缁撴灉Map CompletableFuture + */ + default Map queryColumnMap(final Class entityClass, final ColumnNode[] funcNodes, final String groupByColumn, final FilterBean bean) { + return queryColumnMap(entityClass, funcNodes, groupByColumn, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凣ROUP BY鑱氬悎缁撴灉Map
+ * 绛変环SQL: SELECT col1, FUNC{funcColumn1}, FUNC{funcColumn2} FROM {table} WHERE {filter bean} GROUP BY {col1}
+ * 濡 queryColumnMapAsync(OrderRecord.class, Utility.ofArray(ColumnNodeValue.div(ColumnFuncNode.sum("money"), 100), ColumnFuncNode.avg(ColumnNodeValue.dec("money", 20)))), "targetid", (FilterBean)null) + * 绛変环浜: SELECT targetid, SUM(money) / 100, AVG(money - 20) FROM orderrecord GROUP BY targetid
+ * + * @param Entity娉涘瀷 + * @param Key瀛楁鐨勬暟鎹被鍨 + * @param Number + * @param entityClass Entity绫 + * @param funcNodes ColumnNode[] + * @param groupByColumn GROUP BY瀛楁 + * @param bean 杩囨护鏉′欢 + * + * @return 鑱氬悎缁撴灉Map CompletableFuture + */ + default CompletableFuture> queryColumnMapAsync(final Class entityClass, final ColumnNode[] funcNodes, final String groupByColumn, final FilterBean bean) { + return queryColumnMapAsync(entityClass, funcNodes, groupByColumn, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凣ROUP BY鑱氬悎缁撴灉Map
+ * 绛変环SQL: SELECT col1, FUNC{funcColumn1}, FUNC{funcColumn2} FROM {table} WHERE {filter node} GROUP BY {col1}
+ * 濡 queryColumnMapAsync(OrderRecord.class, Utility.ofArray(ColumnNodeValue.div(ColumnFuncNode.sum("money"), 100), ColumnFuncNode.avg(ColumnNodeValue.dec("money", 20)))), "targetid", (FilterNode)null) + * 绛変环浜: SELECT targetid, SUM(money) / 100, AVG(money - 20) FROM orderrecord GROUP BY targetid
+ * + * @param Entity娉涘瀷 + * @param Key瀛楁鐨勬暟鎹被鍨 + * @param Number + * @param entityClass Entity绫 + * @param funcNodes ColumnNode[] + * @param groupByColumn GROUP BY瀛楁 + * @param node 杩囨护鏉′欢 + * + * @return 鑱氬悎缁撴灉Map CompletableFuture + */ + public Map queryColumnMap(final Class entityClass, final ColumnNode[] funcNodes, final String groupByColumn, final FilterNode node); + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凣ROUP BY鑱氬悎缁撴灉Map
+ * 绛変环SQL: SELECT col1, FUNC{funcColumn1}, FUNC{funcColumn2} FROM {table} WHERE {filter node} GROUP BY {col1}
+ * 濡 queryColumnMapAsync(OrderRecord.class, Utility.ofArray(ColumnNodeValue.div(ColumnFuncNode.sum("money"), 100), ColumnFuncNode.avg(ColumnNodeValue.dec("money", 20)))), "targetid", (FilterNode)null) + * 绛変环浜: SELECT targetid, SUM(money) / 100, AVG(money - 20) FROM orderrecord GROUP BY targetid
+ * + * @param Entity娉涘瀷 + * @param Key瀛楁鐨勬暟鎹被鍨 + * @param Number + * @param entityClass Entity绫 + * @param funcNodes ColumnNode[] + * @param groupByColumn GROUP BY瀛楁 + * @param node 杩囨护鏉′欢 + * + * @return 鑱氬悎缁撴灉Map CompletableFuture + */ + public CompletableFuture> queryColumnMapAsync(final Class entityClass, final ColumnNode[] funcNodes, final String groupByColumn, final FilterNode node); + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凣ROUP BY鑱氬悎缁撴灉Map
+ * 绛変环SQL: SELECT col1, col2, FUNC{funcColumn1}, FUNC{funcColumn2} FROM {table} GROUP BY {col1}, {col2}
+ * 濡 queryColumnMapAsync(OrderRecord.class, Utility.ofArray(ColumnNodeValue.div(ColumnFuncNode.sum("money"), 100), ColumnFuncNode.avg(ColumnNodeValue.dec("money", 20)))), Utility.ofArray("fromid", "targetid")) + * 绛変环浜: SELECT fromid, targetid, SUM(money) / 100, AVG(money - 20) FROM orderrecord GROUP BY fromid, targetid
+ * + * @param Entity娉涘瀷 + * @param Key瀛楁鐨勬暟鎹被鍨 + * @param Number + * @param entityClass Entity绫 + * @param funcNodes ColumnNode[] + * @param groupByColumns GROUP BY瀛楁 + * + * @return 鑱氬悎缁撴灉Map CompletableFuture + */ + default Map queryColumnMap(final Class entityClass, final ColumnNode[] funcNodes, final String[] groupByColumns) { + return queryColumnMap(entityClass, funcNodes, groupByColumns, (FilterNode) null); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凣ROUP BY鑱氬悎缁撴灉Map
+ * 绛変环SQL: SELECT col1, col2, FUNC{funcColumn1}, FUNC{funcColumn2} FROM {table} GROUP BY {col1}, {col2}
+ * 濡 queryColumnMapAsync(OrderRecord.class, Utility.ofArray(ColumnNodeValue.div(ColumnFuncNode.sum("money"), 100), ColumnFuncNode.avg(ColumnNodeValue.dec("money", 20)))), Utility.ofArray("fromid", "targetid")) + * 绛変环浜: SELECT fromid, targetid, SUM(money) / 100, AVG(money - 20) FROM orderrecord GROUP BY fromid, targetid
+ * + * @param Entity娉涘瀷 + * @param Key瀛楁鐨勬暟鎹被鍨 + * @param Number + * @param entityClass Entity绫 + * @param funcNodes ColumnNode[] + * @param groupByColumns GROUP BY瀛楁 + * + * @return 鑱氬悎缁撴灉Map CompletableFuture + */ + default CompletableFuture> queryColumnMapAsync(final Class entityClass, final ColumnNode[] funcNodes, final String[] groupByColumns) { + return queryColumnMapAsync(entityClass, funcNodes, groupByColumns, (FilterNode) null); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凣ROUP BY鑱氬悎缁撴灉Map
+ * 绛変环SQL: SELECT col1, col2, FUNC{funcColumn1}, FUNC{funcColumn2} FROM {table} WHERE {filter bean} GROUP BY {col1}, {col2}
+ * 濡 queryColumnMapAsync(OrderRecord.class, Utility.ofArray(ColumnNodeValue.div(ColumnFuncNode.sum("money"), 100), ColumnFuncNode.avg(ColumnNodeValue.dec("money", 20)))), Utility.ofArray("fromid", "targetid"), (FilterBean)null) + * 绛変环浜: SELECT fromid, targetid, SUM(money) / 100, AVG(money - 20) FROM orderrecord GROUP BY fromid, targetid
+ * + * @param Entity娉涘瀷 + * @param Key瀛楁鐨勬暟鎹被鍨 + * @param Number + * @param entityClass Entity绫 + * @param funcNodes ColumnNode[] + * @param groupByColumns GROUP BY瀛楁 + * @param bean 杩囨护鏉′欢 + * + * @return 鑱氬悎缁撴灉Map CompletableFuture + */ + default Map queryColumnMap(final Class entityClass, final ColumnNode[] funcNodes, final String[] groupByColumns, final FilterBean bean) { + return queryColumnMap(entityClass, funcNodes, groupByColumns, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凣ROUP BY鑱氬悎缁撴灉Map
+ * 绛変环SQL: SELECT col1, col2, FUNC{funcColumn1}, FUNC{funcColumn2} FROM {table} WHERE {filter bean} GROUP BY {col1}, {col2}
+ * 濡 queryColumnMapAsync(OrderRecord.class, Utility.ofArray(ColumnNodeValue.div(ColumnFuncNode.sum("money"), 100), ColumnFuncNode.avg(ColumnNodeValue.dec("money", 20)))), Utility.ofArray("fromid", "targetid"), (FilterBean)null) + * 绛変环浜: SELECT fromid, targetid, SUM(money) / 100, AVG(money - 20) FROM orderrecord GROUP BY fromid, targetid
+ * + * @param Entity娉涘瀷 + * @param Key瀛楁鐨勬暟鎹被鍨 + * @param Number + * @param entityClass Entity绫 + * @param funcNodes ColumnNode[] + * @param groupByColumns GROUP BY瀛楁 + * @param bean 杩囨护鏉′欢 + * + * @return 鑱氬悎缁撴灉Map CompletableFuture + */ + default CompletableFuture> queryColumnMapAsync(final Class entityClass, final ColumnNode[] funcNodes, final String[] groupByColumns, final FilterBean bean) { + return queryColumnMapAsync(entityClass, funcNodes, groupByColumns, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凣ROUP BY鑱氬悎缁撴灉Map
+ * 绛変环SQL: SELECT col1, col2, FUNC{funcColumn1}, FUNC{funcColumn2} FROM {table} WHERE {filter node} GROUP BY {col1}, {col2}
+ * 濡 queryColumnMapAsync(OrderRecord.class, Utility.ofArray(ColumnNodeValue.div(ColumnFuncNode.sum("money"), 100), ColumnFuncNode.avg(ColumnNodeValue.dec("money", 20)))), Utility.ofArray("fromid", "targetid"), (FilterNode)null) + * 绛変环浜: SELECT fromid, targetid, SUM(money) / 100, AVG(money - 20) FROM orderrecord GROUP BY fromid, targetid
+ * + * @param Entity娉涘瀷 + * @param Key瀛楁鐨勬暟鎹被鍨 + * @param Number + * @param entityClass Entity绫 + * @param funcNodes ColumnNode[] + * @param groupByColumns GROUP BY瀛楁 + * @param node 杩囨护鏉′欢 + * + * @return 鑱氬悎缁撴灉Map + */ + public Map queryColumnMap(final Class entityClass, final ColumnNode[] funcNodes, final String[] groupByColumns, final FilterNode node); + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凣ROUP BY鑱氬悎缁撴灉Map
+ * 绛変环SQL: SELECT col1, col2, FUNC{funcColumn1}, FUNC{funcColumn2} FROM {table} WHERE {filter node} GROUP BY {col1}, {col2}
+ * 濡 queryColumnMapAsync(OrderRecord.class, Utility.ofArray(ColumnNodeValue.div(ColumnFuncNode.sum("money"), 100), ColumnFuncNode.avg(ColumnNodeValue.dec("money", 20)))), Utility.ofArray("fromid", "targetid"), (FilterNode)null) + * 绛変环浜: SELECT fromid, targetid, SUM(money) / 100, AVG(money - 20) FROM orderrecord GROUP BY fromid, targetid
+ * + * @param Entity娉涘瀷 + * @param Key瀛楁鐨勬暟鎹被鍨 + * @param Number + * @param entityClass Entity绫 + * @param funcNodes ColumnNode[] + * @param groupByColumns GROUP BY瀛楁 + * @param node 杩囨护鏉′欢 + * + * @return 鑱氬悎缁撴灉Map CompletableFuture + */ + public CompletableFuture> queryColumnMapAsync(final Class entityClass, final ColumnNode[] funcNodes, final String[] groupByColumns, final FilterNode node); + + //-----------------------findAsync---------------------------- + /** + * 鑾峰彇鎸囧畾涓婚敭鍊肩殑鍗曚釜璁板綍, 杩斿洖null琛ㄧず涓嶅瓨鍦ㄥ
+ * 绛変环SQL: SELECT * FROM {table} WHERE {primary} = {id}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param pk 涓婚敭鍊 + * + * @return Entity瀵硅薄 + */ + default T find(final Class clazz, final Serializable pk) { + return find(clazz, (SelectColumn) null, pk); + } + + /** + * 鑾峰彇鎸囧畾涓婚敭鍊肩殑鍗曚釜璁板綍, 杩斿洖null琛ㄧず涓嶅瓨鍦ㄥ
+ * 绛変环SQL: SELECT * FROM {table} WHERE {primary} = {id}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param pk 涓婚敭鍊 + * + * @return Entity瀵硅薄 CompletableFuture + */ + public CompletableFuture findAsync(final Class clazz, final Serializable pk); + + /** + * 鑾峰彇鎸囧畾涓婚敭鍊肩殑鍗曚釜璁板綍, 杩斿洖null琛ㄧず涓嶅瓨鍦ㄥ
+ * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {primary} = {id}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param selects 鎸囧畾瀛楁 + * @param pk 涓婚敭鍊 + * + * @return Entity瀵硅薄 + */ + public T find(final Class clazz, final SelectColumn selects, final Serializable pk); + + /** + * 鑾峰彇鎸囧畾涓婚敭鍊肩殑鍗曚釜璁板綍, 杩斿洖null琛ㄧず涓嶅瓨鍦ㄥ
+ * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {primary} = {id}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param selects 鎸囧畾瀛楁 + * @param pk 涓婚敭鍊 + * + * @return Entity瀵硅薄CompletableFuture + */ + public CompletableFuture findAsync(final Class clazz, final SelectColumn selects, final Serializable pk); + + /** + * 鑾峰彇鎸囧畾涓婚敭鍊肩殑澶氫釜璁板綍, 杩斿洖鏁扮粍锛屾暟缁勯暱搴︿笌pks涓鏍
+ * 绛変环SQL: SELECT * FROM {table} WHERE {primary} = {id1,id2, ···}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param pks 涓婚敭鍊奸泦鍚 + * + * @return Entity瀵硅薄 + */ + default T[] finds(final Class clazz, final Serializable... pks) { + return finds(clazz, (SelectColumn) null, pks); + } + + /** + * 鑾峰彇鎸囧畾涓婚敭鍊肩殑澶氫釜璁板綍, 杩斿洖鏁扮粍锛屾暟缁勯暱搴︿笌pks涓鏍
+ * 绛変环SQL: SELECT * FROM {table} WHERE {primary} = {id1,id2, ···}
+ * + * @param 涓婚敭娉涘瀷 + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param pks 涓婚敭鍊奸泦鍚 + * + * @return Entity瀵硅薄 + */ + default T[] finds(final Class clazz, final Stream pks) { + return finds(clazz, (SelectColumn) null, pks.toArray(v -> new Serializable[v])); + } + + /** + * 鑾峰彇鎸囧畾涓婚敭鍊肩殑澶氫釜璁板綍, 杩斿洖鏁扮粍锛屾暟缁勯暱搴︿笌pks涓鏍
+ * 绛変环SQL: SELECT * FROM {table} WHERE {primary} = {id1,id2, ···}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param pks 涓婚敭鍊奸泦鍚 + * + * @return Entity瀵硅薄 CompletableFuture + */ + default CompletableFuture findsAsync(final Class clazz, final Serializable... pks) { + return findsAsync(clazz, (SelectColumn) null, pks); + } + + /** + * 鑾峰彇鎸囧畾涓婚敭鍊肩殑澶氫釜璁板綍, 杩斿洖鏁扮粍锛屾暟缁勯暱搴︿笌pks涓鏍
+ * 绛変环SQL: SELECT * FROM {table} WHERE {primary} = {id1,id2, ···}
+ * + * @param 涓婚敭娉涘瀷 + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param pks 涓婚敭鍊奸泦鍚 + * + * @return Entity瀵硅薄 CompletableFuture + */ + default CompletableFuture findsAsync(final Class clazz, final Stream pks) { + return findsAsync(clazz, (SelectColumn) null, pks.toArray(v -> new Serializable[v])); + } + + /** + * 鑾峰彇鎸囧畾涓婚敭鍊肩殑澶氫釜璁板綍, 杩斿洖鏁扮粍锛屾暟缁勯暱搴︿笌pks涓鏍
+ * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {primary} = {id1,id2, ···}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param selects 鎸囧畾瀛楁 + * @param pks 涓婚敭鍊奸泦鍚 + * + * @return Entity瀵硅薄 + */ + public T[] finds(final Class clazz, final SelectColumn selects, final Serializable... pks); + + /** + * 鑾峰彇鎸囧畾涓婚敭鍊肩殑澶氫釜璁板綍, 杩斿洖鏁扮粍锛屾暟缁勯暱搴︿笌pks涓鏍
+ * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {primary} = {id1,id2, ···}
+ * + * @param 涓婚敭娉涘瀷 + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param selects 鎸囧畾瀛楁 + * @param pks 涓婚敭鍊奸泦鍚 + * + * @return Entity瀵硅薄 + */ + default T[] finds(final Class clazz, final SelectColumn selects, final Stream pks) { + return finds(clazz, selects, pks.toArray(v -> new Serializable[v])); + } + + /** + * 鑾峰彇鎸囧畾涓婚敭鍊肩殑澶氫釜璁板綍, 杩斿洖鏁扮粍锛屾暟缁勯暱搴︿笌pks涓鏍
+ * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {primary} = {id1,id2, ···}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param selects 鎸囧畾瀛楁 + * @param pks 涓婚敭鍊奸泦鍚 + * + * @return Entity瀵硅薄CompletableFuture + */ + public CompletableFuture findsAsync(final Class clazz, final SelectColumn selects, final Serializable... pks); + + /** + * 鑾峰彇鎸囧畾涓婚敭鍊肩殑澶氫釜璁板綍, 杩斿洖鏁扮粍锛屾暟缁勯暱搴︿笌pks涓鏍
+ * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {primary} = {id1,id2, ···}
+ * + * @param 涓婚敭娉涘瀷 + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param selects 鎸囧畾瀛楁 + * @param pks 涓婚敭鍊奸泦鍚 + * + * @return Entity瀵硅薄 + */ + default CompletableFuture findsAsync(final Class clazz, final SelectColumn selects, final Stream pks) { + return findsAsync(clazz, selects, pks.toArray(v -> new Serializable[v])); + } + + /** + * 鑾峰彇绗﹀悎杩囨护鏉′欢鍗曚釜璁板綍, 杩斿洖null琛ㄧず涓嶅瓨鍦ㄥ
+ * 绛変环SQL: SELECT * FROM {table} WHERE {column} = {key}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param column 杩囨护瀛楁鍚 + * @param colval 杩囨护瀛楁鍊 + * + * @return Entity瀵硅薄 + */ + public T find(final Class clazz, final String column, final Serializable colval); + + /** + * 鑾峰彇绗﹀悎杩囨护鏉′欢鍗曚釜璁板綍, 杩斿洖null琛ㄧず涓嶅瓨鍦ㄥ
+ * 绛変环SQL: SELECT * FROM {table} WHERE {column} = {key}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param column 杩囨护瀛楁鍚 + * @param colval 杩囨护瀛楁鍊 + * + * @return Entity瀵硅薄CompletableFuture + */ + public CompletableFuture findAsync(final Class clazz, final String column, final Serializable colval); + + /** + * 鑾峰彇绗﹀悎杩囨护鏉′欢鍗曚釜璁板綍, 杩斿洖null琛ㄧず涓嶅瓨鍦ㄥ
+ * 绛変环SQL: SELECT * FROM {table} WHERE {filter bean}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param bean 杩囨护鏉′欢 + * + * @return Entity瀵硅薄 + */ + default T find(final Class clazz, final FilterBean bean) { + return find(clazz, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鑾峰彇绗﹀悎杩囨护鏉′欢鍗曚釜璁板綍, 杩斿洖null琛ㄧず涓嶅瓨鍦ㄥ
+ * 绛変环SQL: SELECT * FROM {table} WHERE {filter bean}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param bean 杩囨护鏉′欢 + * + * @return Entity瀵硅薄CompletableFuture + */ + default CompletableFuture findAsync(final Class clazz, final FilterBean bean) { + return findAsync(clazz, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鑾峰彇绗﹀悎杩囨护鏉′欢鍗曚釜璁板綍, 杩斿洖null琛ㄧず涓嶅瓨鍦ㄥ
+ * 绛変环SQL: SELECT * FROM {table} WHERE {filter node}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param node 杩囨护鏉′欢 + * + * @return Entity瀵硅薄 + */ + default T find(final Class clazz, final FilterNode node) { + return find(clazz, (SelectColumn) null, node); + } + + /** + * 鑾峰彇绗﹀悎杩囨护鏉′欢鍗曚釜璁板綍, 杩斿洖null琛ㄧず涓嶅瓨鍦ㄥ
+ * 绛変环SQL: SELECT * FROM {table} WHERE {filter node}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param node 杩囨护鏉′欢 + * + * @return Entity瀵硅薄CompletableFuture + */ + default CompletableFuture findAsync(final Class clazz, final FilterNode node) { + return findAsync(clazz, (SelectColumn) null, node); + } + + /** + * 鑾峰彇绗﹀悎杩囨护鏉′欢鍗曚釜璁板綍, 杩斿洖null琛ㄧず涓嶅瓨鍦ㄥ
+ * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter bean}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param selects 鎸囧畾瀛楁 + * @param bean 杩囨护鏉′欢 + * + * @return Entity瀵硅薄 + */ + default T find(final Class clazz, final SelectColumn selects, final FilterBean bean) { + return find(clazz, selects, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鑾峰彇绗﹀悎杩囨护鏉′欢鍗曚釜璁板綍, 杩斿洖null琛ㄧず涓嶅瓨鍦ㄥ
+ * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter bean}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param selects 鎸囧畾瀛楁 + * @param bean 杩囨护鏉′欢 + * + * @return Entity瀵硅薄 CompletableFuture + */ + default CompletableFuture findAsync(final Class clazz, final SelectColumn selects, final FilterBean bean) { + return findAsync(clazz, selects, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鑾峰彇绗﹀悎杩囨护鏉′欢鍗曚釜璁板綍, 杩斿洖null琛ㄧず涓嶅瓨鍦ㄥ
+ * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter node}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param selects 鎸囧畾瀛楁 + * @param node 杩囨护鏉′欢 + * + * @return Entity瀵硅薄 + */ + public T find(final Class clazz, final SelectColumn selects, final FilterNode node); + + /** + * 鑾峰彇绗﹀悎杩囨护鏉′欢鍗曚釜璁板綍, 杩斿洖null琛ㄧず涓嶅瓨鍦ㄥ
+ * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter node}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param selects 鎸囧畾瀛楁 + * @param node 杩囨护鏉′欢 + * + * @return Entity瀵硅薄 CompletableFuture + */ + public CompletableFuture findAsync(final Class clazz, final SelectColumn selects, final FilterNode node); + + /** + * 鑾峰彇绗﹀悎杩囨护鏉′欢鍗曚釜璁板綍鐨勫崟涓瓧娈靛, 杩斿洖null琛ㄧず涓嶅瓨鍦ㄥ
+ * 绛変环SQL: SELECT {column} FROM {table} WHERE {primary} = {id}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param column 瀛楁鍚 + * @param pk 涓婚敭鍊 + * + * @return Entity瀵硅薄 + */ + public Serializable findColumn(final Class clazz, final String column, final Serializable pk); + + /** + * 鑾峰彇绗﹀悎杩囨护鏉′欢鍗曚釜璁板綍鐨勫崟涓瓧娈靛, 杩斿洖null琛ㄧず涓嶅瓨鍦ㄥ
+ * 绛変环SQL: SELECT {column} FROM {table} WHERE {primary} = {id}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param column 瀛楁鍚 + * @param pk 涓婚敭鍊 + * + * @return Entity瀵硅薄 CompletableFuture + */ + public CompletableFuture findColumnAsync(final Class clazz, final String column, final Serializable pk); + + /** + * 鑾峰彇绗﹀悎杩囨护鏉′欢鍗曚釜璁板綍鐨勫崟涓瓧娈靛, 杩斿洖null琛ㄧず涓嶅瓨鍦ㄥ
+ * 绛変环SQL: SELECT {column} FROM {table} WHERE {filter bean}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param column 瀛楁鍚 + * @param bean 杩囨护鏉′欢 + * + * @return 瀛楁鍊 + */ + default Serializable findColumn(final Class clazz, final String column, final FilterBean bean) { + return findColumn(clazz, column, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鑾峰彇绗﹀悎杩囨护鏉′欢鍗曚釜璁板綍鐨勫崟涓瓧娈靛, 杩斿洖null琛ㄧず涓嶅瓨鍦ㄥ
+ * 绛変环SQL: SELECT {column} FROM {table} WHERE {filter bean}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param column 瀛楁鍚 + * @param bean 杩囨护鏉′欢 + * + * @return 瀛楁鍊 CompletableFuture + */ + default CompletableFuture findColumnAsync(final Class clazz, final String column, final FilterBean bean) { + return findColumnAsync(clazz, column, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鑾峰彇绗﹀悎杩囨护鏉′欢鍗曚釜璁板綍鐨勫崟涓瓧娈靛, 杩斿洖null琛ㄧず涓嶅瓨鍦ㄥ
+ * 绛変环SQL: SELECT {column} FROM {table} WHERE {filter node}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param column 瀛楁鍚 + * @param node 杩囨护鏉′欢 + * + * @return 瀛楁鍊 + */ + default Serializable findColumn(final Class clazz, final String column, final FilterNode node) { + return findColumn(clazz, column, null, node); + } + + /** + * 鑾峰彇绗﹀悎杩囨护鏉′欢鍗曚釜璁板綍鐨勫崟涓瓧娈靛, 杩斿洖null琛ㄧず涓嶅瓨鍦ㄥ
+ * 绛変环SQL: SELECT {column} FROM {table} WHERE {filter node}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param column 瀛楁鍚 + * @param node 杩囨护鏉′欢 + * + * @return 瀛楁鍊 CompletableFuture + */ + default CompletableFuture findColumnAsync(final Class clazz, final String column, final FilterNode node) { + return findColumnAsync(clazz, column, null, node); + } + + /** + * 鑾峰彇绗﹀悎杩囨护鏉′欢鍗曚釜璁板綍鐨勫崟涓瓧娈靛, 涓嶅瓨鍦ㄥ煎垯杩斿洖榛樿鍊
+ * 绛変环SQL: SELECT {column} FROM {table} WHERE {primary} = {id}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param column 瀛楁鍚 + * @param defValue 榛樿鍊 + * @param pk 涓婚敭鍊 + * + * @return 瀛楁鍊 + */ + public Serializable findColumn(final Class clazz, final String column, final Serializable defValue, final Serializable pk); + + /** + * 鑾峰彇绗﹀悎杩囨护鏉′欢鍗曚釜璁板綍鐨勫崟涓瓧娈靛, 涓嶅瓨鍦ㄥ煎垯杩斿洖榛樿鍊
+ * 绛変环SQL: SELECT {column} FROM {table} WHERE {primary} = {id}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param column 瀛楁鍚 + * @param defValue 榛樿鍊 + * @param pk 涓婚敭鍊 + * + * @return 瀛楁鍊 CompletableFuture + */ + public CompletableFuture findColumnAsync(final Class clazz, final String column, final Serializable defValue, final Serializable pk); + + /** + * 鑾峰彇绗﹀悎杩囨护鏉′欢鍗曚釜璁板綍鐨勫崟涓瓧娈靛, 涓嶅瓨鍦ㄥ煎垯杩斿洖榛樿鍊
+ * 绛変环SQL: SELECT {column} FROM {table} WHERE {filter bean}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param column 瀛楁鍚 + * @param defValue 榛樿鍊 + * @param bean 杩囨护鏉′欢 + * + * @return 瀛楁鍊 + */ + default Serializable findColumn(final Class clazz, final String column, final Serializable defValue, final FilterBean bean) { + return findColumn(clazz, column, defValue, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鑾峰彇绗﹀悎杩囨护鏉′欢鍗曚釜璁板綍鐨勫崟涓瓧娈靛, 涓嶅瓨鍦ㄥ煎垯杩斿洖榛樿鍊
+ * 绛変环SQL: SELECT {column} FROM {table} WHERE {filter bean}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param column 瀛楁鍚 + * @param defValue 榛樿鍊 + * @param bean 杩囨护鏉′欢 + * + * @return 瀛楁鍊 CompletableFuture + */ + default CompletableFuture findColumnAsync(final Class clazz, final String column, final Serializable defValue, final FilterBean bean) { + return findColumnAsync(clazz, column, defValue, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鑾峰彇绗﹀悎杩囨护鏉′欢鍗曚釜璁板綍鐨勫崟涓瓧娈靛, 涓嶅瓨鍦ㄥ煎垯杩斿洖榛樿鍊
+ * 绛変环SQL: SELECT {column} FROM {table} WHERE {filter node}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param column 瀛楁鍚 + * @param defValue 榛樿鍊 + * @param node 杩囨护鏉′欢 + * + * @return 瀛楁鍊 + */ + public Serializable findColumn(final Class clazz, final String column, final Serializable defValue, final FilterNode node); + + /** + * 鑾峰彇绗﹀悎杩囨护鏉′欢鍗曚釜璁板綍鐨勫崟涓瓧娈靛, 涓嶅瓨鍦ㄥ煎垯杩斿洖榛樿鍊
+ * 绛変环SQL: SELECT {column} FROM {table} WHERE {filter node}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param column 瀛楁鍚 + * @param defValue 榛樿鍊 + * @param node 杩囨护鏉′欢 + * + * @return 瀛楁鍊 CompletableFuture + */ + public CompletableFuture findColumnAsync(final Class clazz, final String column, final Serializable defValue, final FilterNode node); + + /** + * 鍒ゆ柇鏄惁瀛樺湪涓婚敭鍊肩殑璁板綍
+ * 绛変环SQL: SELECT COUNT(*) FROM {table} WHERE {primary} = {id}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param pk 涓婚敭鍊 + * + * @return 鏄惁瀛樺湪 + */ + public boolean exists(final Class clazz, final Serializable pk); + + /** + * 鍒ゆ柇鏄惁瀛樺湪涓婚敭鍊肩殑璁板綍
+ * 绛変环SQL: SELECT COUNT(*) FROM {table} WHERE {primary} = {id}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param pk 涓婚敭鍊 + * + * @return 鏄惁瀛樺湪CompletableFuture + */ + public CompletableFuture existsAsync(final Class clazz, final Serializable pk); + + /** + * 鍒ゆ柇鏄惁瀛樺湪绗﹀悎杩囨护鏉′欢鐨勮褰
+ * 绛変环SQL: SELECT COUNT(*) FROM {table} WHERE {filter bean}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param bean 杩囨护鏉′欢 + * + * @return 鏄惁瀛樺湪 + */ + default boolean exists(final Class clazz, final FilterBean bean) { + return exists(clazz, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鍒ゆ柇鏄惁瀛樺湪绗﹀悎杩囨护鏉′欢鐨勮褰
+ * 绛変环SQL: SELECT COUNT(*) FROM {table} WHERE {filter bean}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param bean 杩囨护鏉′欢 + * + * @return 鏄惁瀛樺湪CompletableFuture + */ + default CompletableFuture existsAsync(final Class clazz, final FilterBean bean) { + return existsAsync(clazz, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鍒ゆ柇鏄惁瀛樺湪绗﹀悎杩囨护鏉′欢鐨勮褰
+ * 绛変环SQL: SELECT COUNT(*) FROM {table} WHERE {filter node}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param node 杩囨护鏉′欢 + * + * @return 鏄惁瀛樺湪 + */ + public boolean exists(final Class clazz, final FilterNode node); + + /** + * 鍒ゆ柇鏄惁瀛樺湪绗﹀悎杩囨护鏉′欢鐨勮褰
+ * 绛変环SQL: SELECT COUNT(*) FROM {table} WHERE {filter node}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param node 杩囨护鏉′欢 + * + * @return 鏄惁瀛樺湪CompletableFuture + */ + public CompletableFuture existsAsync(final Class clazz, final FilterNode node); + + //-----------------------list set---------------------------- + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨勬煇涓瓧娈礢et闆嗗悎
+ * 绛変环SQL: SELECT DISTINCT {selectedColumn} FROM {table} WHERE {column} = {key}
+ * + * @param Entity娉涘瀷 + * @param 瀛楁绫诲瀷 + * @param selectedColumn 鎸囧畾瀛楁 + * @param clazz Entity绫 + * @param column 杩囨护瀛楁鍚 + * @param colval 杩囨护瀛楁鍊 + * + * @return 瀛楁鍊肩殑闆嗗悎 + */ + public Set queryColumnSet(final String selectedColumn, final Class clazz, final String column, final Serializable colval); + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨勬煇涓瓧娈礢et闆嗗悎
+ * 绛変环SQL: SELECT DISTINCT {selectedColumn} FROM {table} WHERE {column} = {key}
+ * + * @param Entity娉涘瀷 + * @param 瀛楁绫诲瀷 + * @param selectedColumn 鎸囧畾瀛楁 + * @param clazz Entity绫 + * @param column 杩囨护瀛楁鍚 + * @param colval 杩囨护瀛楁鍊 + * + * @return 瀛楁鍊肩殑闆嗗悎CompletableFuture + */ + public CompletableFuture> queryColumnSetAsync(final String selectedColumn, final Class clazz, final String column, final Serializable colval); + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨勬煇涓瓧娈礢et闆嗗悎
+ * 绛変环SQL: SELECT DISTINCT {selectedColumn} FROM {table} WHERE {filter bean}
+ * + * @param Entity娉涘瀷 + * @param 瀛楁绫诲瀷 + * @param selectedColumn 鎸囧畾瀛楁 + * @param clazz Entity绫 + * @param bean 杩囨护鏉′欢 + * + * @return 瀛楁鍊肩殑闆嗗悎 + */ + default Set queryColumnSet(final String selectedColumn, final Class clazz, final FilterBean bean) { + return queryColumnSet(selectedColumn, clazz, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨勬煇涓瓧娈礢et闆嗗悎
+ * 绛変环SQL: SELECT DISTINCT {selectedColumn} FROM {table} WHERE {filter bean}
+ * + * @param Entity娉涘瀷 + * @param 瀛楁绫诲瀷 + * @param selectedColumn 鎸囧畾瀛楁 + * @param clazz Entity绫 + * @param bean 杩囨护鏉′欢 + * + * @return 瀛楁鍊肩殑闆嗗悎CompletableFuture + */ + default CompletableFuture> queryColumnSetAsync(final String selectedColumn, final Class clazz, final FilterBean bean) { + return queryColumnSetAsync(selectedColumn, clazz, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨勬煇涓瓧娈礢et闆嗗悎
+ * 绛変环SQL: SELECT DISTINCT {selectedColumn} FROM {table} WHERE {filter node}
+ * + * @param Entity娉涘瀷 + * @param 瀛楁绫诲瀷 + * @param selectedColumn 鎸囧畾瀛楁 + * @param clazz Entity绫 + * @param node 杩囨护鏉′欢 + * + * @return 瀛楁鍊肩殑闆嗗悎 + */ + default Set queryColumnSet(final String selectedColumn, final Class clazz, final FilterNode node) { + return queryColumnSet(selectedColumn, clazz, (Flipper) null, node); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨勬煇涓瓧娈礢et闆嗗悎
+ * 绛変环SQL: SELECT DISTINCT {selectedColumn} FROM {table} WHERE {filter node}
+ * + * @param Entity娉涘瀷 + * @param 瀛楁绫诲瀷 + * @param selectedColumn 鎸囧畾瀛楁 + * @param clazz Entity绫 + * @param node 杩囨护鏉′欢 + * + * @return 瀛楁鍊肩殑闆嗗悎CompletableFuture + */ + default CompletableFuture> queryColumnSetAsync(final String selectedColumn, final Class clazz, final FilterNode node) { + return queryColumnSetAsync(selectedColumn, clazz, (Flipper) null, node); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨勬煇涓瓧娈礢et闆嗗悎
+ * 绛変环SQL: SELECT DISTINCT {selectedColumn} FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param 瀛楁绫诲瀷 + * @param selectedColumn 鎸囧畾瀛楁 + * @param clazz Entity绫 + * @param flipper 缈婚〉瀵硅薄 + * @param bean 杩囨护鏉′欢 + * + * @return 瀛楁鍊肩殑闆嗗悎 + */ + default Set queryColumnSet(final String selectedColumn, final Class clazz, final Flipper flipper, final FilterBean bean) { + return queryColumnSet(selectedColumn, clazz, flipper, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨勬煇涓瓧娈礢et闆嗗悎
+ * 绛変环SQL: SELECT DISTINCT {selectedColumn} FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param 瀛楁绫诲瀷 + * @param selectedColumn 鎸囧畾瀛楁 + * @param clazz Entity绫 + * @param flipper 缈婚〉瀵硅薄 + * @param bean 杩囨护鏉′欢 + * + * @return 瀛楁鍊肩殑闆嗗悎CompletableFuture + */ + default CompletableFuture> queryColumnSetAsync(final String selectedColumn, final Class clazz, final Flipper flipper, final FilterBean bean) { + return queryColumnSetAsync(selectedColumn, clazz, flipper, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨勬煇涓瓧娈礢et闆嗗悎
+ * 绛変环SQL: SELECT DISTINCT {selectedColumn} FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param 瀛楁绫诲瀷 + * @param selectedColumn 鎸囧畾瀛楁 + * @param clazz Entity绫 + * @param flipper 缈婚〉瀵硅薄 + * @param node 杩囨护鏉′欢 + * + * @return 瀛楁鍊肩殑闆嗗悎 + */ + public Set queryColumnSet(final String selectedColumn, final Class clazz, final Flipper flipper, final FilterNode node); + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨勬煇涓瓧娈礢et闆嗗悎
+ * 绛変环SQL: SELECT DISTINCT {selectedColumn} FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param 瀛楁绫诲瀷 + * @param selectedColumn 鎸囧畾瀛楁 + * @param clazz Entity绫 + * @param flipper 缈婚〉瀵硅薄 + * @param node 杩囨护鏉′欢 + * + * @return 瀛楁鍊肩殑闆嗗悎CompletableFuture + */ + public CompletableFuture> queryColumnSetAsync(final String selectedColumn, final Class clazz, final Flipper flipper, final FilterNode node); + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨勬煇涓瓧娈礚ist闆嗗悎
+ * 绛変环SQL: SELECT {selectedColumn} FROM {table} WHERE {column} = {key}
+ * + * @param Entity娉涘瀷 + * @param 瀛楁绫诲瀷 + * @param selectedColumn 鎸囧畾瀛楁 + * @param clazz Entity绫 + * @param column 杩囨护瀛楁鍚 + * @param colval 杩囨护瀛楁鍊 + * + * @return 瀛楁鍊肩殑闆嗗悎 + */ + public List queryColumnList(final String selectedColumn, final Class clazz, final String column, final Serializable colval); + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨勬煇涓瓧娈礚ist闆嗗悎
+ * 绛変环SQL: SELECT {selectedColumn} FROM {table} WHERE {column} = {key}
+ * + * @param Entity娉涘瀷 + * @param 瀛楁绫诲瀷 + * @param selectedColumn 鎸囧畾瀛楁 + * @param clazz Entity绫 + * @param column 杩囨护瀛楁鍚 + * @param colval 杩囨护瀛楁鍊 + * + * @return 瀛楁鍊肩殑闆嗗悎CompletableFuture + */ + public CompletableFuture> queryColumnListAsync(final String selectedColumn, final Class clazz, final String column, final Serializable colval); + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨勬煇涓瓧娈礚ist闆嗗悎
+ * 绛変环SQL: SELECT {selectedColumn} FROM {table} WHERE {filter bean}
+ * + * @param Entity娉涘瀷 + * @param 瀛楁绫诲瀷 + * @param selectedColumn 鎸囧畾瀛楁 + * @param clazz Entity绫 + * @param bean 杩囨护鏉′欢 + * + * @return 瀛楁鍊肩殑闆嗗悎 + */ + default List queryColumnList(final String selectedColumn, final Class clazz, final FilterBean bean) { + return queryColumnList(selectedColumn, clazz, (Flipper) null, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨勬煇涓瓧娈礚ist闆嗗悎
+ * 绛変环SQL: SELECT {selectedColumn} FROM {table} WHERE {filter bean}
+ * + * @param Entity娉涘瀷 + * @param 瀛楁绫诲瀷 + * @param selectedColumn 鎸囧畾瀛楁 + * @param clazz Entity绫 + * @param bean 杩囨护鏉′欢 + * + * @return 瀛楁鍊肩殑闆嗗悎CompletableFuture + */ + default CompletableFuture> queryColumnListAsync(final String selectedColumn, final Class clazz, final FilterBean bean) { + return queryColumnListAsync(selectedColumn, clazz, (Flipper) null, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨勬煇涓瓧娈礚ist闆嗗悎
+ * 绛変环SQL: SELECT {selectedColumn} FROM {table} WHERE {filter node}
+ * + * @param Entity娉涘瀷 + * @param 瀛楁绫诲瀷 + * @param selectedColumn 鎸囧畾瀛楁 + * @param clazz Entity绫 + * @param node 杩囨护鏉′欢 + * + * @return 瀛楁鍊肩殑闆嗗悎 + */ + default List queryColumnList(final String selectedColumn, final Class clazz, final FilterNode node) { + return queryColumnList(selectedColumn, clazz, (Flipper) null, node); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨勬煇涓瓧娈礚ist闆嗗悎
+ * 绛変环SQL: SELECT {selectedColumn} FROM {table} WHERE {filter node}
+ * + * @param Entity娉涘瀷 + * @param 瀛楁绫诲瀷 + * @param selectedColumn 鎸囧畾瀛楁 + * @param clazz Entity绫 + * @param node 杩囨护鏉′欢 + * + * @return 瀛楁鍊肩殑闆嗗悎CompletableFuture + */ + default CompletableFuture> queryColumnListAsync(final String selectedColumn, final Class clazz, final FilterNode node) { + return queryColumnListAsync(selectedColumn, clazz, (Flipper) null, node); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨勬煇涓瓧娈礚ist闆嗗悎
+ * 绛変环SQL: SELECT {selectedColumn} FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param 瀛楁绫诲瀷 + * @param selectedColumn 鎸囧畾瀛楁 + * @param clazz Entity绫 + * @param flipper 缈婚〉瀵硅薄 + * @param bean 杩囨护鏉′欢 + * + * @return 瀛楁鍊肩殑闆嗗悎 + */ + default List queryColumnList(final String selectedColumn, final Class clazz, final Flipper flipper, final FilterBean bean) { + return queryColumnList(selectedColumn, clazz, flipper, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨勬煇涓瓧娈礚ist闆嗗悎
+ * 绛変环SQL: SELECT {selectedColumn} FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param 瀛楁绫诲瀷 + * @param selectedColumn 鎸囧畾瀛楁 + * @param clazz Entity绫 + * @param flipper 缈婚〉瀵硅薄 + * @param bean 杩囨护鏉′欢 + * + * @return 瀛楁鍊肩殑闆嗗悎CompletableFuture + */ + default CompletableFuture> queryColumnListAsync(final String selectedColumn, final Class clazz, final Flipper flipper, final FilterBean bean) { + return queryColumnListAsync(selectedColumn, clazz, flipper, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨勬煇涓瓧娈礚ist闆嗗悎
+ * 绛変环SQL: SELECT {selectedColumn} FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param 瀛楁绫诲瀷 + * @param selectedColumn 鎸囧畾瀛楁 + * @param clazz Entity绫 + * @param flipper 缈婚〉瀵硅薄 + * @param node 杩囨护鏉′欢 + * + * @return 瀛楁鍊肩殑闆嗗悎 + */ + public List queryColumnList(final String selectedColumn, final Class clazz, final Flipper flipper, final FilterNode node); + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨勬煇涓瓧娈礚ist闆嗗悎
+ * 绛変环SQL: SELECT {selectedColumn} FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param 瀛楁绫诲瀷 + * @param selectedColumn 鎸囧畾瀛楁 + * @param clazz Entity绫 + * @param flipper 缈婚〉瀵硅薄 + * @param node 杩囨护鏉′欢 + * + * @return 瀛楁鍊肩殑闆嗗悎CompletableFuture + */ + public CompletableFuture> queryColumnListAsync(final String selectedColumn, final Class clazz, final Flipper flipper, final FilterNode node); + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨勬煇涓瓧娈礢heet闆嗗悎
+ * 绛変环SQL: SELECT {selectedColumn} FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param 瀛楁绫诲瀷 + * @param selectedColumn 鎸囧畾瀛楁 + * @param clazz Entity绫 + * @param flipper 缈婚〉瀵硅薄 + * @param bean 杩囨护鏉′欢 + * + * @return 瀛楁鍊肩殑闆嗗悎 + */ + default Sheet queryColumnSheet(final String selectedColumn, final Class clazz, final Flipper flipper, final FilterBean bean) { + return queryColumnSheet(selectedColumn, clazz, flipper, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨勬煇涓瓧娈礢heet闆嗗悎
+ * 绛変环SQL: SELECT {selectedColumn} FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param 瀛楁绫诲瀷 + * @param selectedColumn 鎸囧畾瀛楁 + * @param clazz Entity绫 + * @param flipper 缈婚〉瀵硅薄 + * @param bean 杩囨护鏉′欢 + * + * @return 瀛楁鍊肩殑闆嗗悎CompletableFuture + */ + default CompletableFuture> queryColumnSheetAsync(final String selectedColumn, final Class clazz, final Flipper flipper, final FilterBean bean) { + return queryColumnSheetAsync(selectedColumn, clazz, flipper, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨勬煇涓瓧娈礢heet闆嗗悎
+ * 绛変环SQL: SELECT {selectedColumn} FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param 瀛楁绫诲瀷 + * @param selectedColumn 鎸囧畾瀛楁 + * @param clazz Entity绫 + * @param flipper 缈婚〉瀵硅薄 + * @param node 杩囨护鏉′欢 + * + * @return 瀛楁鍊肩殑闆嗗悎 + */ + public Sheet queryColumnSheet(final String selectedColumn, final Class clazz, final Flipper flipper, final FilterNode node); + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨勬煇涓瓧娈礢heet闆嗗悎
+ * 绛変环SQL: SELECT {selectedColumn} FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param 瀛楁绫诲瀷 + * @param selectedColumn 鎸囧畾瀛楁 + * @param clazz Entity绫 + * @param flipper 缈婚〉瀵硅薄 + * @param node 杩囨护鏉′欢 + * + * @return 瀛楁鍊肩殑闆嗗悎CompletableFuture + */ + public CompletableFuture> queryColumnSheetAsync(final String selectedColumn, final Class clazz, final Flipper flipper, final FilterNode node); + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist杞琈ap闆嗗悎锛 key=涓婚敭鍊, value=Entity瀵硅薄
+ * 绛変环SQL: SELECT * FROM {table} WHERE id IN {ids}
+ * + * @param 涓婚敭娉涘瀷 + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param keyStream 涓婚敭Stream + * + * @return Entity鐨勯泦鍚 + */ + default Map queryMap(final Class clazz, final Stream keyStream) { + return queryMap(clazz, (SelectColumn) null, keyStream); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist杞琈ap闆嗗悎锛 key=涓婚敭鍊, value=Entity瀵硅薄
+ * 绛変环SQL: SELECT * FROM {table} WHERE id IN {ids}
+ * + * @param 涓婚敭娉涘瀷 + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param keyStream 涓婚敭Stream + * + * @return Entity鐨勯泦鍚圕ompletableFuture + */ + default CompletableFuture> queryMapAsync(final Class clazz, final Stream keyStream) { + return queryMapAsync(clazz, (SelectColumn) null, keyStream); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist杞琈ap闆嗗悎锛 key=涓婚敭鍊, value=Entity瀵硅薄
+ * 绛変环SQL: SELECT * FROM {table} WHERE {filter node}
+ * + * @param 涓婚敭娉涘瀷 + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param bean FilterBean + * + * @return Entity鐨勯泦鍚 + */ + default Map queryMap(final Class clazz, final FilterBean bean) { + return queryMap(clazz, (SelectColumn) null, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist杞琈ap闆嗗悎锛 key=涓婚敭鍊, value=Entity瀵硅薄
+ * 绛変环SQL: SELECT * FROM {table} WHERE {filter node}
+ * + * @param 涓婚敭娉涘瀷 + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param bean FilterBean + * + * @return Entity鐨勯泦鍚圕ompletableFuture + */ + default CompletableFuture> queryMapAsync(final Class clazz, final FilterBean bean) { + return queryMapAsync(clazz, (SelectColumn) null, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist杞琈ap闆嗗悎锛 key=涓婚敭鍊, value=Entity瀵硅薄
+ * 绛変环SQL: SELECT * FROM {table} WHERE {filter node}
+ * + * @param 涓婚敭娉涘瀷 + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param node FilterNode + * + * @return Entity鐨勯泦鍚 + */ + default Map queryMap(final Class clazz, final FilterNode node) { + return queryMap(clazz, (SelectColumn) null, node); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist杞琈ap闆嗗悎锛 key=涓婚敭鍊, value=Entity瀵硅薄
+ * 绛変环SQL: SELECT * FROM {table} WHERE {filter node}
+ * + * @param 涓婚敭娉涘瀷 + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param node FilterNode + * + * @return Entity鐨勯泦鍚圕ompletableFuture + */ + default CompletableFuture> queryMapAsync(final Class clazz, final FilterNode node) { + return queryMapAsync(clazz, (SelectColumn) null, node); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist杞琈ap闆嗗悎锛 key=涓婚敭鍊, value=Entity瀵硅薄
+ * 绛変环SQL: SELECT * FROM {table} WHERE id IN {ids}
+ * + * @param 涓婚敭娉涘瀷 + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param selects 鎸囧畾瀛楁 + * @param keyStream 涓婚敭Stream + * + * @return Entity鐨勯泦鍚 + */ + public Map queryMap(final Class clazz, final SelectColumn selects, final Stream keyStream); + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist杞琈ap闆嗗悎锛 key=涓婚敭鍊, value=Entity瀵硅薄
+ * 绛変环SQL: SELECT * FROM {table} WHERE id IN {ids}
+ * + * @param 涓婚敭娉涘瀷 + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param selects 鎸囧畾瀛楁 + * @param keyStream 涓婚敭Stream + * + * @return Entity鐨勯泦鍚圕ompletableFuture + */ + public CompletableFuture> queryMapAsync(final Class clazz, final SelectColumn selects, final Stream keyStream); + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist杞琈ap闆嗗悎锛 key=涓婚敭鍊, value=Entity瀵硅薄
+ * 绛変环SQL: SELECT * FROM {table} WHERE {filter node}
+ * + * @param 涓婚敭娉涘瀷 + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param selects 鎸囧畾瀛楁 + * @param bean FilterBean + * + * @return Entity鐨勯泦鍚 + */ + default Map queryMap(final Class clazz, final SelectColumn selects, final FilterBean bean) { + return queryMap(clazz, selects, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist杞琈ap闆嗗悎锛 key=涓婚敭鍊, value=Entity瀵硅薄
+ * 绛変环SQL: SELECT * FROM {table} WHERE {filter node}
+ * + * @param 涓婚敭娉涘瀷 + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param selects 鎸囧畾瀛楁 + * @param bean FilterBean + * + * @return Entity鐨勯泦鍚圕ompletableFuture + */ + default CompletableFuture> queryMapAsync(final Class clazz, final SelectColumn selects, FilterBean bean) { + return queryMapAsync(clazz, selects, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist杞琈ap闆嗗悎锛 key=涓婚敭鍊, value=Entity瀵硅薄
+ * 绛変环SQL: SELECT * FROM {table} WHERE {filter node}
+ * + * @param 涓婚敭娉涘瀷 + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param selects 鎸囧畾瀛楁 + * @param node FilterNode + * + * @return Entity鐨勯泦鍚 + */ + public Map queryMap(final Class clazz, final SelectColumn selects, final FilterNode node); + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist杞琈ap闆嗗悎锛 key=涓婚敭鍊, value=Entity瀵硅薄
+ * 绛変环SQL: SELECT * FROM {table} WHERE {filter node}
+ * + * @param 涓婚敭娉涘瀷 + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param selects 鎸囧畾瀛楁 + * @param node FilterNode + * + * @return Entity鐨勯泦鍚圕ompletableFuture + */ + public CompletableFuture> queryMapAsync(final Class clazz, final SelectColumn selects, final FilterNode node); + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷et闆嗗悎
+ * 绛変环SQL: SELECT DISTINCT * FROM {table} WHERE {column} = {key} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param column 杩囨护瀛楁鍚 + * @param colval 杩囨护瀛楁鍊 + * + * @return Entity鐨勯泦鍚 + */ + default Set querySet(final Class clazz, final String column, final Serializable colval) { + return querySet(clazz, (Flipper) null, column, colval); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷et闆嗗悎
+ * 绛変环SQL: SELECT DISTINCT * FROM {table} WHERE {column} = {key} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param column 杩囨护瀛楁鍚 + * @param colval 杩囨护瀛楁鍊 + * + * @return Entity鐨勯泦鍚圕ompletableFuture + */ + default CompletableFuture> querySetAsync(final Class clazz, final String column, final Serializable colval) { + return querySetAsync(clazz, (Flipper) null, column, colval); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷et闆嗗悎
+ * 绛変环SQL: SELECT DISTINCT * FROM {table} WHERE {filter bean}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param bean 杩囨护鏉′欢 + * + * @return Entity鐨勯泦鍚 + */ + default Set querySet(final Class clazz, final FilterBean bean) { + return querySet(clazz, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷et闆嗗悎
+ * 绛変环SQL: SELECT DISTINCT * FROM {table} WHERE {filter bean}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param bean 杩囨护鏉′欢 + * + * @return Entity鐨勯泦鍚圕ompletableFuture + */ + default CompletableFuture> querySetAsync(final Class clazz, final FilterBean bean) { + return querySetAsync(clazz, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鏌ヨ璁板綍鐨凷et闆嗗悎
+ * 绛変环SQL: SELECT DISTINCT * FROM {table}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * + * @return Entity鐨勯泦鍚 + */ + default Set querySet(final Class clazz) { + return querySet(clazz, (SelectColumn) null, (Flipper) null, (FilterNode) null); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷et闆嗗悎
+ * 绛変环SQL: SELECT DISTINCT * FROM {table} WHERE {filter node}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param node 杩囨护鏉′欢 + * + * @return Entity鐨勯泦鍚 + */ + default Set querySet(final Class clazz, final FilterNode node) { + return querySet(clazz, (SelectColumn) null, (Flipper) null, node); + } + + /** + * 鏌ヨ璁板綍鐨凷et闆嗗悎
+ * 绛変环SQL: SELECT DISTINCT * FROM {table}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * + * @return Entity鐨勯泦鍚圕ompletableFuture + */ + default CompletableFuture> querySetAsync(final Class clazz) { + return querySetAsync(clazz, (SelectColumn) null, (Flipper) null, (FilterNode) null); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷et闆嗗悎
+ * 绛変环SQL: SELECT DISTINCT * FROM {table} WHERE {filter node}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param node 杩囨护鏉′欢 + * + * @return Entity鐨勯泦鍚圕ompletableFuture + */ + default CompletableFuture> querySetAsync(final Class clazz, final FilterNode node) { + return querySetAsync(clazz, (SelectColumn) null, (Flipper) null, node); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷et闆嗗悎
+ * 绛変环SQL: SELECT DISTINCT {column1},{column2}, ··· FROM {table} WHERE {filter bean}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param selects 鎸囧畾瀛楁 + * @param bean 杩囨护鏉′欢 + * + * @return Entity鐨勯泦鍚 + */ + default Set querySet(final Class clazz, final SelectColumn selects, final FilterBean bean) { + return querySet(clazz, selects, (Flipper) null, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷et闆嗗悎
+ * 绛変环SQL: SELECT DISTINCT {column1},{column2}, ··· FROM {table} WHERE {filter bean}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param selects 鎸囧畾瀛楁 + * @param bean 杩囨护鏉′欢 + * + * @return Entity鐨勯泦鍚圕ompletableFuture + */ + default CompletableFuture> querySetAsync(final Class clazz, final SelectColumn selects, final FilterBean bean) { + return querySetAsync(clazz, selects, (Flipper) null, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷et闆嗗悎
+ * 绛変环SQL: SELECT DISTINCT {column1},{column2}, ··· FROM {table} WHERE {filter node}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param selects 鎸囧畾瀛楁 + * @param node 杩囨护鏉′欢 + * + * @return Entity鐨勯泦鍚 + */ + default Set querySet(final Class clazz, final SelectColumn selects, final FilterNode node) { + return querySet(clazz, selects, (Flipper) null, node); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷et闆嗗悎
+ * 绛変环SQL: SELECT DISTINCT {column1},{column2}, ··· FROM {table} WHERE {filter node}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param selects 鎸囧畾瀛楁 + * @param node 杩囨护鏉′欢 + * + * @return Entity鐨勯泦鍚圕ompletableFuture + */ + default CompletableFuture> querySetAsync(final Class clazz, final SelectColumn selects, final FilterNode node) { + return querySetAsync(clazz, selects, (Flipper) null, node); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷et闆嗗悎
+ * 绛変环SQL: SELECT DISTINCT * FROM {table} WHERE {column} = {key} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param flipper 缈婚〉瀵硅薄 + * @param column 杩囨护瀛楁鍚 + * @param colval 杩囨护瀛楁鍊 + * + * @return Entity鐨勯泦鍚 + */ + public Set querySet(final Class clazz, final Flipper flipper, final String column, final Serializable colval); + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷et闆嗗悎
+ * 绛変环SQL: SELECT DISTINCT * FROM {table} WHERE {column} = {key} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param flipper 缈婚〉瀵硅薄 + * @param column 杩囨护瀛楁鍚 + * @param colval 杩囨护瀛楁鍊 + * + * @return Entity鐨勯泦鍚圕ompletableFuture + */ + public CompletableFuture> querySetAsync(final Class clazz, final Flipper flipper, final String column, final Serializable colval); + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷et闆嗗悎
+ * 绛変环SQL: SELECT DISTINCT * FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param flipper 缈婚〉瀵硅薄 + * @param bean 杩囨护鏉′欢 + * + * @return Entity鐨勯泦鍚 + */ + default Set querySet(final Class clazz, final Flipper flipper, final FilterBean bean) { + return querySet(clazz, (SelectColumn) null, flipper, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷et闆嗗悎
+ * 绛変环SQL: SELECT DISTINCT * FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param flipper 缈婚〉瀵硅薄 + * @param bean 杩囨护鏉′欢 + * + * @return Entity鐨勯泦鍚圕ompletableFuture + */ + default CompletableFuture> querySetAsync(final Class clazz, final Flipper flipper, final FilterBean bean) { + return querySetAsync(clazz, (SelectColumn) null, flipper, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷et闆嗗悎
+ * 绛変环SQL: SELECT DISTINCT * FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param flipper 缈婚〉瀵硅薄 + * @param node 杩囨护鏉′欢 + * + * @return Entity鐨勯泦鍚 + * + */ + default Set querySet(final Class clazz, final Flipper flipper, final FilterNode node) { + return querySet(clazz, (SelectColumn) null, flipper, node); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷et闆嗗悎
+ * 绛変环SQL: SELECT DISTINCT * FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param flipper 缈婚〉瀵硅薄 + * @param node 杩囨护鏉′欢 + * + * @return Entity鐨勯泦鍚 + * + */ + default CompletableFuture> querySetAsync(final Class clazz, final Flipper flipper, final FilterNode node) { + return querySetAsync(clazz, (SelectColumn) null, flipper, node); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷et闆嗗悎
+ * 绛変环SQL: SELECT DISTINCT {column1},{column2}, ··· FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param selects 鎸囧畾瀛楁 + * @param flipper 缈婚〉瀵硅薄 + * @param bean 杩囨护鏉′欢 + * + * @return Entity鐨勯泦鍚 + */ + default Set querySet(final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean) { + return querySet(clazz, selects, flipper, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷et闆嗗悎
+ * 绛変环SQL: SELECT DISTINCT {column1},{column2}, ··· FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param selects 鎸囧畾瀛楁 + * @param flipper 缈婚〉瀵硅薄 + * @param bean 杩囨护鏉′欢 + * + * @return Entity鐨勯泦鍚圕ompletableFuture + */ + default CompletableFuture> querySetAsync(final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean) { + return querySetAsync(clazz, selects, flipper, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷et闆嗗悎
+ * 绛変环SQL: SELECT DISTINCT {column1},{column2}, ··· FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param selects 鎸囧畾瀛楁 + * @param flipper 缈婚〉瀵硅薄 + * @param node 杩囨护鏉′欢 + * + * @return Entity鐨勯泦鍚 + */ + public Set querySet(final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node); + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷et闆嗗悎
+ * 绛変环SQL: SELECT DISTINCT {column1},{column2}, ··· FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param selects 鎸囧畾瀛楁 + * @param flipper 缈婚〉瀵硅薄 + * @param node 杩囨护鏉′欢 + * + * @return Entity鐨勯泦鍚圕ompletableFuture + */ + public CompletableFuture> querySetAsync(final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node); + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist闆嗗悎
+ * 绛変环SQL: SELECT * FROM {table} WHERE {column} = {key} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param column 杩囨护瀛楁鍚 + * @param colval 杩囨护瀛楁鍊 + * + * @return Entity鐨勯泦鍚 + */ + default List queryList(final Class clazz, final String column, final Serializable colval) { + return queryList(clazz, (Flipper) null, column, colval); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist闆嗗悎
+ * 绛変环SQL: SELECT * FROM {table} WHERE {column} = {key} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param column 杩囨护瀛楁鍚 + * @param colval 杩囨护瀛楁鍊 + * + * @return Entity鐨勯泦鍚圕ompletableFuture + */ + default CompletableFuture> queryListAsync(final Class clazz, final String column, final Serializable colval) { + return queryListAsync(clazz, (Flipper) null, column, colval); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist闆嗗悎
+ * 绛変环SQL: SELECT * FROM {table} WHERE {filter bean}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param bean 杩囨护鏉′欢 + * + * @return Entity鐨勯泦鍚 + */ + default List queryList(final Class clazz, final FilterBean bean) { + return queryList(clazz, (SelectColumn) null, (Flipper) null, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist闆嗗悎
+ * 绛変环SQL: SELECT * FROM {table} WHERE {filter bean}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param bean 杩囨护鏉′欢 + * + * @return Entity鐨勯泦鍚圕ompletableFuture + */ + default CompletableFuture> queryListAsync(final Class clazz, final FilterBean bean) { + return queryListAsync(clazz, (SelectColumn) null, (Flipper) null, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鏌ヨ璁板綍鐨凩ist闆嗗悎
+ * 绛変环SQL: SELECT * FROM {table}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * + * @return Entity鐨勯泦鍚 + */ + default List queryList(final Class clazz) { + return queryList(clazz, (SelectColumn) null, (Flipper) null, (FilterNode) null); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist闆嗗悎
+ * 绛変环SQL: SELECT * FROM {table} WHERE {filter node}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param node 杩囨护鏉′欢 + * + * @return Entity鐨勯泦鍚 + */ + default List queryList(final Class clazz, final FilterNode node) { + return queryList(clazz, (SelectColumn) null, (Flipper) null, node); + } + + /** + * 鏌ヨ璁板綍鐨凩ist闆嗗悎
+ * 绛変环SQL: SELECT * FROM {table}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * + * @return Entity鐨勯泦鍚圕ompletableFuture + */ + default CompletableFuture> queryListAsync(final Class clazz) { + return queryListAsync(clazz, (SelectColumn) null, (Flipper) null, (FilterNode) null); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist闆嗗悎
+ * 绛変环SQL: SELECT * FROM {table} WHERE {filter node}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param node 杩囨护鏉′欢 + * + * @return Entity鐨勯泦鍚圕ompletableFuture + */ + default CompletableFuture> queryListAsync(final Class clazz, final FilterNode node) { + return queryListAsync(clazz, (SelectColumn) null, (Flipper) null, node); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist闆嗗悎
+ * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter bean}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param selects 鎸囧畾瀛楁 + * @param bean 杩囨护鏉′欢 + * + * @return Entity鐨勯泦鍚 + */ + default List queryList(final Class clazz, final SelectColumn selects, final FilterBean bean) { + return queryList(clazz, selects, (Flipper) null, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist闆嗗悎
+ * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter bean}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param selects 鎸囧畾瀛楁 + * @param bean 杩囨护鏉′欢 + * + * @return Entity鐨勯泦鍚圕ompletableFuture + */ + default CompletableFuture> queryListAsync(final Class clazz, final SelectColumn selects, final FilterBean bean) { + return queryListAsync(clazz, selects, (Flipper) null, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist闆嗗悎
+ * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter node}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param selects 鎸囧畾瀛楁 + * @param node 杩囨护鏉′欢 + * + * @return Entity鐨勯泦鍚 + */ + default List queryList(final Class clazz, final SelectColumn selects, final FilterNode node) { + return queryList(clazz, selects, (Flipper) null, node); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist闆嗗悎
+ * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter node}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param selects 鎸囧畾瀛楁 + * @param node 杩囨护鏉′欢 + * + * @return Entity鐨勯泦鍚圕ompletableFuture + */ + default CompletableFuture> queryListAsync(final Class clazz, final SelectColumn selects, final FilterNode node) { + return queryListAsync(clazz, selects, (Flipper) null, node); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist闆嗗悎
+ * 绛変环SQL: SELECT * FROM {table} WHERE {column} = {key} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param flipper 缈婚〉瀵硅薄 + * @param column 杩囨护瀛楁鍚 + * @param colval 杩囨护瀛楁鍊 + * + * @return Entity鐨勯泦鍚 + */ + public List queryList(final Class clazz, final Flipper flipper, final String column, final Serializable colval); + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist闆嗗悎
+ * 绛変环SQL: SELECT * FROM {table} WHERE {column} = {key} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param flipper 缈婚〉瀵硅薄 + * @param column 杩囨护瀛楁鍚 + * @param colval 杩囨护瀛楁鍊 + * + * @return Entity鐨勯泦鍚圕ompletableFuture + */ + public CompletableFuture> queryListAsync(final Class clazz, final Flipper flipper, final String column, final Serializable colval); + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist闆嗗悎
+ * 绛変环SQL: SELECT * FROM {table} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param flipper 缈婚〉瀵硅薄 + * + * @return Entity鐨勯泦鍚 + */ + default List queryList(final Class clazz, final Flipper flipper) { + return queryList(clazz, (SelectColumn) null, flipper, (FilterNode) null); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist闆嗗悎
+ * 绛変环SQL: SELECT * FROM {table} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param flipper 缈婚〉瀵硅薄 + * + * @return Entity鐨勯泦鍚圕ompletableFuture + */ + default CompletableFuture> queryListAsync(final Class clazz, final Flipper flipper) { + return queryListAsync(clazz, (SelectColumn) null, flipper, (FilterNode) null); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist闆嗗悎
+ * 绛変环SQL: SELECT * FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param flipper 缈婚〉瀵硅薄 + * @param bean 杩囨护鏉′欢 + * + * @return Entity鐨勯泦鍚 + */ + default List queryList(final Class clazz, final Flipper flipper, final FilterBean bean) { + return queryList(clazz, (SelectColumn) null, flipper, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist闆嗗悎
+ * 绛変环SQL: SELECT * FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param flipper 缈婚〉瀵硅薄 + * @param bean 杩囨护鏉′欢 + * + * @return Entity鐨勯泦鍚圕ompletableFuture + */ + default CompletableFuture> queryListAsync(final Class clazz, final Flipper flipper, final FilterBean bean) { + return queryListAsync(clazz, (SelectColumn) null, flipper, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist闆嗗悎
+ * 绛変环SQL: SELECT * FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param flipper 缈婚〉瀵硅薄 + * @param node 杩囨护鏉′欢 + * + * @return Entity鐨勯泦鍚 + * + */ + default List queryList(final Class clazz, final Flipper flipper, final FilterNode node) { + return queryList(clazz, (SelectColumn) null, flipper, node); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist闆嗗悎
+ * 绛変环SQL: SELECT * FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param flipper 缈婚〉瀵硅薄 + * @param node 杩囨护鏉′欢 + * + * @return Entity鐨勯泦鍚 + * + */ + default CompletableFuture> queryListAsync(final Class clazz, final Flipper flipper, final FilterNode node) { + return queryListAsync(clazz, (SelectColumn) null, flipper, node); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist闆嗗悎
+ * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param selects 鎸囧畾瀛楁 + * @param flipper 缈婚〉瀵硅薄 + * + * @return Entity鐨勯泦鍚 + */ + default List queryList(final Class clazz, final SelectColumn selects, final Flipper flipper) { + return queryList(clazz, selects, flipper, (FilterNode) null); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist闆嗗悎
+ * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param selects 鎸囧畾瀛楁 + * @param flipper 缈婚〉瀵硅薄 + * + * @return Entity鐨勯泦鍚圕ompletableFuture + */ + default CompletableFuture> queryListAsync(final Class clazz, final SelectColumn selects, final Flipper flipper) { + return queryListAsync(clazz, selects, flipper, (FilterNode) null); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist闆嗗悎
+ * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param selects 鎸囧畾瀛楁 + * @param flipper 缈婚〉瀵硅薄 + * @param bean 杩囨护鏉′欢 + * + * @return Entity鐨勯泦鍚 + */ + default List queryList(final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean) { + return queryList(clazz, selects, flipper, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist闆嗗悎
+ * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param selects 鎸囧畾瀛楁 + * @param flipper 缈婚〉瀵硅薄 + * @param bean 杩囨护鏉′欢 + * + * @return Entity鐨勯泦鍚圕ompletableFuture + */ + default CompletableFuture> queryListAsync(final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean) { + return queryListAsync(clazz, selects, flipper, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist闆嗗悎
+ * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param selects 鎸囧畾瀛楁 + * @param flipper 缈婚〉瀵硅薄 + * @param node 杩囨护鏉′欢 + * + * @return Entity鐨勯泦鍚 + */ + public List queryList(final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node); + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凩ist闆嗗悎
+ * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param selects 鎸囧畾瀛楁 + * @param flipper 缈婚〉瀵硅薄 + * @param node 杩囨护鏉′欢 + * + * @return Entity鐨勯泦鍚圕ompletableFuture + */ + public CompletableFuture> queryListAsync(final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node); + + //-----------------------sheet---------------------------- + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷heet闆嗗悎
+ * 绛変环SQL: SELECT * FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param flipper 缈婚〉瀵硅薄 + * @param bean 杩囨护鏉′欢 + * + * @return Entity鐨勯泦鍚 + */ + default Sheet querySheet(final Class clazz, final Flipper flipper, final FilterBean bean) { + return querySheet(clazz, (SelectColumn) null, flipper, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷heet闆嗗悎
+ * 绛変环SQL: SELECT * FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param flipper 缈婚〉瀵硅薄 + * @param bean 杩囨护鏉′欢 + * + * @return Entity鐨勯泦鍚圕ompletableFuture + */ + default CompletableFuture> querySheetAsync(final Class clazz, final Flipper flipper, final FilterBean bean) { + return querySheetAsync(clazz, (SelectColumn) null, flipper, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷heet闆嗗悎
+ * 绛変环SQL: SELECT * FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param flipper 缈婚〉瀵硅薄 + * @param node 杩囨护鏉′欢 + * + * @return Entity鐨勯泦鍚 + */ + default Sheet querySheet(final Class clazz, final Flipper flipper, final FilterNode node) { + return querySheet(clazz, (SelectColumn) null, flipper, node); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷heet闆嗗悎
+ * 绛変环SQL: SELECT * FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param flipper 缈婚〉瀵硅薄 + * @param node 杩囨护鏉′欢 + * + * @return Entity鐨勯泦鍚圕ompletableFuture + */ + default CompletableFuture> querySheetAsync(final Class clazz, final Flipper flipper, final FilterNode node) { + return querySheetAsync(clazz, (SelectColumn) null, flipper, node); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷heet闆嗗悎
+ * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param selects 鎸囧畾瀛楁 + * @param flipper 缈婚〉瀵硅薄 + * @param bean 杩囨护鏉′欢 + * + * @return Entity鐨勯泦鍚 + */ + default Sheet querySheet(final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean) { + return querySheet(clazz, selects, flipper, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷heet闆嗗悎
+ * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter bean} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param selects 鎸囧畾瀛楁 + * @param flipper 缈婚〉瀵硅薄 + * @param bean 杩囨护鏉′欢 + * + * @return Entity鐨勯泦鍚圕ompletableFuture + */ + default CompletableFuture> querySheetAsync(final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterBean bean) { + return querySheetAsync(clazz, selects, flipper, FilterNodeBean.createFilterNode(bean)); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷heet闆嗗悎
+ * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param selects 鎸囧畾瀛楁 + * @param flipper 缈婚〉瀵硅薄 + * @param node 杩囨护鏉′欢 + * + * @return Entity鐨勯泦鍚 + */ + public Sheet querySheet(final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node); + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凷heet闆嗗悎
+ * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {filter node} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param selects 鎸囧畾瀛楁 + * @param flipper 缈婚〉瀵硅薄 + * @param node 杩囨护鏉′欢 + * + * @return Entity鐨勯泦鍚圕ompletableFuture + */ + public CompletableFuture> querySheetAsync(final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node); + +} diff --git a/src/main/java/org/redkale/source/DataSourceProvider.java b/src/main/java/org/redkale/source/DataSourceProvider.java index c07b45fa9..ffbc21b7a 100644 --- a/src/main/java/org/redkale/source/DataSourceProvider.java +++ b/src/main/java/org/redkale/source/DataSourceProvider.java @@ -1,25 +1,25 @@ -/* - * 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.source; - -import org.redkale.util.AnyValue; - -/** - * - * 鑷畾涔夌殑DataSource鍔犺浇鍣, 濡傛灉鏍囪@Priority鍔犺浇鍣ㄧ殑浼樺厛绾ч渶瑕佸ぇ浜1000锛 1000浠ヤ笅棰勭暀缁欏畼鏂瑰姞杞藉櫒 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @since 2.5.0 - */ -public interface DataSourceProvider { - - public boolean acceptsConf(AnyValue config); - - public Class sourceClass(); -} +/* + * 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.source; + +import org.redkale.util.AnyValue; + +/** + * + * 鑷畾涔夌殑DataSource鍔犺浇鍣, 濡傛灉鏍囪@Priority鍔犺浇鍣ㄧ殑浼樺厛绾ч渶瑕佸ぇ浜1000锛 1000浠ヤ笅棰勭暀缁欏畼鏂瑰姞杞藉櫒 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @since 2.5.0 + */ +public interface DataSourceProvider { + + public boolean acceptsConf(AnyValue config); + + public Class sourceClass(); +} diff --git a/src/main/java/org/redkale/source/DataSources.java b/src/main/java/org/redkale/source/DataSources.java index b12cf2ccb..daf0d13d3 100644 --- a/src/main/java/org/redkale/source/DataSources.java +++ b/src/main/java/org/redkale/source/DataSources.java @@ -1,315 +1,315 @@ -/* - * 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.source; - -import java.io.*; -import java.lang.reflect.Constructor; -import java.net.*; -import java.util.*; -import javax.annotation.Priority; -import org.redkale.convert.json.JsonConvert; -import org.redkale.util.AnyValue; -import org.redkale.util.RedkaleClassLoader; - -/** - * - * @author zhangjx - */ -public final class DataSources { - - public static final String DATASOURCE_CONFPATH = "DATASOURCE_CONFPATH"; - - public static final String JDBC_DATASOURCE_CLASS = "javax.persistence.datasource"; - - public static final String JDBC_TABLE_AUTODDL = "javax.persistence.table.autoddl"; - - public static final String JDBC_CACHE_MODE = "javax.persistence.cachemode"; - - public static final String JDBC_CONNECTIONS_LIMIT = "javax.persistence.connections.limit"; - - public static final String JDBC_CONNECTIONSCAPACITY = "javax.persistence.connections.bufcapacity"; - - public static final String JDBC_CONTAIN_SQLTEMPLATE = "javax.persistence.contain.sqltemplate"; - - public static final String JDBC_NOTCONTAIN_SQLTEMPLATE = "javax.persistence.notcontain.sqltemplate"; - - public static final String JDBC_TABLENOTEXIST_SQLSTATES = "javax.persistence.tablenotexist.sqlstates"; - - public static final String JDBC_TABLECOPY_SQLTEMPLATE = "javax.persistence.tablecopy.sqltemplate"; - - public static final String JDBC_CONNECTTIMEOUT_SECONDS = "javax.persistence.connecttimeout"; - - public static final String JDBC_READTIMEOUT_SECONDS = "javax.persistence.readtimeout"; - - public static final String JDBC_WRITETIMEOUT_SECONDS = "javax.persistence.writetimeout"; - - public static final String JDBC_URL = "javax.persistence.jdbc.url"; - - public static final String JDBC_USER = "javax.persistence.jdbc.user"; - - public static final String JDBC_PWD = "javax.persistence.jdbc.password"; - - public static final String JDBC_ENCODING = "javax.persistence.jdbc.encoding"; - - @Deprecated //@deprecated @since 2.5.0 - public static final String JDBC_DRIVER = "javax.persistence.jdbc.driver"; - - @Deprecated //@deprecated @since 2.5.0 - public static final String JDBC_SOURCE = "javax.persistence.jdbc.source"; - - //@since 2.4.0 for SearchSource default value: true - public static final String JDBC_AUTO_MAPPING = "javax.persistence.jdbc.auto-mapping"; - - private DataSources() { - } - - public static DataSource createDataSource(final String unitName, final AnyValue conf) throws IOException { - Properties prop = new Properties(); - AnyValue[] confs = conf.getAnyValues("property"); - if (confs != null) { - for (AnyValue itemConf : confs) { - String name = itemConf.getValue("name"); - String value = itemConf.getValue("value"); - if (name != null && value != null) prop.put(name, value); - } - } - return createDataSource(unitName, prop, prop); - } - - public static DataSource createDataSource(final String unitName, Properties prop) throws IOException { - return createDataSource(unitName, prop, prop); - } - - public static DataSource createDataSource(final String unitName, Properties readprop, Properties writeprop) throws IOException { - return createDataSource(unitName, null, readprop, writeprop); - } - - public static DataSource createDataSource(final String unitName, URL persistxml, Properties readprop, Properties writeprop) throws IOException { - String impl = readprop.getProperty(JDBC_DATASOURCE_CLASS, DataJdbcSource.class.getName()); - String dbtype = null; - if (DataJdbcSource.class.getName().equals(impl)) { - if (DataJdbcSource.acceptsConf(readprop)) { - return new DataJdbcSource(unitName, persistxml, parseDbtype(readprop.getProperty(JDBC_URL)), readprop, writeprop); - } - String url = readprop.getProperty(JDBC_URL); - dbtype = parseDbtype(url); - if (dbtype == null) throw new RuntimeException("not found datasource implements class, url=" + url); - - RedkaleClassLoader.putServiceLoader(DataSourceProvider.class); - Class dsClass = null; - final AnyValue.DefaultAnyValue lc = new AnyValue.DefaultAnyValue(); - readprop.forEach((k, v) -> lc.addValue(k.toString(), v.toString())); - lc.setValue("dbtype", dbtype); - List providers = new ArrayList<>(); - Iterator it = ServiceLoader.load(DataSourceProvider.class).iterator(); - while (it.hasNext()) { - DataSourceProvider provider = it.next(); - if (provider != null) { - RedkaleClassLoader.putReflectionPublicConstructors(provider.getClass(), provider.getClass().getName()); - } - if (provider != null && provider.acceptsConf(lc)) { - providers.add(provider); - } - } - Collections.sort(providers, (a, b) -> { - Priority p1 = a == null ? null : a.getClass().getAnnotation(Priority.class); - Priority p2 = b == null ? null : b.getClass().getAnnotation(Priority.class); - return (p2 == null ? 0 : p2.value()) - (p1 == null ? 0 : p1.value()); - }); - for (DataSourceProvider provider : providers) { - dsClass = provider.sourceClass(); - if (dsClass != null) break; - } - if (dsClass == null) throw new RuntimeException("not found datasource implements ServiceLoader, url=" + url); - impl = dsClass.getName(); - } - try { - Class ds = Thread.currentThread().getContextClassLoader().loadClass(impl); - RedkaleClassLoader.putReflectionPublicConstructors(ds, impl); - for (Constructor d : ds.getConstructors()) { - Class[] paramtypes = d.getParameterTypes(); - if (paramtypes.length == 1 && paramtypes[0] == Properties.class) { - RedkaleClassLoader.putReflectionDeclaredConstructors(ds, impl, Properties.class); - return (DataSource) d.newInstance(readprop); - } else if (paramtypes.length == 2 && paramtypes[0] == String.class && paramtypes[1] == Properties.class) { - RedkaleClassLoader.putReflectionDeclaredConstructors(ds, impl, String.class, Properties.class); - return (DataSource) d.newInstance(unitName, readprop); - } else if (paramtypes.length == 3 && paramtypes[0] == String.class && paramtypes[1] == Properties.class && paramtypes[2] == Properties.class) { - RedkaleClassLoader.putReflectionDeclaredConstructors(ds, impl, String.class, Properties.class, Properties.class); - return (DataSource) d.newInstance(unitName, readprop, writeprop); - } else if (paramtypes.length == 4 && paramtypes[0] == String.class && paramtypes[1] == String.class && paramtypes[2] == Properties.class && paramtypes[3] == Properties.class) { - RedkaleClassLoader.putReflectionDeclaredConstructors(ds, impl, String.class, String.class, Properties.class, Properties.class); - return (DataSource) d.newInstance(unitName, dbtype, readprop, writeprop); - } else if (paramtypes.length == 4 && paramtypes[0] == String.class && paramtypes[1] == URL.class && paramtypes[2] == Properties.class && paramtypes[3] == Properties.class) { - RedkaleClassLoader.putReflectionDeclaredConstructors(ds, impl, String.class, URL.class, Properties.class, Properties.class); - return (DataSource) d.newInstance(unitName, persistxml, readprop, writeprop); - } else if (paramtypes.length == 5 && paramtypes[0] == String.class && paramtypes[1] == URL.class && paramtypes[2] == String.class && paramtypes[3] == Properties.class && paramtypes[4] == Properties.class) { - RedkaleClassLoader.putReflectionDeclaredConstructors(ds, impl, String.class, URL.class, Properties.class, Properties.class); - if (dbtype == null) dbtype = parseDbtype(readprop.getProperty(JDBC_URL)); - return (DataSource) d.newInstance(unitName, persistxml, dbtype, readprop, writeprop); - } - } - throw new IOException("DataSource impl class (" + impl + ") have no Constructor by (Properties prop) or (String name, Properties prop) or (String name, Properties readprop, Propertieswriteprop) or (String name, URL persistxml, Properties readprop, Propertieswriteprop)"); - } catch (IOException ex) { - throw ex; - } catch (Exception e) { - throw new IOException(e); - } - } - - public static String parseDbtype(String url) { - String dbtype = null; - if (url.startsWith("http://") || url.startsWith("https://") || url.startsWith("search://") || url.startsWith("searchs://")) { //elasticsearch or opensearch - dbtype = "search"; - } else { - /* jdbc:mysql:// jdbc:microsoft:sqlserver:// 鍙://涔嬪墠鐨勫埌鏈鍚庝竴涓:涔嬮棿鐨勫瓧绗︿覆 */ - int pos = url.indexOf("://"); - if (pos > 0) { - String url0 = url.substring(0, pos); - pos = url0.lastIndexOf(':'); - if (pos > 0) { - dbtype = url0.substring(pos + 1); - } else { //mongodb://127.0.01:27017 - dbtype = url0; - } - } else { //jdbc:oracle:thin:@localhost:1521 - String url0 = url.substring(url.indexOf(":") + 1); - pos = url0.indexOf(':'); - if (pos > 0) dbtype = url0.substring(0, pos); - } - } - if ("mariadb".equals(dbtype)) return "mysql"; - return dbtype; - } - - public static DataSource createDataSource(final String confURI, final String unitName) throws IOException { - return createDataSource(unitName, System.getProperty(DATASOURCE_CONFPATH, "").isEmpty() - ? RedkaleClassLoader.getConfResourceAsURI(confURI, "persistence.xml").toURL() - : (System.getProperty(DATASOURCE_CONFPATH, "").contains("://") ? URI.create(System.getProperty(DATASOURCE_CONFPATH)).toURL() : new File(System.getProperty(DATASOURCE_CONFPATH)).toURI().toURL())); - } - - public static DataSource createDataSource(final String unitName, URL persistxml) throws IOException { - if (persistxml == null) persistxml = DataSources.class.getResource("/persistence.xml"); - InputStream in = persistxml == null ? null : persistxml.openStream(); - if (in == null) return null; - Map map = loadPersistenceXml(in); - Properties readprop = null; - Properties writeprop = null; - if (unitName != null) { - readprop = map.get(unitName); - writeprop = readprop; - if (readprop == null) { - readprop = map.get(unitName + ".read"); - writeprop = map.get(unitName + ".write"); - } - } - if (unitName == null || unitName.isEmpty()) { - String key = null; - for (Map.Entry en : map.entrySet()) { - key = en.getKey(); - readprop = en.getValue(); - writeprop = readprop; - break; - } - if (key != null && (key.endsWith(".read") || key.endsWith(".write"))) { - if (key.endsWith(".read")) { - writeprop = map.get(key.substring(0, key.lastIndexOf('.')) + ".write"); - } else { - readprop = map.get(key.substring(0, key.lastIndexOf('.')) + ".read"); - } - } - } - if (readprop == null) throw new IOException("Cannot find (resource.name = '" + unitName + "') DataSource"); - if (writeprop == null) writeprop = readprop; - if (readprop.getProperty(JDBC_URL, "").startsWith("memory:source")) return new DataMemorySource(unitName, persistxml, readprop, writeprop); - - return createDataSource(unitName, readprop, writeprop); - } - - public static Map loadPersistenceXml(final InputStream in0) { - final Map map = new LinkedHashMap(); - - boolean flag = false; - try (final InputStream in = in0) { - - AnyValue config = AnyValue.loadFromXml(in).getAnyValue("persistence"); - - for (AnyValue conf : config.getAnyValues("persistence-unit")) { - Properties result = new Properties(); - conf.forEach(null, (n, c) -> { - if ("properties".equals(n)) { - for (AnyValue sub : c.getAnyValues("property")) { - result.put(sub.getValue("name"), sub.getValue("value")); - } - } else { - String v = c.getValue(AnyValue.XML_TEXT_NODE_NAME); - if (v != null) { - if ("shared-cache-mode".equalsIgnoreCase(n)) { - result.put(JDBC_CACHE_MODE, v); - } else { - result.put(n, v); - } - } - } - }); - map.put(conf.getValue("name"), result); - } - in.close(); - } catch (Exception ex) { - throw new RuntimeException(ex); - } - return map; - } - - public static UrlInfo parseUrl(final String url) { - final UrlInfo info = new UrlInfo(); - info.url = url; - if (url.startsWith("jdbc:h2:")) return info; - String url0 = url.substring(url.indexOf("://") + 3); - int pos = url0.indexOf('?'); //127.0.0.1:5432/db?charset=utr8&xxx=yy - if (pos > 0) { - String params = url0.substring(pos + 1).replace("&", "&"); - for (String param : params.split("&")) { - int p = param.indexOf('='); - if (p < 1) continue; - info.attributes.put(param.substring(0, p), param.substring(p + 1)); - } - url0 = url0.substring(0, pos); - } - pos = url0.indexOf('/'); //127.0.0.1:5432/db - if (pos > 0) { - info.database = url0.substring(pos + 1); - url0 = url0.substring(0, pos); - } - pos = url0.indexOf(':'); - if (pos > 0) { - info.servaddr = new InetSocketAddress(url0.substring(0, pos), Integer.parseInt(url0.substring(pos + 1))); - } else if (url.startsWith("http://")) { - info.servaddr = new InetSocketAddress(url0, 80); - } else if (url.startsWith("https://")) { - info.servaddr = new InetSocketAddress(url0, 443); - } else { - throw new RuntimeException(url + " parse port error"); - } - return info; - } - - public static class UrlInfo { - - public Properties attributes = new Properties(); - - public String url; - - public String database; - - public InetSocketAddress servaddr; - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - } -} +/* + * 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.source; + +import java.io.*; +import java.lang.reflect.Constructor; +import java.net.*; +import java.util.*; +import javax.annotation.Priority; +import org.redkale.convert.json.JsonConvert; +import org.redkale.util.AnyValue; +import org.redkale.util.RedkaleClassLoader; + +/** + * + * @author zhangjx + */ +public final class DataSources { + + public static final String DATASOURCE_CONFPATH = "DATASOURCE_CONFPATH"; + + public static final String JDBC_DATASOURCE_CLASS = "javax.persistence.datasource"; + + public static final String JDBC_TABLE_AUTODDL = "javax.persistence.table.autoddl"; + + public static final String JDBC_CACHE_MODE = "javax.persistence.cachemode"; + + public static final String JDBC_CONNECTIONS_LIMIT = "javax.persistence.connections.limit"; + + public static final String JDBC_CONNECTIONSCAPACITY = "javax.persistence.connections.bufcapacity"; + + public static final String JDBC_CONTAIN_SQLTEMPLATE = "javax.persistence.contain.sqltemplate"; + + public static final String JDBC_NOTCONTAIN_SQLTEMPLATE = "javax.persistence.notcontain.sqltemplate"; + + public static final String JDBC_TABLENOTEXIST_SQLSTATES = "javax.persistence.tablenotexist.sqlstates"; + + public static final String JDBC_TABLECOPY_SQLTEMPLATE = "javax.persistence.tablecopy.sqltemplate"; + + public static final String JDBC_CONNECTTIMEOUT_SECONDS = "javax.persistence.connecttimeout"; + + public static final String JDBC_READTIMEOUT_SECONDS = "javax.persistence.readtimeout"; + + public static final String JDBC_WRITETIMEOUT_SECONDS = "javax.persistence.writetimeout"; + + public static final String JDBC_URL = "javax.persistence.jdbc.url"; + + public static final String JDBC_USER = "javax.persistence.jdbc.user"; + + public static final String JDBC_PWD = "javax.persistence.jdbc.password"; + + public static final String JDBC_ENCODING = "javax.persistence.jdbc.encoding"; + + @Deprecated //@deprecated @since 2.5.0 + public static final String JDBC_DRIVER = "javax.persistence.jdbc.driver"; + + @Deprecated //@deprecated @since 2.5.0 + public static final String JDBC_SOURCE = "javax.persistence.jdbc.source"; + + //@since 2.4.0 for SearchSource default value: true + public static final String JDBC_AUTO_MAPPING = "javax.persistence.jdbc.auto-mapping"; + + private DataSources() { + } + + public static DataSource createDataSource(final String unitName, final AnyValue conf) throws IOException { + Properties prop = new Properties(); + AnyValue[] confs = conf.getAnyValues("property"); + if (confs != null) { + for (AnyValue itemConf : confs) { + String name = itemConf.getValue("name"); + String value = itemConf.getValue("value"); + if (name != null && value != null) prop.put(name, value); + } + } + return createDataSource(unitName, prop, prop); + } + + public static DataSource createDataSource(final String unitName, Properties prop) throws IOException { + return createDataSource(unitName, prop, prop); + } + + public static DataSource createDataSource(final String unitName, Properties readprop, Properties writeprop) throws IOException { + return createDataSource(unitName, null, readprop, writeprop); + } + + public static DataSource createDataSource(final String unitName, URL persistxml, Properties readprop, Properties writeprop) throws IOException { + String impl = readprop.getProperty(JDBC_DATASOURCE_CLASS, DataJdbcSource.class.getName()); + String dbtype = null; + if (DataJdbcSource.class.getName().equals(impl)) { + if (DataJdbcSource.acceptsConf(readprop)) { + return new DataJdbcSource(unitName, persistxml, parseDbtype(readprop.getProperty(JDBC_URL)), readprop, writeprop); + } + String url = readprop.getProperty(JDBC_URL); + dbtype = parseDbtype(url); + if (dbtype == null) throw new RuntimeException("not found datasource implements class, url=" + url); + + RedkaleClassLoader.putServiceLoader(DataSourceProvider.class); + Class dsClass = null; + final AnyValue.DefaultAnyValue lc = new AnyValue.DefaultAnyValue(); + readprop.forEach((k, v) -> lc.addValue(k.toString(), v.toString())); + lc.setValue("dbtype", dbtype); + List providers = new ArrayList<>(); + Iterator it = ServiceLoader.load(DataSourceProvider.class).iterator(); + while (it.hasNext()) { + DataSourceProvider provider = it.next(); + if (provider != null) { + RedkaleClassLoader.putReflectionPublicConstructors(provider.getClass(), provider.getClass().getName()); + } + if (provider != null && provider.acceptsConf(lc)) { + providers.add(provider); + } + } + Collections.sort(providers, (a, b) -> { + Priority p1 = a == null ? null : a.getClass().getAnnotation(Priority.class); + Priority p2 = b == null ? null : b.getClass().getAnnotation(Priority.class); + return (p2 == null ? 0 : p2.value()) - (p1 == null ? 0 : p1.value()); + }); + for (DataSourceProvider provider : providers) { + dsClass = provider.sourceClass(); + if (dsClass != null) break; + } + if (dsClass == null) throw new RuntimeException("not found datasource implements ServiceLoader, url=" + url); + impl = dsClass.getName(); + } + try { + Class ds = Thread.currentThread().getContextClassLoader().loadClass(impl); + RedkaleClassLoader.putReflectionPublicConstructors(ds, impl); + for (Constructor d : ds.getConstructors()) { + Class[] paramtypes = d.getParameterTypes(); + if (paramtypes.length == 1 && paramtypes[0] == Properties.class) { + RedkaleClassLoader.putReflectionDeclaredConstructors(ds, impl, Properties.class); + return (DataSource) d.newInstance(readprop); + } else if (paramtypes.length == 2 && paramtypes[0] == String.class && paramtypes[1] == Properties.class) { + RedkaleClassLoader.putReflectionDeclaredConstructors(ds, impl, String.class, Properties.class); + return (DataSource) d.newInstance(unitName, readprop); + } else if (paramtypes.length == 3 && paramtypes[0] == String.class && paramtypes[1] == Properties.class && paramtypes[2] == Properties.class) { + RedkaleClassLoader.putReflectionDeclaredConstructors(ds, impl, String.class, Properties.class, Properties.class); + return (DataSource) d.newInstance(unitName, readprop, writeprop); + } else if (paramtypes.length == 4 && paramtypes[0] == String.class && paramtypes[1] == String.class && paramtypes[2] == Properties.class && paramtypes[3] == Properties.class) { + RedkaleClassLoader.putReflectionDeclaredConstructors(ds, impl, String.class, String.class, Properties.class, Properties.class); + return (DataSource) d.newInstance(unitName, dbtype, readprop, writeprop); + } else if (paramtypes.length == 4 && paramtypes[0] == String.class && paramtypes[1] == URL.class && paramtypes[2] == Properties.class && paramtypes[3] == Properties.class) { + RedkaleClassLoader.putReflectionDeclaredConstructors(ds, impl, String.class, URL.class, Properties.class, Properties.class); + return (DataSource) d.newInstance(unitName, persistxml, readprop, writeprop); + } else if (paramtypes.length == 5 && paramtypes[0] == String.class && paramtypes[1] == URL.class && paramtypes[2] == String.class && paramtypes[3] == Properties.class && paramtypes[4] == Properties.class) { + RedkaleClassLoader.putReflectionDeclaredConstructors(ds, impl, String.class, URL.class, Properties.class, Properties.class); + if (dbtype == null) dbtype = parseDbtype(readprop.getProperty(JDBC_URL)); + return (DataSource) d.newInstance(unitName, persistxml, dbtype, readprop, writeprop); + } + } + throw new IOException("DataSource impl class (" + impl + ") have no Constructor by (Properties prop) or (String name, Properties prop) or (String name, Properties readprop, Propertieswriteprop) or (String name, URL persistxml, Properties readprop, Propertieswriteprop)"); + } catch (IOException ex) { + throw ex; + } catch (Exception e) { + throw new IOException(e); + } + } + + public static String parseDbtype(String url) { + String dbtype = null; + if (url.startsWith("http://") || url.startsWith("https://") || url.startsWith("search://") || url.startsWith("searchs://")) { //elasticsearch or opensearch + dbtype = "search"; + } else { + /* jdbc:mysql:// jdbc:microsoft:sqlserver:// 鍙://涔嬪墠鐨勫埌鏈鍚庝竴涓:涔嬮棿鐨勫瓧绗︿覆 */ + int pos = url.indexOf("://"); + if (pos > 0) { + String url0 = url.substring(0, pos); + pos = url0.lastIndexOf(':'); + if (pos > 0) { + dbtype = url0.substring(pos + 1); + } else { //mongodb://127.0.01:27017 + dbtype = url0; + } + } else { //jdbc:oracle:thin:@localhost:1521 + String url0 = url.substring(url.indexOf(":") + 1); + pos = url0.indexOf(':'); + if (pos > 0) dbtype = url0.substring(0, pos); + } + } + if ("mariadb".equals(dbtype)) return "mysql"; + return dbtype; + } + + public static DataSource createDataSource(final String confURI, final String unitName) throws IOException { + return createDataSource(unitName, System.getProperty(DATASOURCE_CONFPATH, "").isEmpty() + ? RedkaleClassLoader.getConfResourceAsURI(confURI, "persistence.xml").toURL() + : (System.getProperty(DATASOURCE_CONFPATH, "").contains("://") ? URI.create(System.getProperty(DATASOURCE_CONFPATH)).toURL() : new File(System.getProperty(DATASOURCE_CONFPATH)).toURI().toURL())); + } + + public static DataSource createDataSource(final String unitName, URL persistxml) throws IOException { + if (persistxml == null) persistxml = DataSources.class.getResource("/persistence.xml"); + InputStream in = persistxml == null ? null : persistxml.openStream(); + if (in == null) return null; + Map map = loadPersistenceXml(in); + Properties readprop = null; + Properties writeprop = null; + if (unitName != null) { + readprop = map.get(unitName); + writeprop = readprop; + if (readprop == null) { + readprop = map.get(unitName + ".read"); + writeprop = map.get(unitName + ".write"); + } + } + if (unitName == null || unitName.isEmpty()) { + String key = null; + for (Map.Entry en : map.entrySet()) { + key = en.getKey(); + readprop = en.getValue(); + writeprop = readprop; + break; + } + if (key != null && (key.endsWith(".read") || key.endsWith(".write"))) { + if (key.endsWith(".read")) { + writeprop = map.get(key.substring(0, key.lastIndexOf('.')) + ".write"); + } else { + readprop = map.get(key.substring(0, key.lastIndexOf('.')) + ".read"); + } + } + } + if (readprop == null) throw new IOException("Cannot find (resource.name = '" + unitName + "') DataSource"); + if (writeprop == null) writeprop = readprop; + if (readprop.getProperty(JDBC_URL, "").startsWith("memory:source")) return new DataMemorySource(unitName, persistxml, readprop, writeprop); + + return createDataSource(unitName, readprop, writeprop); + } + + public static Map loadPersistenceXml(final InputStream in0) { + final Map map = new LinkedHashMap(); + + boolean flag = false; + try (final InputStream in = in0) { + + AnyValue config = AnyValue.loadFromXml(in).getAnyValue("persistence"); + + for (AnyValue conf : config.getAnyValues("persistence-unit")) { + Properties result = new Properties(); + conf.forEach(null, (n, c) -> { + if ("properties".equals(n)) { + for (AnyValue sub : c.getAnyValues("property")) { + result.put(sub.getValue("name"), sub.getValue("value")); + } + } else { + String v = c.getValue(AnyValue.XML_TEXT_NODE_NAME); + if (v != null) { + if ("shared-cache-mode".equalsIgnoreCase(n)) { + result.put(JDBC_CACHE_MODE, v); + } else { + result.put(n, v); + } + } + } + }); + map.put(conf.getValue("name"), result); + } + in.close(); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + return map; + } + + public static UrlInfo parseUrl(final String url) { + final UrlInfo info = new UrlInfo(); + info.url = url; + if (url.startsWith("jdbc:h2:")) return info; + String url0 = url.substring(url.indexOf("://") + 3); + int pos = url0.indexOf('?'); //127.0.0.1:5432/db?charset=utr8&xxx=yy + if (pos > 0) { + String params = url0.substring(pos + 1).replace("&", "&"); + for (String param : params.split("&")) { + int p = param.indexOf('='); + if (p < 1) continue; + info.attributes.put(param.substring(0, p), param.substring(p + 1)); + } + url0 = url0.substring(0, pos); + } + pos = url0.indexOf('/'); //127.0.0.1:5432/db + if (pos > 0) { + info.database = url0.substring(pos + 1); + url0 = url0.substring(0, pos); + } + pos = url0.indexOf(':'); + if (pos > 0) { + info.servaddr = new InetSocketAddress(url0.substring(0, pos), Integer.parseInt(url0.substring(pos + 1))); + } else if (url.startsWith("http://")) { + info.servaddr = new InetSocketAddress(url0, 80); + } else if (url.startsWith("https://")) { + info.servaddr = new InetSocketAddress(url0, 443); + } else { + throw new RuntimeException(url + " parse port error"); + } + return info; + } + + public static class UrlInfo { + + public Properties attributes = new Properties(); + + public String url; + + public String database; + + public InetSocketAddress servaddr; + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + } +} diff --git a/src/main/java/org/redkale/source/DataSqlSource.java b/src/main/java/org/redkale/source/DataSqlSource.java index bb96626d5..be99b0dfa 100644 --- a/src/main/java/org/redkale/source/DataSqlSource.java +++ b/src/main/java/org/redkale/source/DataSqlSource.java @@ -1,2130 +1,2130 @@ -/* - * 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.source; - -import java.io.Serializable; -import java.math.*; -import java.net.URL; -import java.util.*; -import java.util.concurrent.*; -import java.util.concurrent.atomic.*; -import java.util.function.*; -import java.util.logging.*; -import java.util.stream.Stream; -import javax.annotation.Resource; -import static org.redkale.boot.Application.*; -import org.redkale.net.AsyncGroup; -import org.redkale.service.*; -import static org.redkale.source.DataSources.*; -import org.redkale.source.EntityInfo.EntityColumn; -import org.redkale.util.*; - -/** - * DataSource鐨凷QL鎶借薄瀹炵幇绫
- * 娉ㄦ剰: 鎵鏈夌殑鎿嶄綔鍙兘浣滅敤鍦ㄤ竴寮犺〃涓婏紝涓嶈兘鍚屾椂鍙樻洿澶氬紶琛 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@Local -@AutoLoad(false) -@SuppressWarnings("unchecked") -@ResourceType(DataSource.class) -public abstract class DataSqlSource extends AbstractDataSource implements Function { - - protected static final Flipper FLIPPER_ONE = new Flipper(1); - - protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); - - protected String name; - - protected URL persistFile; - - protected boolean cacheForbidden; - - private final String dbtype; - - private final boolean autoddl; - - protected Properties readConfProps; - - protected Properties writeConfProps; - - @Resource(name = RESNAME_APP_ASYNCGROUP) - protected AsyncGroup asyncGroup; - - @Resource(name = RESNAME_APP_EXECUTOR) - protected ExecutorService workExecutor; - - protected final BiFunction sqlFormatter; - - protected BiConsumer futureCompleteConsumer = (r, t) -> { - if (t != null) logger.log(Level.INFO, "CompletableFuture complete error", (Throwable) t); - }; - - protected final BiFunction> fullloader = (s, i) - -> ((CompletableFuture) querySheetDB(i, false, false, false, null, null, (FilterNode) null)).thenApply(e -> e == null ? new ArrayList() : e.list(true)); - - //鐢ㄤ簬鍙嶅悜LIKE浣跨敤 - protected final String containSQL; - - //鐢ㄤ簬鍙嶅悜LIKE浣跨敤 - protected final String notcontainSQL; - - //鐢ㄤ簬鍒ゆ柇琛ㄤ笉瀛樺湪鐨勪娇鐢, 澶氫釜SQLState鐢;闅斿紑 - protected final String tablenotexistSqlstates; - - //鐢ㄤ簬澶嶅埗琛ㄧ粨鏋勪娇鐢 - protected final String tablecopySQL; - - @SuppressWarnings({"OverridableMethodCallInConstructor", "LeakingThisInConstructor"}) - public DataSqlSource(String unitName, URL persistFile, String dbtype, Properties readConf, Properties writeConf) { - if (readConf == null) readConf = new Properties(); - if (writeConf == null) writeConf = readConf; - this.dbtype = dbtype; - initProperties(readConf); - if (writeConf != readConf) initProperties(writeConf); - this.name = unitName; - this.persistFile = persistFile; - this.readConfProps = readConf; - this.writeConfProps = writeConf; - this.sqlFormatter = (info, val) -> formatValueToString(info, val); - this.autoddl = "true".equals(readConf.getProperty(DataSources.JDBC_TABLE_AUTODDL, "false").trim()); - - this.containSQL = readConf.getProperty(DataSources.JDBC_CONTAIN_SQLTEMPLATE, "LOCATE(${keystr}, ${column}) > 0"); - this.notcontainSQL = readConf.getProperty(DataSources.JDBC_NOTCONTAIN_SQLTEMPLATE, "LOCATE(${keystr}, ${column}) = 0"); - - this.tablenotexistSqlstates = ";" + readConf.getProperty(DataSources.JDBC_TABLENOTEXIST_SQLSTATES, "42000;42S02") + ";"; - this.tablecopySQL = readConf.getProperty(DataSources.JDBC_TABLECOPY_SQLTEMPLATE, "CREATE TABLE IF NOT EXISTS ${newtable} LIKE ${oldtable}"); - } - - protected void initProperties(Properties props) { - if ("oracle".equals(this.dbtype)) { - props.setProperty(JDBC_CONTAIN_SQLTEMPLATE, "INSTR(${keystr}, ${column}) > 0"); - props.setProperty(JDBC_NOTCONTAIN_SQLTEMPLATE, "INSTR(${keystr}, ${column}) = 0"); - if (!props.containsKey(JDBC_TABLENOTEXIST_SQLSTATES)) { - props.setProperty(JDBC_TABLENOTEXIST_SQLSTATES, "42000;42S02"); - } - if (!props.containsKey(JDBC_TABLECOPY_SQLTEMPLATE)) { - //娉ㄦ剰锛氭璇彞澶嶅埗琛ㄧ粨鏋勪細瀵艰嚧榛樿鍊煎拰涓婚敭淇℃伅鐨勪涪澶 - props.setProperty(JDBC_TABLECOPY_SQLTEMPLATE, "CREATE TABLE IF NOT EXISTS ${newtable} AS SELECT * FROM ${oldtable} WHERE 1=2"); - } - } else if ("sqlserver".equals(this.dbtype)) { - props.setProperty(JDBC_CONTAIN_SQLTEMPLATE, "CHARINDEX(${column}, ${keystr}) > 0"); - props.setProperty(JDBC_NOTCONTAIN_SQLTEMPLATE, "CHARINDEX(${column}, ${keystr}) = 0"); - } else if ("postgresql".equals(this.dbtype)) { - if (!props.containsKey(JDBC_TABLECOPY_SQLTEMPLATE)) { //娉ㄦ剰锛氭璇彞澶嶅埗琛ㄧ粨鏋勪細瀵艰嚧榛樿鍊煎拰涓婚敭淇℃伅鐨勪涪澶 - //娉ㄦ剰锛歱ostgresql涓嶆敮鎸佽法搴撳鍒惰〃缁撴瀯 - //props.setProperty(JDBC_TABLECOPY_SQLTEMPLATE, "CREATE TABLE ${newtable} AS (SELECT * FROM ${oldtable} LIMIT 0)"); - props.setProperty(JDBC_TABLECOPY_SQLTEMPLATE, "CREATE TABLE IF NOT EXISTS ${newtable} (LIKE ${oldtable} INCLUDING DEFAULTS INCLUDING CONSTRAINTS INCLUDING COMMENTS INCLUDING INDEXES)"); - } - if (!props.containsKey(JDBC_TABLENOTEXIST_SQLSTATES)) { - props.setProperty(JDBC_TABLENOTEXIST_SQLSTATES, "42P01;3F000"); - } - } - } - - //鐢熸垚鍒涘缓琛ㄧ殑SQL - protected String createTableSql(EntityInfo info) { - if (info == null || !autoddl) return null; - javax.persistence.Table table = info.getType().getAnnotation(javax.persistence.Table.class); - if ("mysql".equals(dbtype())) { //mysql - StringBuilder sb = new StringBuilder(); - sb.append("CREATE TABLE IF NOT EXISTS `").append(info.getOriginTable()).append("`(\n"); - EntityColumn primary = null; - T one = info.constructorAttributes == null ? info.getCreator().create() : null; - for (EntityColumn column : info.getDDLColumns()) { - if (column.primary) primary = column; - String sqltype = "VARCHAR(" + column.length + ")"; - String sqlnull = column.primary ? "NOT NULL" : "NULL"; - if (column.type == boolean.class || column.type == Boolean.class) { - sqltype = "TINYINT(1)"; - Boolean val = one == null ? null : (Boolean) info.getAttribute(column.field).get(one); - sqlnull = "NOT NULL DEFAULT " + (val != null && val ? 1 : 0); - } else if (column.type == byte.class || column.type == Byte.class) { - sqltype = "TINYINT"; - Number val = one == null ? null : (Number) info.getAttribute(column.field).get(one); - sqlnull = "NOT NULL DEFAULT " + (val == null ? 0 : val.byteValue()); - } else if (column.type == short.class || column.type == Short.class) { - sqltype = "SMALLINT"; - Number val = one == null ? null : (Number) info.getAttribute(column.field).get(one); - sqlnull = "NOT NULL DEFAULT " + (val == null ? 0 : val); - } else if (column.type == char.class || column.type == Character.class) { - sqltype = "SMALLINT UNSIGNED"; - Number val = one == null ? null : (Number) info.getAttribute(column.field).get(one); - sqlnull = "NOT NULL DEFAULT " + (val == null ? 0 : val.intValue()); - } else if (column.type == int.class || column.type == Integer.class || column.type == AtomicInteger.class) { - sqltype = "INT"; - Number val = one == null ? null : (Number) info.getAttribute(column.field).get(one); - sqlnull = "NOT NULL DEFAULT " + (val == null ? 0 : val); - } else if (column.type == long.class || column.type == Long.class || column.type == AtomicLong.class || column.type == LongAdder.class) { - sqltype = "BIGINT"; - Number val = one == null ? null : (Number) info.getAttribute(column.field).get(one); - sqlnull = "NOT NULL DEFAULT " + (val == null ? 0 : val); - } else if (column.type == float.class || column.type == Float.class) { - sqltype = "FLOAT"; - if (column.precision > 0) sqltype += "(" + column.precision + "," + column.scale + ")"; - Number val = one == null ? null : (Number) info.getAttribute(column.field).get(one); - sqlnull = "NOT NULL DEFAULT " + (val == null ? 0 : val); - } else if (column.type == double.class || column.type == Double.class) { - sqltype = "DOUBLE"; - if (column.precision > 0) sqltype += "(" + column.precision + "," + column.scale + ")"; - Number val = one == null ? null : (Number) info.getAttribute(column.field).get(one); - sqlnull = "NOT NULL DEFAULT " + (val == null ? 0 : val); - } else if (column.type == BigInteger.class) { - sqltype = "DECIMAL"; - if (column.precision > 0) { - sqltype += "(" + column.precision + "," + column.scale + ")"; - } else { - sqltype += "(19,2)"; - } - Number val = one == null ? null : (Number) info.getAttribute(column.field).get(one); - sqlnull = "NOT NULL DEFAULT " + (val == null ? 0 : val); - } else if (column.type == BigDecimal.class) { - sqltype = "DECIMAL"; - if (column.precision > 0) sqltype += "(" + column.precision + "," + column.scale + ")"; - Number val = one == null ? null : (Number) info.getAttribute(column.field).get(one); - sqlnull = "NOT NULL DEFAULT " + (val == null ? 0 : val); - } else if (column.type == String.class) { - if (column.length < 65535) { - String val = one == null ? null : (String) info.getAttribute(column.field).get(one); - if (val != null) { - sqlnull = "NOT NULL DEFAULT '" + val.replace('\'', '"') + "'"; - } else if (column.primary) { - sqlnull = "NOT NULL DEFAULT ''"; - } - } else if (column.length == 65535) { - sqltype = "TEXT"; - if (!column.nullable) sqlnull = "NOT NULL"; - } else if (column.length <= 16777215) { - sqltype = "MEDIUMTEXT"; - if (!column.nullable) sqlnull = "NOT NULL"; - } else { - sqltype = "LONGTEXT"; - if (!column.nullable) sqlnull = "NOT NULL"; - } - } else if (column.type == byte[].class) { - if (column.length <= 65535) { - sqltype = "BLOB"; - if (!column.nullable) sqlnull = "NOT NULL"; - } else if (column.length <= 16777215) { - sqltype = "MEDIUMBLOB"; - if (!column.nullable) sqlnull = "NOT NULL"; - } else { - sqltype = "LONGBLOB"; - if (!column.nullable) sqlnull = "NOT NULL"; - } - } else if (column.type == java.time.LocalDate.class || column.type == java.util.Date.class || "java.sql.Date".equals(column.type.getName())) { - sqltype = "DATE"; - } else if (column.type == java.time.LocalTime.class || "java.sql.Time".equals(column.type.getName())) { - sqltype = "TIME"; - } else if (column.type == java.time.LocalDateTime.class || "java.sql.Timestamp".equals(column.type.getName())) { - sqltype = "DATETIME"; - } else { //JavaBean - sqltype = column.length >= 65535 ? "TEXT" : ("VARCHAR(" + column.length + ")"); - sqlnull = !column.nullable ? "NOT NULL DEFAULT ''" : "NULL"; - } - sb.append(" `").append(column.column).append("` ").append(sqltype).append(" ").append(sqlnull); - if (column.comment != null && !column.comment.isEmpty()) { - sb.append(" COMMENT '").append(column.comment.replace('\'', '"')).append("'"); - } - sb.append(",\n"); - } - sb.append(" PRIMARY KEY (`").append(primary.column).append("`)\n"); - sb.append(")ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4"); - if (table != null && !table.comment().isEmpty()) { - sb.append(" COMMENT '").append(table.comment().replace('\'', '"')).append("'"); - } - return sb.toString(); - } else if ("postgresql".equals(dbtype())) { //postgresql - StringBuilder sb = new StringBuilder(); - sb.append("CREATE TABLE IF NOT EXISTS ").append(info.getOriginTable()).append("(\n"); - EntityColumn primary = null; - T one = info.constructorAttributes == null ? info.getCreator().create() : null; - for (EntityColumn column : info.getDDLColumns()) { - if (column.primary) primary = column; - String sqltype = "VARCHAR(" + column.length + ")"; - String sqlnull = column.primary ? "NOT NULL" : "NULL"; - if (column.type == boolean.class || column.type == Boolean.class) { - sqltype = "BOOL"; - Boolean val = one == null ? null : (Boolean) info.getAttribute(column.field).get(one); - sqlnull = "NOT NULL DEFAULT " + (val != null && val ? 1 : 0); - } else if (column.type == byte.class || column.type == Byte.class) { - sqltype = "INT2"; - Number val = one == null ? null : (Number) info.getAttribute(column.field).get(one); - sqlnull = "NOT NULL DEFAULT " + (val == null ? 0 : val.byteValue()); - } else if (column.type == short.class || column.type == Short.class) { - sqltype = "INT2"; - Number val = one == null ? null : (Number) info.getAttribute(column.field).get(one); - sqlnull = "NOT NULL DEFAULT " + (val == null ? 0 : val); - } else if (column.type == char.class || column.type == Character.class) { - sqltype = "INT2 UNSIGNED"; - Number val = one == null ? null : (Number) info.getAttribute(column.field).get(one); - sqlnull = "NOT NULL DEFAULT " + (val == null ? 0 : val.intValue()); - } else if (column.type == int.class || column.type == Integer.class || column.type == AtomicInteger.class) { - sqltype = "INT4"; - Number val = one == null ? null : (Number) info.getAttribute(column.field).get(one); - sqlnull = "NOT NULL DEFAULT " + (val == null ? 0 : val); - } else if (column.type == long.class || column.type == Long.class || column.type == AtomicLong.class || column.type == LongAdder.class) { - sqltype = "INT8"; - Number val = one == null ? null : (Number) info.getAttribute(column.field).get(one); - sqlnull = "NOT NULL DEFAULT " + (val == null ? 0 : val); - } else if (column.type == float.class || column.type == Float.class) { - sqltype = "FLOAT4"; - if (column.precision > 0) sqltype += "(" + column.precision + "," + column.scale + ")"; - Number val = one == null ? null : (Number) info.getAttribute(column.field).get(one); - sqlnull = "NOT NULL DEFAULT " + (val == null ? 0 : val); - } else if (column.type == double.class || column.type == Double.class) { - sqltype = "FLOAT8"; - if (column.precision > 0) sqltype += "(" + column.precision + "," + column.scale + ")"; - Number val = one == null ? null : (Number) info.getAttribute(column.field).get(one); - sqlnull = "NOT NULL DEFAULT " + (val == null ? 0 : val); - } else if (column.type == BigInteger.class) { - sqltype = "NUMERIC"; - if (column.precision > 0) { - sqltype += "(" + column.precision + "," + column.scale + ")"; - } else { - sqltype += "(19,2)"; - } - Number val = one == null ? null : (Number) info.getAttribute(column.field).get(one); - sqlnull = "NOT NULL DEFAULT " + (val == null ? 0 : val); - } else if (column.type == BigDecimal.class) { - sqltype = "NUMERIC"; - if (column.precision > 0) sqltype += "(" + column.precision + "," + column.scale + ")"; - Number val = one == null ? null : (Number) info.getAttribute(column.field).get(one); - sqlnull = "NOT NULL DEFAULT " + (val == null ? 0 : val); - } else if (column.type == String.class) { - if (column.length < 65535) { - String val = one == null ? null : (String) info.getAttribute(column.field).get(one); - if (val != null) { - sqlnull = "NOT NULL DEFAULT '" + val.replace('\'', '"') + "'"; - } else if (column.primary) { - sqlnull = "NOT NULL DEFAULT ''"; - } - } else { - sqltype = "TEXT"; - if (!column.nullable) sqlnull = "NOT NULL"; - } - } else if (column.type == byte[].class) { - sqltype = "OID"; - if (!column.nullable) sqlnull = "NOT NULL"; - } else if (column.type == java.time.LocalDate.class || column.type == java.util.Date.class || "java.sql.Date".equals(column.type.getName())) { - sqltype = "DATE"; - } else if (column.type == java.time.LocalTime.class || "java.sql.Time".equals(column.type.getName())) { - sqltype = "TIME"; - } else if (column.type == java.time.LocalDateTime.class || "java.sql.Timestamp".equals(column.type.getName())) { - sqltype = "TIMESTAMP"; - } else { //JavaBean - sqltype = column.length >= 65535 ? "TEXT" : ("VARCHAR(" + column.length + ")"); - sqlnull = !column.nullable ? "NOT NULL DEFAULT ''" : "NULL"; - } - sb.append(" ").append(column.column).append(" ").append(sqltype).append(" ").append(sqlnull); - if (column.comment != null && !column.comment.isEmpty()) { - //postgresql涓嶆敮鎸丏DL涓甫comment - } - sb.append(",\n"); - } - sb.append(" PRIMARY KEY (").append(primary.column).append(")\n"); - sb.append(")"); - return sb.toString(); - } - return null; - } - - @Local - protected boolean isTableNotExist(EntityInfo info, String code) { - if (code == null || code.isEmpty()) return false; - return tablenotexistSqlstates.contains(';' + code + ';'); - } - - @Local - protected String getTableCopySQL(EntityInfo info, String newTable) { - return tablecopySQL.replace("${newtable}", newTable).replace("${oldtable}", info.table); - } - - @Override - public void init(AnyValue conf) { - this.cacheForbidden = "NONE".equalsIgnoreCase(readConfProps.getProperty(JDBC_CACHE_MODE)); - } - - @Override - public void destroy(AnyValue config) { - super.destroy(config); - } - - @Override - @Local - public void compile(Class clazz) { - EntityInfo.compile(clazz, this); - } - - @Local - public final String dbtype() { - if (dbtype == null) throw new NullPointerException("dbtype is null"); - return dbtype; - } - - @Local - public final boolean autoddl() { - return autoddl; - } - - @Local - public abstract int directExecute(String sql); - - @Local - public abstract int[] directExecute(String... sqls); - - @Local - public abstract V directQuery(String sql, Function handler); - - //鏄惁寮傛 - protected abstract boolean isAsync(); - - //index浠1寮濮 - protected abstract String prepareParamSign(int index); - - //鎻掑叆绾綍 - protected abstract CompletableFuture insertDB(final EntityInfo info, T... entitys); - - //鍒犻櫎璁板綍 - protected abstract CompletableFuture deleteDB(final EntityInfo info, Flipper flipper, final String sql); - - //娓呯┖琛 - protected abstract CompletableFuture clearTableDB(final EntityInfo info, final String table, final String sql); - - //鍒犻櫎琛 - protected abstract CompletableFuture dropTableDB(final EntityInfo info, final String table, final String sql); - - //鏇存柊绾綍 - protected abstract CompletableFuture updateEntityDB(final EntityInfo info, T... entitys); - - //鏇存柊绾綍 - protected abstract CompletableFuture updateColumnDB(final EntityInfo info, Flipper flipper, final String sql, final boolean prepared, Object... params); - - //鏌ヨNumber Map鏁版嵁 - protected abstract CompletableFuture> getNumberMapDB(final EntityInfo info, final String sql, final FilterFuncColumn... columns); - - //鏌ヨNumber鏁版嵁 - protected abstract CompletableFuture getNumberResultDB(final EntityInfo info, final String sql, final Number defVal, final String column); - - //鏌ヨMap鏁版嵁 - protected abstract CompletableFuture> queryColumnMapDB(final EntityInfo info, final String sql, final String keyColumn); - - //鏌ヨMap鏁版嵁 - protected abstract CompletableFuture> queryColumnMapDB(final EntityInfo info, final String sql, final ColumnNode[] funcNodes, final String[] groupByColumns); - - //鏌ヨ鍗曟潯璁板綍 - protected abstract CompletableFuture findDB(final EntityInfo info, final String sql, final boolean onlypk, final SelectColumn selects); - - //鏌ヨ鍗曟潯璁板綍鐨勫崟涓瓧娈 - protected abstract CompletableFuture findColumnDB(final EntityInfo info, final String sql, final boolean onlypk, final String column, final Serializable defValue); - - //鍒ゆ柇璁板綍鏄惁瀛樺湪 - protected abstract CompletableFuture existsDB(final EntityInfo info, final String sql, final boolean onlypk); - - //鏌ヨ涓椤垫暟鎹 - protected abstract CompletableFuture> querySheetDB(final EntityInfo info, final boolean readcache, final boolean needtotal, final boolean distinct, final SelectColumn selects, final Flipper flipper, final FilterNode node); - - protected CharSequence createSQLJoin(FilterNode node, final Function func, final boolean update, final Map joinTabalis, final Set haset, final EntityInfo info) { - return node == null ? null : node.createSQLJoin(func, update, joinTabalis, haset, info); - } - - protected CharSequence createSQLExpress(FilterNode node, final EntityInfo info, final Map joinTabalis) { - return node == null ? null : node.createSQLExpress(this, info, joinTabalis); - } - - @Local - @Override - public String getType() { - return "sql"; - } - - @Override - public final String resourceName() { - return name; - } - - @Local - @Override - public EntityInfo apply(Class t) { - return loadEntityInfo(t); - } - - @Local - @Override - public void close() throws Exception { - } - - protected EntityInfo loadEntityInfo(Class clazz) { - return loadEntityInfo(clazz, this.cacheForbidden, readConfProps, fullloader); - } - - public EntityCache loadCache(Class clazz) { - EntityInfo info = loadEntityInfo(clazz); - return info.getCache(); - } - - /** - * 灏唀ntity鐨勫璞″叏閮ㄥ姞杞藉埌Cache涓幓锛屽鏋渃lazz娌℃湁琚獲javax.persistence.Cacheable娉ㄨВ鍒欎笉鍋氫换浣曚簨 - * - * @param Entity绫绘硾鍨 - * @param clazz Entity绫 - */ - public void refreshCache(Class clazz) { - EntityInfo info = loadEntityInfo(clazz); - EntityCache cache = info.getCache(); - if (cache == null) return; - cache.fullLoadAsync(); - } - - protected CharSequence formatValueToString(final EntityInfo info, Object value) { - final String dbtype = dbtype(); - if ("mysql".equals(dbtype)) { - if (value == null) return null; - if (value instanceof CharSequence) { - return new StringBuilder().append('\'').append(value.toString().replace("\\", "\\\\").replace("'", "\\'")).append('\'').toString(); - } else if (!(value instanceof Number) && !(value instanceof java.util.Date) - && !value.getClass().getName().startsWith("java.sql.") && !value.getClass().getName().startsWith("java.time.")) { - return new StringBuilder().append('\'').append(info.getJsonConvert().convertTo(value).replace("\\", "\\\\").replace("'", "\\'")).append('\'').toString(); - } - return String.valueOf(value); - } else if (value != null && value instanceof CharSequence && "postgresql".equals(dbtype)) { - String s = String.valueOf(value); - int pos = s.indexOf('\''); - if (pos >= 0) return new StringBuilder().append("E'").append(value.toString().replace("\\", "\\\\").replace("'", "\\'")).append('\'').toString(); - } - return info.formatSQLValue(value, null); - } - - //----------------------------- insert ----------------------------- - /** - * 鏂板瀵硅薄锛 蹇呴』鏄疎ntity瀵硅薄 - * - * @param Entity绫绘硾鍨 - * @param entitys Entity瀵硅薄 - * - * @return 褰卞搷鐨勮褰曟潯鏁 - */ - @Override - public int insert(T... entitys) { - if (entitys.length == 0) return 0; - checkEntity("insert", false, entitys); - final EntityInfo info = loadEntityInfo((Class) entitys[0].getClass()); - if (isOnlyCache(info)) return insertCache(info, entitys); - return insertDB(info, entitys).whenComplete((rs, t) -> { - if (t != null) { - futureCompleteConsumer.accept(rs, t); - } else { - insertCache(info, entitys); - } - }).join(); - } - - @Override - public CompletableFuture insertAsync(T... entitys) { - if (entitys.length == 0) return CompletableFuture.completedFuture(0); - CompletableFuture future = checkEntity("insert", true, entitys); - if (future != null) return future; - final EntityInfo info = loadEntityInfo((Class) entitys[0].getClass()); - if (isOnlyCache(info)) { - return CompletableFuture.completedFuture(insertCache(info, entitys)); - } - if (isAsync()) return insertDB(info, entitys).whenComplete((rs, t) -> { - if (t != null) { - futureCompleteConsumer.accept(rs, t); - } else { - insertCache(info, entitys); - } - }); - return CompletableFuture.supplyAsync(() -> insertDB(info, entitys).join(), getExecutor()).whenComplete((rs, t) -> { - if (t != null) { - futureCompleteConsumer.accept(rs, t); - } else { - insertCache(info, entitys); - } - }); - } - - protected int insertCache(final EntityInfo info, T... entitys) { - final EntityCache cache = info.getCache(); - if (cache == null) return 0; - int c = 0; - for (final T value : entitys) { - c += cache.insert(value); - } - return c; - } - - //----------------------------- deleteCompose ----------------------------- - /** - * 鍒犻櫎瀵硅薄锛 蹇呴』鏄疎ntity瀵硅薄 - * - * @param Entity绫绘硾鍨 - * @param entitys Entity瀵硅薄 - * - * @return 鍒犻櫎鐨勬暟鎹潯鏁 - */ - @Override - public int delete(T... entitys) { - if (entitys.length == 0) return -1; - checkEntity("delete", false, entitys); - final Class clazz = (Class) entitys[0].getClass(); - final EntityInfo info = loadEntityInfo(clazz); - final Attribute primary = info.getPrimary(); - Serializable[] ids = new Serializable[entitys.length]; - int i = 0; - for (final T value : entitys) { - ids[i++] = (Serializable) primary.get(value); - } - return delete(clazz, ids); - } - - @Override - public CompletableFuture deleteAsync(final T... entitys) { - if (entitys.length == 0) return CompletableFuture.completedFuture(-1); - CompletableFuture future = checkEntity("delete", true, entitys); - if (future != null) return future; - final Class clazz = (Class) entitys[0].getClass(); - final EntityInfo info = loadEntityInfo(clazz); - final Attribute primary = info.getPrimary(); - Serializable[] ids = new Serializable[entitys.length]; - int i = 0; - for (final T value : entitys) { - ids[i++] = (Serializable) primary.get(value); - } - return deleteAsync(clazz, ids); - } - - @Override - public int delete(Class clazz, Serializable... pks) { - if (pks.length == 0) return -1; - final EntityInfo info = loadEntityInfo(clazz); - if (isOnlyCache(info)) return deleteCache(info, -1, pks); - return deleteCompose(info, pks).whenComplete((rs, t) -> { - if (t != null) { - futureCompleteConsumer.accept(rs, t); - } else { - deleteCache(info, rs, pks); - } - }).join(); - } - - @Override - public CompletableFuture deleteAsync(final Class clazz, final Serializable... pks) { - if (pks.length == 0) return CompletableFuture.completedFuture(-1); - final EntityInfo info = loadEntityInfo(clazz); - if (isOnlyCache(info)) { - return CompletableFuture.completedFuture(deleteCache(info, -1, pks)); - } - if (isAsync()) return deleteCompose(info, pks).whenComplete((rs, t) -> { - if (t != null) { - futureCompleteConsumer.accept(rs, t); - } else { - deleteCache(info, rs, pks); - } - }); - return CompletableFuture.supplyAsync(() -> deleteCompose(info, pks).join(), getExecutor()).whenComplete((rs, t) -> { - if (t != null) { - futureCompleteConsumer.accept(rs, t); - } else { - deleteCache(info, rs, pks); - } - }); - } - - @Override - public int delete(Class clazz, FilterNode node) { - return delete(clazz, (Flipper) null, node); - } - - @Override - public CompletableFuture deleteAsync(final Class clazz, final FilterNode node) { - return deleteAsync(clazz, (Flipper) null, node); - } - - @Override - public int delete(Class clazz, final Flipper flipper, FilterNode node) { - final EntityInfo info = loadEntityInfo(clazz); - if (isOnlyCache(info)) return deleteCache(info, -1, flipper, node); - return this.deleteCompose(info, flipper, node).whenComplete((rs, t) -> { - if (t != null) { - futureCompleteConsumer.accept(rs, t); - } else { - deleteCache(info, rs, flipper, node); - } - }).join(); - } - - @Override - public CompletableFuture deleteAsync(final Class clazz, final Flipper flipper, FilterNode node) { - final EntityInfo info = loadEntityInfo(clazz); - if (isOnlyCache(info)) { - return CompletableFuture.completedFuture(deleteCache(info, -1, flipper, node)); - } - if (isAsync()) return this.deleteCompose(info, flipper, node).whenComplete((rs, t) -> { - if (t != null) { - futureCompleteConsumer.accept(rs, t); - } else { - deleteCache(info, rs, flipper, node); - } - }); - return CompletableFuture.supplyAsync(() -> this.deleteCompose(info, flipper, node).join(), getExecutor()).whenComplete((rs, t) -> { - if (t != null) { - futureCompleteConsumer.accept(rs, t); - } else { - deleteCache(info, rs, flipper, node); - } - }); - } - - protected CompletableFuture deleteCompose(final EntityInfo info, final Serializable... pks) { - if (pks.length == 1) { - String sql = "DELETE FROM " + info.getTable(pks[0]) + " WHERE " + info.getPrimarySQLColumn() + "=" + info.formatSQLValue(info.getPrimarySQLColumn(), pks[0], sqlFormatter); - return deleteDB(info, null, sql); - } - String sql = "DELETE FROM " + info.getTable(pks[0]) + " WHERE " + info.getPrimarySQLColumn() + " IN ("; - for (int i = 0; i < pks.length; i++) { - if (i > 0) sql += ','; - sql += info.formatSQLValue(info.getPrimarySQLColumn(), pks[i], sqlFormatter); - } - sql += ")"; - if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " delete sql=" + sql); - return deleteDB(info, null, sql); - } - - protected CompletableFuture deleteCompose(final EntityInfo info, final Flipper flipper, final FilterNode node) { - Map joinTabalis = null; - CharSequence join = null; - CharSequence where = null; - if (node != null) { - joinTabalis = node.getJoinTabalis(); - join = node.createSQLJoin(this, true, joinTabalis, new HashSet<>(), info); - where = node.createSQLExpress(this, info, joinTabalis); - } - StringBuilder join1 = null; - StringBuilder join2 = null; - if (join != null) { - String joinstr = join.toString(); - join1 = multisplit('[', ']', ",", new StringBuilder(), joinstr, 0); - join2 = multisplit('{', '}', " AND ", new StringBuilder(), joinstr, 0); - } - String sql = "DELETE " + ("mysql".equals(dbtype()) ? "a" : "") + " FROM " + info.getTable(node) + " a" + (join1 == null ? "" : (", " + join1)) - + ((where == null || where.length() == 0) ? (join2 == null ? "" : (" WHERE " + join2)) - : (" WHERE " + where + (join2 == null ? "" : (" AND " + join2)))) + info.createSQLOrderby(flipper); - if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " delete sql=" - + (sql + ((flipper == null || flipper.getLimit() < 1) ? "" : (" LIMIT " + flipper.getLimit())))); - return deleteDB(info, flipper, sql); - } - - //----------------------------- clearTableCompose ----------------------------- - @Override - public int clearTable(Class clazz) { - return clearTable(clazz, (FilterNode) null); - } - - @Override - public int clearTable(Class clazz, FilterNode node) { - final EntityInfo info = loadEntityInfo(clazz); - if (isOnlyCache(info)) return clearTableCache(info, node); - return this.clearTableCompose(info, node).whenComplete((rs, t) -> { - if (t != null) { - futureCompleteConsumer.accept(rs, t); - } else { - clearTableCache(info, node); - } - }).join(); - } - - @Override - public CompletableFuture clearTableAsync(final Class clazz, FilterNode node) { - final EntityInfo info = loadEntityInfo(clazz); - if (isOnlyCache(info)) { - return CompletableFuture.completedFuture(clearTableCache(info, node)); - } - if (isAsync()) return this.clearTableCompose(info, node).whenComplete((rs, t) -> { - if (t != null) { - futureCompleteConsumer.accept(rs, t); - } else { - clearTableCache(info, node); - } - }); - return CompletableFuture.supplyAsync(() -> this.clearTableCompose(info, node).join(), getExecutor()).whenComplete((rs, t) -> { - if (t != null) { - futureCompleteConsumer.accept(rs, t); - } else { - clearTableCache(info, node); - } - }); - } - - protected CompletableFuture clearTableCompose(final EntityInfo info, final FilterNode node) { - final String table = info.getTable(node); - String sql = "TRUNCATE TABLE " + table; - if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " clearTable sql=" + sql); - return clearTableDB(info, table, sql); - } - - //----------------------------- dropTableCompose ----------------------------- - @Override - public int dropTable(Class clazz, FilterNode node) { - final EntityInfo info = loadEntityInfo(clazz); - if (isOnlyCache(info)) return dropTableCache(info, node); - return this.dropTableCompose(info, node).whenComplete((rs, t) -> { - if (t != null) { - futureCompleteConsumer.accept(rs, t); - } else { - dropTableCache(info, node); - } - }).join(); - } - - @Override - public CompletableFuture dropTableAsync(final Class clazz, FilterNode node) { - final EntityInfo info = loadEntityInfo(clazz); - if (isOnlyCache(info)) { - return CompletableFuture.completedFuture(dropTableCache(info, node)); - } - if (isAsync()) return this.dropTableCompose(info, node).whenComplete((rs, t) -> { - if (t != null) { - futureCompleteConsumer.accept(rs, t); - } else { - dropTableCache(info, node); - } - }); - return CompletableFuture.supplyAsync(() -> this.dropTableCompose(info, node).join(), getExecutor()).whenComplete((rs, t) -> { - if (t != null) { - futureCompleteConsumer.accept(rs, t); - } else { - dropTableCache(info, node); - } - }); - } - - protected CompletableFuture dropTableCompose(final EntityInfo info, final FilterNode node) { - final String table = info.getTable(node); - String sql = "DROP TABLE " + table; - if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " dropTable sql=" + sql); - return dropTableDB(info, table, sql); - } - - protected int clearTableCache(final EntityInfo info, FilterNode node) { - final EntityCache cache = info.getCache(); - if (cache == null) return -1; - return cache.clear(); - } - - protected int dropTableCache(final EntityInfo info, FilterNode node) { - final EntityCache cache = info.getCache(); - if (cache == null) return -1; - return cache.drop(); - } - - protected int deleteCache(final EntityInfo info, int count, Flipper flipper, FilterNode node) { - final EntityCache cache = info.getCache(); - if (cache == null) return -1; - Serializable[] ids = cache.delete(flipper, node); - return count >= 0 ? count : (ids == null ? 0 : ids.length); - } - - protected int deleteCache(final EntityInfo info, int count, Serializable... pks) { - final EntityCache cache = info.getCache(); - if (cache == null) return -1; - int c = 0; - for (Serializable key : pks) { - c += cache.delete(key); - } - return count >= 0 ? count : c; - } - - protected static StringBuilder multisplit(char ch1, char ch2, String split, StringBuilder sb, String str, int from) { - if (str == null) return sb; - int pos1 = str.indexOf(ch1, from); - if (pos1 < 0) return sb; - int pos2 = str.indexOf(ch2, from); - if (pos2 < 0) return sb; - if (sb.length() > 0) sb.append(split); - sb.append(str.substring(pos1 + 1, pos2)); - return multisplit(ch1, ch2, split, sb, str, pos2 + 1); - } - - //---------------------------- update ---------------------------- - /** - * 鏇存柊瀵硅薄锛 蹇呴』鏄疎ntity瀵硅薄 - * - * @param Entity绫绘硾鍨 - * @param entitys Entity瀵硅薄 - * - * @return 鏇存柊鐨勬暟鎹潯鏁 - */ - @Override - public int update(T... entitys) { - if (entitys.length == 0) return -1; - checkEntity("update", false, entitys); - final Class clazz = (Class) entitys[0].getClass(); - final EntityInfo info = loadEntityInfo(clazz); - if (isOnlyCache(info)) return updateCache(info, -1, entitys); - return updateEntityDB(info, entitys).whenComplete((rs, t) -> { - if (t != null) { - futureCompleteConsumer.accept(rs, t); - } else { - updateCache(info, rs, entitys); - } - }).join(); - } - - @Override - public CompletableFuture updateAsync(final T... entitys) { - if (entitys.length == 0) return CompletableFuture.completedFuture(-1); - CompletableFuture future = checkEntity("update", true, entitys); - if (future != null) return future; - final Class clazz = (Class) entitys[0].getClass(); - final EntityInfo info = loadEntityInfo(clazz); - if (isOnlyCache(info)) { - return CompletableFuture.completedFuture(updateCache(info, -1, entitys)); - } - if (isAsync()) return updateEntityDB(info, entitys).whenComplete((rs, t) -> { - if (t != null) { - futureCompleteConsumer.accept(rs, t); - } else { - updateCache(info, rs, entitys); - } - }); - return CompletableFuture.supplyAsync(() -> updateEntityDB(info, entitys).join(), getExecutor()).whenComplete((rs, t) -> { - if (t != null) { - futureCompleteConsumer.accept(rs, t); - } else { - updateCache(info, rs, entitys); - } - }); - } - - /** - * 鏍规嵁涓婚敭鍊兼洿鏂板璞$殑column瀵瑰簲鐨勫硷紝 蹇呴』鏄疎ntity Class - * - * @param Entity绫荤殑娉涘瀷 - * @param clazz Entity绫 - * @param pk 涓婚敭鍊 - * @param column 杩囨护瀛楁鍚 - * @param colval 杩囨护瀛楁鍊 - * - * @return 鏇存柊鐨勬暟鎹潯鏁 - */ - @Override - public int updateColumn(Class clazz, Serializable pk, String column, Serializable colval) { - final EntityInfo info = loadEntityInfo(clazz); - if (isOnlyCache(info)) return updateCache(info, -1, pk, column, colval); - return updateColumnCompose(info, pk, column, colval).whenComplete((rs, t) -> { - if (t != null) { - futureCompleteConsumer.accept(rs, t); - } else { - updateCache(info, rs, pk, column, colval); - } - }).join(); - } - - @Override - public CompletableFuture updateColumnAsync(final Class clazz, final Serializable pk, final String column, final Serializable colval) { - final EntityInfo info = loadEntityInfo(clazz); - if (isOnlyCache(info)) { - return CompletableFuture.completedFuture(updateCache(info, -1, pk, column, colval)); - } - if (isAsync()) return updateColumnCompose(info, pk, column, colval).whenComplete((rs, t) -> { - if (t != null) { - futureCompleteConsumer.accept(rs, t); - } else { - updateCache(info, rs, pk, column, colval); - } - }); - return CompletableFuture.supplyAsync(() -> updateColumnCompose(info, pk, column, colval).join(), getExecutor()).whenComplete((rs, t) -> { - if (t != null) { - futureCompleteConsumer.accept(rs, t); - } else { - updateCache(info, rs, pk, column, colval); - } - }); - } - - protected CompletableFuture updateColumnCompose(final EntityInfo info, Serializable pk, String column, final Serializable colval) { - if (colval instanceof byte[]) { - String sql = "UPDATE " + info.getTable(pk) + " SET " + info.getSQLColumn(null, column) + "=" + prepareParamSign(1) + " WHERE " + info.getPrimarySQLColumn() + "=" + info.formatSQLValue(info.getPrimarySQLColumn(), pk, sqlFormatter); - return updateColumnDB(info, null, sql, true, colval); - } else { - String sql = "UPDATE " + info.getTable(pk) + " SET " + info.getSQLColumn(null, column) + "=" - + info.formatSQLValue(column, colval, sqlFormatter) + " WHERE " + info.getPrimarySQLColumn() + "=" + info.formatSQLValue(info.getPrimarySQLColumn(), pk, sqlFormatter); - return updateColumnDB(info, null, sql, false); - } - } - - /** - * 鏍规嵁涓婚敭鍊兼洿鏂板璞$殑column瀵瑰簲鐨勫硷紝 蹇呴』鏄疎ntity Class - * - * @param Entity绫荤殑娉涘瀷 - * @param clazz Entity绫 - * @param column 杩囨护瀛楁鍚 - * @param colval 杩囨护瀛楁鍊 - * @param node 杩囨护node 涓嶈兘涓簄ull - * - * @return 鏇存柊鐨勬暟鎹潯鏁 - */ - @Override - public int updateColumn(Class clazz, String column, Serializable colval, FilterNode node) { - final EntityInfo info = loadEntityInfo(clazz); - if (isOnlyCache(info)) return updateCache(info, -1, column, colval, node); - return this.updateColumnCompose(info, column, colval, node).whenComplete((rs, t) -> { - if (t != null) { - futureCompleteConsumer.accept(rs, t); - } else { - updateCache(info, rs, column, colval, node); - } - }).join(); - } - - @Override - public CompletableFuture updateColumnAsync(final Class clazz, final String column, final Serializable colval, final FilterNode node) { - final EntityInfo info = loadEntityInfo(clazz); - if (isOnlyCache(info)) { - return CompletableFuture.completedFuture(updateCache(info, -1, column, colval, node)); - } - if (isAsync()) return this.updateColumnCompose(info, column, colval, node).whenComplete((rs, t) -> { - if (t != null) { - futureCompleteConsumer.accept(rs, t); - } else { - updateCache(info, rs, column, colval, node); - } - }); - return CompletableFuture.supplyAsync(() -> this.updateColumnCompose(info, column, colval, node).join(), getExecutor()).whenComplete((rs, t) -> { - if (t != null) { - futureCompleteConsumer.accept(rs, t); - } else { - updateCache(info, rs, column, colval, node); - } - }); - } - - protected CompletableFuture updateColumnCompose(final EntityInfo info, final String column, final Serializable colval, final FilterNode node) { - Map joinTabalis = node.getJoinTabalis(); - CharSequence join = node.createSQLJoin(this, true, joinTabalis, new HashSet<>(), info); - CharSequence where = node.createSQLExpress(this, info, joinTabalis); - - StringBuilder join1 = null; - StringBuilder join2 = null; - if (join != null) { - String joinstr = join.toString(); - join1 = multisplit('[', ']', ",", new StringBuilder(), joinstr, 0); - join2 = multisplit('{', '}', " AND ", new StringBuilder(), joinstr, 0); - } - String alias = "postgresql".equals(dbtype()) ? null : "a"; //postgresql鐨凚UG锛 UPDATE鐨凷ET涓笉鑳藉惈鍒悕 - if (colval instanceof byte[]) { - String sql = "UPDATE " + info.getTable(node) + " a " + (join1 == null ? "" : (", " + join1)) - + " SET " + info.getSQLColumn(alias, column) + "=" + prepareParamSign(1) - + ((where == null || where.length() == 0) ? (join2 == null ? "" : (" WHERE " + join2)) - : (" WHERE " + where + (join2 == null ? "" : (" AND " + join2)))); - return updateColumnDB(info, null, sql, true, colval); - } else { - String sql = "UPDATE " + info.getTable(node) + " a " + (join1 == null ? "" : (", " + join1)) - + " SET " + info.getSQLColumn(alias, column) + "=" + info.formatSQLValue(colval, sqlFormatter) - + ((where == null || where.length() == 0) ? (join2 == null ? "" : (" WHERE " + join2)) - : (" WHERE " + where + (join2 == null ? "" : (" AND " + join2)))); - return updateColumnDB(info, null, sql, false); - } - } - - /** - * 鏍规嵁涓婚敭鍊兼洿鏂板璞$殑澶氫釜column瀵瑰簲鐨勫硷紝 蹇呴』鏄疎ntity Class - * - * @param Entity绫荤殑娉涘瀷 - * @param clazz Entity绫 - * @param pk 涓婚敭鍊 - * @param values 瀛楁鍊 - * - * @return 鏇存柊鐨勬暟鎹潯鏁 - */ - @Override - public int updateColumn(final Class clazz, final Serializable pk, final ColumnValue... values) { - if (values == null || values.length < 1) return -1; - final EntityInfo info = loadEntityInfo(clazz); - if (isOnlyCache(info)) return updateCache(info, -1, pk, values); - return this.updateColumnCompose(info, pk, values).whenComplete((rs, t) -> { - if (t != null) { - futureCompleteConsumer.accept(rs, t); - } else { - updateCache(info, rs, pk, values); - } - }).join(); - } - - @Override - public CompletableFuture updateColumnAsync(final Class clazz, final Serializable pk, final ColumnValue... values) { - if (values == null || values.length < 1) return CompletableFuture.completedFuture(-1); - final EntityInfo info = loadEntityInfo(clazz); - if (isOnlyCache(info)) { - return CompletableFuture.completedFuture(updateCache(info, -1, pk, values)); - } - if (isAsync()) return this.updateColumnCompose(info, pk, values).whenComplete((rs, t) -> { - if (t != null) { - futureCompleteConsumer.accept(rs, t); - } else { - updateCache(info, rs, pk, values); - } - }); - return CompletableFuture.supplyAsync(() -> this.updateColumnCompose(info, pk, values).join(), getExecutor()).whenComplete((rs, t) -> { - if (t != null) { - futureCompleteConsumer.accept(rs, t); - } else { - updateCache(info, rs, pk, values); - } - }); - } - - protected CompletableFuture updateColumnCompose(final EntityInfo info, final Serializable pk, final ColumnValue... values) { - StringBuilder setsql = new StringBuilder(); - List blobs = null; - int index = 0; - for (ColumnValue col : values) { - if (col == null) continue; - Attribute attr = info.getUpdateAttribute(col.getColumn()); - if (attr == null) throw new RuntimeException(info.getType() + " cannot found column " + col.getColumn()); - if (setsql.length() > 0) setsql.append(", "); - String sqlColumn = info.getSQLColumn(null, col.getColumn()); - if (col.getValue() instanceof byte[]) { - if (blobs == null) blobs = new ArrayList<>(); - blobs.add((byte[]) col.getValue()); - setsql.append(sqlColumn).append("=").append(prepareParamSign(++index)); - } else { - setsql.append(sqlColumn).append("=").append(info.formatSQLValue(sqlColumn, attr, col, sqlFormatter)); - } - } - if (setsql.length() < 1) return CompletableFuture.completedFuture(0); - String sql = "UPDATE " + info.getTable(pk) + " SET " + setsql + " WHERE " + info.getPrimarySQLColumn() + "=" + info.formatSQLValue(info.getPrimarySQLColumn(), pk, sqlFormatter); - if (blobs == null) return updateColumnDB(info, null, sql, false); - return updateColumnDB(info, null, sql, true, blobs.toArray()); - } - - @Override - public int updateColumn(final Class clazz, final FilterNode node, final Flipper flipper, final ColumnValue... values) { - if (values == null || values.length < 1) return -1; - final EntityInfo info = loadEntityInfo(clazz); - if (isOnlyCache(info)) return updateCache(info, -1, node, flipper, values); - return this.updateColumnCompose(info, node, flipper, values).whenComplete((rs, t) -> { - if (t != null) { - futureCompleteConsumer.accept(rs, t); - } else { - updateCache(info, rs, node, flipper, values); - } - }).join(); - } - - @Override - public CompletableFuture updateColumnAsync(final Class clazz, final FilterNode node, final Flipper flipper, final ColumnValue... values) { - if (values == null || values.length < 1) return CompletableFuture.completedFuture(-1); - final EntityInfo info = loadEntityInfo(clazz); - if (isOnlyCache(info)) { - return CompletableFuture.completedFuture(updateCache(info, -1, node, flipper, values)); - } - if (isAsync()) return this.updateColumnCompose(info, node, flipper, values).whenComplete((rs, t) -> { - if (t != null) { - futureCompleteConsumer.accept(rs, t); - } else { - updateCache(info, rs, node, flipper, values); - } - }); - return CompletableFuture.supplyAsync(() -> this.updateColumnCompose(info, node, flipper, values).join(), getExecutor()).whenComplete((rs, t) -> { - if (t != null) { - futureCompleteConsumer.accept(rs, t); - } else { - updateCache(info, rs, node, flipper, values); - } - }); - } - - protected CompletableFuture updateColumnCompose(final EntityInfo info, final FilterNode node, final Flipper flipper, final ColumnValue... values) { - StringBuilder setsql = new StringBuilder(); - List blobs = null; - int index = 0; - String alias = "postgresql".equals(dbtype()) ? null : "a"; //postgresql鐨凚UG锛 UPDATE鐨凷ET涓笉鑳藉惈鍒悕 - for (ColumnValue col : values) { - if (col == null) continue; - Attribute attr = info.getUpdateAttribute(col.getColumn()); - if (attr == null) continue; - if (setsql.length() > 0) setsql.append(", "); - String sqlColumn = info.getSQLColumn(alias, col.getColumn()); - if (col.getValue() instanceof byte[]) { - if (blobs == null) blobs = new ArrayList<>(); - blobs.add((byte[]) col.getValue()); - setsql.append(sqlColumn).append("=").append(prepareParamSign(++index)); - } else { - setsql.append(sqlColumn).append("=").append(info.formatSQLValue(sqlColumn, attr, col, sqlFormatter)); - } - } - if (setsql.length() < 1) return CompletableFuture.completedFuture(0); - Map joinTabalis = node == null ? null : node.getJoinTabalis(); - CharSequence join = node == null ? null : node.createSQLJoin(this, true, joinTabalis, new HashSet<>(), info); - CharSequence where = node == null ? null : node.createSQLExpress(this, info, joinTabalis); - StringBuilder join1 = null; - StringBuilder join2 = null; - if (join != null) { - String joinstr = join.toString(); - join1 = multisplit('[', ']', ",", new StringBuilder(), joinstr, 0); - join2 = multisplit('{', '}', " AND ", new StringBuilder(), joinstr, 0); - } - String sql = "UPDATE " + info.getTable(node) + " a " + (join1 == null ? "" : (", " + join1)) + " SET " + setsql - + ((where == null || where.length() == 0) ? (join2 == null ? "" : (" WHERE " + join2)) - : (" WHERE " + where + (join2 == null ? "" : (" AND " + join2)))) - + info.createSQLOrderby(flipper); - if (blobs == null) return updateColumnDB(info, null, sql, false); - return updateColumnDB(info, flipper, sql, true, blobs.toArray()); - } - - @Override - public int updateColumn(final T entity, final SelectColumn selects) { - if (entity == null || selects == null) return -1; - Class clazz = (Class) entity.getClass(); - final EntityInfo info = loadEntityInfo(clazz); - if (isOnlyCache(info)) return updateCache(info, -1, false, entity, null, selects); - return this.updateColumnCompose(info, false, entity, null, selects).whenComplete((rs, t) -> { - if (t != null) { - futureCompleteConsumer.accept(rs, t); - } else { - updateCache(info, rs, false, entity, null, selects); - } - }).join(); - } - - @Override - public CompletableFuture updateColumnAsync(final T entity, final SelectColumn selects) { - if (entity == null || selects == null) return CompletableFuture.completedFuture(-1); - Class clazz = (Class) entity.getClass(); - final EntityInfo info = loadEntityInfo(clazz); - if (isOnlyCache(info)) { - return CompletableFuture.completedFuture(updateCache(info, -1, false, entity, null, selects)); - } - if (isAsync()) return this.updateColumnCompose(info, false, entity, null, selects).whenComplete((rs, t) -> { - if (t != null) { - futureCompleteConsumer.accept(rs, t); - } else { - updateCache(info, rs, false, entity, null, selects); - } - }); - return CompletableFuture.supplyAsync(() -> this.updateColumnCompose(info, false, entity, null, selects).join(), getExecutor()).whenComplete((rs, t) -> { - if (t != null) { - futureCompleteConsumer.accept(rs, t); - } else { - updateCache(info, rs, false, entity, null, selects); - } - }); - } - - @Override - public int updateColumn(final T entity, final FilterNode node, final SelectColumn selects) { - if (entity == null || node == null || selects == null) return -1; - Class clazz = (Class) entity.getClass(); - final EntityInfo info = loadEntityInfo(clazz); - if (isOnlyCache(info)) return updateCache(info, -1, true, entity, node, selects); - return this.updateColumnCompose(info, true, entity, node, selects).whenComplete((rs, t) -> { - if (t != null) { - futureCompleteConsumer.accept(rs, t); - } else { - updateCache(info, rs, true, entity, node, selects); - } - }).join(); - } - - @Override - public CompletableFuture updateColumnAsync(final T entity, final FilterNode node, final SelectColumn selects) { - if (entity == null || node == null || selects == null) return CompletableFuture.completedFuture(-1); - Class clazz = (Class) entity.getClass(); - final EntityInfo info = loadEntityInfo(clazz); - if (isOnlyCache(info)) { - return CompletableFuture.completedFuture(updateCache(info, -1, true, entity, node, selects)); - } - if (isAsync()) return this.updateColumnCompose(info, true, entity, node, selects).whenComplete((rs, t) -> { - if (t != null) { - futureCompleteConsumer.accept(rs, t); - } else { - updateCache(info, rs, true, entity, node, selects); - } - }); - return CompletableFuture.supplyAsync(() -> this.updateColumnCompose(info, true, entity, node, selects).join(), getExecutor()).whenComplete((rs, t) -> { - if (t != null) { - futureCompleteConsumer.accept(rs, t); - } else { - updateCache(info, rs, true, entity, node, selects); - } - }); - } - - protected CompletableFuture updateColumnCompose(final EntityInfo info, final boolean neednode, final T entity, final FilterNode node, final SelectColumn selects) { - StringBuilder setsql = new StringBuilder(); - List blobs = null; - int index = 0; - String alias = "postgresql".equals(dbtype()) ? null : "a"; //postgresql鐨凚UG锛 UPDATE鐨凷ET涓笉鑳藉惈鍒悕 - for (Attribute attr : info.updateAttributes) { - if (!selects.test(attr.field())) continue; - if (setsql.length() > 0) setsql.append(", "); - setsql.append(info.getSQLColumn(alias, attr.field())); - Serializable val = info.getFieldValue(attr, entity); - if (val instanceof byte[]) { - if (blobs == null) blobs = new ArrayList<>(); - blobs.add((byte[]) val); - setsql.append("=").append(prepareParamSign(++index)); - } else { - CharSequence sqlval = info.formatSQLValue(val, sqlFormatter); - if (sqlval == null && info.isNotNullJson(attr)) sqlval = "''"; - setsql.append("=").append(sqlval); - } - } - if (neednode) { - Map joinTabalis = node.getJoinTabalis(); - CharSequence join = node.createSQLJoin(this, true, joinTabalis, new HashSet<>(), info); - CharSequence where = node.createSQLExpress(this, info, joinTabalis); - StringBuilder join1 = null; - StringBuilder join2 = null; - if (join != null) { - String joinstr = join.toString(); - join1 = multisplit('[', ']', ",", new StringBuilder(), joinstr, 0); - join2 = multisplit('{', '}', " AND ", new StringBuilder(), joinstr, 0); - } - String sql = "UPDATE " + info.getTable(node) + " a " + (join1 == null ? "" : (", " + join1)) + " SET " + setsql - + ((where == null || where.length() == 0) ? (join2 == null ? "" : (" WHERE " + join2)) - : (" WHERE " + where + (join2 == null ? "" : (" AND " + join2)))); - if (blobs == null) return updateColumnDB(info, null, sql, false); - return updateColumnDB(info, null, sql, true, blobs.toArray()); - } else { - final Serializable id = (Serializable) info.getSQLValue(info.getPrimary(), entity); - String sql = "UPDATE " + info.getTable(id) + " a SET " + setsql + " WHERE " + info.getPrimarySQLColumn() + "=" + info.formatSQLValue(id, sqlFormatter); - if (blobs == null) return updateColumnDB(info, null, sql, false); - return updateColumnDB(info, null, sql, true, blobs.toArray()); - } - } - - protected int updateCache(final EntityInfo info, int count, final boolean neednode, final T entity, final FilterNode node, final SelectColumn selects) { - final EntityCache cache = info.getCache(); - if (cache == null) return count; - final List> attrs = new ArrayList<>(); - for (Attribute attr : info.updateAttributes) { - if (!selects.test(attr.field())) continue; - attrs.add(attr); - } - if (neednode) { - T[] rs = cache.update(entity, attrs, node); - return count >= 0 ? count : (rs == null ? 0 : rs.length); - } else { - T rs = cache.update(entity, attrs); - return count >= 0 ? count : (rs == null ? 0 : 1); - } - } - - protected int updateCache(final EntityInfo info, int count, final FilterNode node, final Flipper flipper, final ColumnValue... values) { - final EntityCache cache = info.getCache(); - if (cache == null) return count; - final List> attrs = new ArrayList<>(); - final List cols = new ArrayList<>(); - for (ColumnValue col : values) { - if (col == null) continue; - Attribute attr = info.getUpdateAttribute(col.getColumn()); - if (attr == null) continue; - attrs.add(attr); - cols.add(col); - } - T[] rs = cache.updateColumn(node, flipper, attrs, cols); - return count >= 0 ? count : (rs == null ? 0 : 1); - } - - protected int updateCache(final EntityInfo info, int count, final Serializable pk, final ColumnValue... values) { - final EntityCache cache = info.getCache(); - if (cache == null) return count; - final List> attrs = new ArrayList<>(); - final List cols = new ArrayList<>(); - for (ColumnValue col : values) { - if (col == null) continue; - Attribute attr = info.getUpdateAttribute(col.getColumn()); - if (attr == null) continue; - attrs.add(attr); - cols.add(col); - } - T rs = cache.updateColumn(pk, attrs, cols); - return count >= 0 ? count : (rs == null ? 0 : 1); - } - - protected int updateCache(final EntityInfo info, int count, String column, final Serializable colval, FilterNode node) { - final EntityCache cache = info.getCache(); - if (cache == null) return count; - T[] rs = cache.update(info.getAttribute(column), colval, node); - return count >= 0 ? count : (rs == null ? 0 : 1); - } - - protected int updateCache(final EntityInfo info, int count, final Serializable pk, final String column, final Serializable colval) { - final EntityCache cache = info.getCache(); - if (cache == null) return count; - T rs = cache.update(pk, info.getAttribute(column), colval); - return count >= 0 ? count : (rs == null ? 0 : 1); - } - - protected int updateCache(final EntityInfo info, int count, T... entitys) { - final EntityCache cache = info.getCache(); - if (cache == null) return -1; - int c2 = 0; - for (final T value : entitys) { - c2 += cache.update(value); - } - return count >= 0 ? count : c2; - } - - public int reloadCache(Class clazz, Serializable... pks) { - final EntityInfo info = loadEntityInfo(clazz); - final EntityCache cache = info.getCache(); - if (cache == null) return -1; - String column = info.getPrimary().field(); - int c = 0; - for (Serializable id : pks) { - Sheet sheet = querySheetCompose(false, true, false, clazz, null, FLIPPER_ONE, FilterNode.create(column, id)).join(); - T value = sheet.isEmpty() ? null : sheet.list().get(0); - if (value != null) c += cache.update(value); - } - return c; - } - - //------------------------- getNumberMapCompose ------------------------- - @Override - public Map getNumberMap(final Class entityClass, final FilterNode node, final FilterFuncColumn... columns) { - final EntityInfo info = loadEntityInfo(entityClass); - final EntityCache cache = info.getCache(); - if (cache != null && (isOnlyCache(info) || cache.isFullLoaded())) { - final Map map = new HashMap<>(); - if (node == null || isCacheUseable(node, this)) { - for (FilterFuncColumn ffc : columns) { - for (String col : ffc.cols()) { - map.put(ffc.col(col), cache.getNumberResult(ffc.func, ffc.defvalue, col, node)); - } - } - return map; - } - } - return (Map) getNumberMapCompose(info, node, columns).join(); - } - - @Override - public CompletableFuture> getNumberMapAsync(final Class entityClass, final FilterNode node, final FilterFuncColumn... columns) { - final EntityInfo info = loadEntityInfo(entityClass); - final EntityCache cache = info.getCache(); - if (cache != null && (isOnlyCache(info) || cache.isFullLoaded())) { - final Map map = new HashMap<>(); - if (node == null || isCacheUseable(node, this)) { - for (FilterFuncColumn ffc : columns) { - for (String col : ffc.cols()) { - map.put(ffc.col(col), cache.getNumberResult(ffc.getFunc(), ffc.getDefvalue(), col, node)); - } - } - return CompletableFuture.completedFuture(map); - } - } - if (isAsync()) return getNumberMapCompose(info, node, columns); - return CompletableFuture.supplyAsync(() -> (Map) getNumberMapCompose(info, node, columns).join(), getExecutor()); - } - - protected CompletableFuture> getNumberMapCompose(final EntityInfo info, final FilterNode node, final FilterFuncColumn... columns) { - final Map joinTabalis = node == null ? null : node.getJoinTabalis(); - final Set haset = new HashSet<>(); - final CharSequence join = node == null ? null : node.createSQLJoin(this, false, joinTabalis, haset, info); - final CharSequence where = node == null ? null : node.createSQLExpress(this, info, joinTabalis); - StringBuilder sb = new StringBuilder(); - for (FilterFuncColumn ffc : columns) { - for (String col : ffc.cols()) { - if (sb.length() > 0) sb.append(", "); - sb.append(ffc.func.getColumn((col == null || col.isEmpty() ? "*" : info.getSQLColumn("a", col)))); - } - } - final String sql = "SELECT " + sb + " FROM " + info.getTable(node) + " a" - + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where)); - if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " getnumbermap sql=" + sql); - return getNumberMapDB(info, sql, columns); - } - - @Local - protected CompletableFuture> getNumberMapDBApply(EntityInfo info, CompletableFuture future, FilterFuncColumn... columns) { - return future.thenApply((DataResultSet dataset) -> { - final Map map = new HashMap<>(); - if (dataset.next()) { - int index = 0; - for (FilterFuncColumn ffc : columns) { - for (String col : ffc.cols()) { - Object o = dataset.getObject(++index); - Number rs = ffc.getDefvalue(); - if (o != null) rs = (Number) o; - map.put(ffc.col(col), rs); - } - } - } - dataset.close(); - return map; - }); - } - - //------------------------ getNumberResultCompose ----------------------- - @Override - public Number getNumberResult(final Class entityClass, final FilterFunc func, final Number defVal, final String column, final FilterNode node) { - final EntityInfo info = loadEntityInfo(entityClass); - final EntityCache cache = info.getCache(); - if (cache != null && (isOnlyCache(info) || cache.isFullLoaded())) { - if (node == null || isCacheUseable(node, this)) { - return cache.getNumberResult(func, defVal, column, node); - } - } - return getNumberResultCompose(info, entityClass, func, defVal, column, node).join(); - } - - @Override - public CompletableFuture getNumberResultAsync(final Class entityClass, final FilterFunc func, final Number defVal, final String column, final FilterNode node) { - final EntityInfo info = loadEntityInfo(entityClass); - final EntityCache cache = info.getCache(); - if (cache != null && (isOnlyCache(info) || cache.isFullLoaded())) { - if (node == null || isCacheUseable(node, this)) { - return CompletableFuture.completedFuture(cache.getNumberResult(func, defVal, column, node)); - } - } - if (isAsync()) return getNumberResultCompose(info, entityClass, func, defVal, column, node); - return CompletableFuture.supplyAsync(() -> getNumberResultCompose(info, entityClass, func, defVal, column, node).join(), getExecutor()); - } - - protected CompletableFuture getNumberResultCompose(final EntityInfo info, final Class entityClass, final FilterFunc func, final Number defVal, final String column, final FilterNode node) { - final Map joinTabalis = node == null ? null : node.getJoinTabalis(); - final Set haset = new HashSet<>(); - final CharSequence join = node == null ? null : node.createSQLJoin(this, false, joinTabalis, haset, info); - final CharSequence where = node == null ? null : node.createSQLExpress(this, info, joinTabalis); - final String sql = "SELECT " + func.getColumn((column == null || column.isEmpty() ? "*" : info.getSQLColumn("a", column))) + " FROM " + info.getTable(node) + " a" - + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where)); - if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(entityClass.getSimpleName() + " getnumberresult sql=" + sql); - return getNumberResultDB(info, sql, defVal, column); - } - - @Local - protected CompletableFuture getNumberResultDBApply(EntityInfo info, CompletableFuture future, Number defVal, String column) { - return future.thenApply((DataResultSet dataset) -> { - Number rs = defVal; - if (dataset.next()) { - Object o = dataset.getObject(1); - if (o != null) rs = (Number) o; - } - dataset.close(); - return rs; - }); - } - - //------------------------ queryColumnMapCompose ------------------------ - @Override - public Map queryColumnMap(final Class entityClass, final String keyColumn, final FilterFunc func, final String funcColumn, FilterNode node) { - final EntityInfo info = loadEntityInfo(entityClass); - final EntityCache cache = info.getCache(); - if (cache != null && (isOnlyCache(info) || cache.isFullLoaded())) { - if (node == null || isCacheUseable(node, this)) { - return cache.queryColumnMap(keyColumn, func, funcColumn, node); - } - } - return (Map) queryColumnMapCompose(info, keyColumn, func, funcColumn, node).join(); - } - - @Override - public CompletableFuture> queryColumnMapAsync(final Class entityClass, final String keyColumn, final FilterFunc func, final String funcColumn, FilterNode node) { - final EntityInfo info = loadEntityInfo(entityClass); - final EntityCache cache = info.getCache(); - if (cache != null && (isOnlyCache(info) || cache.isFullLoaded())) { - if (node == null || isCacheUseable(node, this)) { - return CompletableFuture.completedFuture(cache.queryColumnMap(keyColumn, func, funcColumn, node)); - } - } - if (isAsync()) return queryColumnMapCompose(info, keyColumn, func, funcColumn, node); - return CompletableFuture.supplyAsync(() -> (Map) queryColumnMapCompose(info, keyColumn, func, funcColumn, node).join(), getExecutor()); - } - - protected CompletableFuture> queryColumnMapCompose(final EntityInfo info, final String keyColumn, final FilterFunc func, final String funcColumn, FilterNode node) { - final String keySqlColumn = info.getSQLColumn(null, keyColumn); - final Map joinTabalis = node == null ? null : node.getJoinTabalis(); - final Set haset = new HashSet<>(); - final CharSequence join = node == null ? null : node.createSQLJoin(this, false, joinTabalis, haset, info); - final CharSequence where = node == null ? null : node.createSQLExpress(this, info, joinTabalis); - final String funcSqlColumn = func == null ? info.getSQLColumn("a", funcColumn) : func.getColumn((funcColumn == null || funcColumn.isEmpty() ? "*" : info.getSQLColumn("a", funcColumn))); - final String sql = "SELECT a." + keySqlColumn + ", " + funcSqlColumn - + " FROM " + info.getTable(node) + " a" + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where)) + " GROUP BY a." + keySqlColumn; - if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " querycolumnmap sql=" + sql); - return queryColumnMapDB(info, sql, keyColumn); - } - - @Local - protected CompletableFuture> queryColumnMapDBApply(EntityInfo info, CompletableFuture future, final String keyColumn) { - return future.thenApply((DataResultSet dataset) -> { - Map rs = new LinkedHashMap<>(); - while (dataset.next()) { - rs.put((K) dataset.getObject(1), (N) dataset.getObject(2)); - } - dataset.close(); - return rs; - }); - } - - @Override - public Map queryColumnMap(final Class entityClass, final ColumnNode[] funcNodes, final String groupByColumn, final FilterNode node) { - Map map = queryColumnMap(entityClass, funcNodes, Utility.ofArray(groupByColumn), node); - final Map rs = new LinkedHashMap<>(); - map.forEach((keys, values) -> rs.put(keys[0], values)); - return rs; - } - - @Override - public CompletableFuture> queryColumnMapAsync(final Class entityClass, final ColumnNode[] funcNodes, final String groupByColumn, final FilterNode node) { - CompletableFuture> future = queryColumnMapAsync(entityClass, funcNodes, Utility.ofArray(groupByColumn), node); - return future.thenApply(map -> { - final Map rs = new LinkedHashMap<>(); - map.forEach((keys, values) -> rs.put(keys[0], values)); - return rs; - }); - } - - @Override - public Map queryColumnMap(final Class entityClass, final ColumnNode[] funcNodes, final String[] groupByColumns, final FilterNode node) { - final EntityInfo info = loadEntityInfo(entityClass); - final EntityCache cache = info.getCache(); - if (cache != null && (isOnlyCache(info) || cache.isFullLoaded())) { - if (node == null || isCacheUseable(node, this)) { - return cache.queryColumnMap(funcNodes, groupByColumns, node); - } - } - return (Map) queryColumnMapCompose(info, funcNodes, groupByColumns, node).join(); - } - - @Override - public CompletableFuture> queryColumnMapAsync(final Class entityClass, final ColumnNode[] funcNodes, final String[] groupByColumns, final FilterNode node) { - final EntityInfo info = loadEntityInfo(entityClass); - final EntityCache cache = info.getCache(); - if (cache != null && (isOnlyCache(info) || cache.isFullLoaded())) { - if (node == null || isCacheUseable(node, this)) { - return CompletableFuture.completedFuture(cache.queryColumnMap(funcNodes, groupByColumns, node)); - } - } - if (isAsync()) return queryColumnMapCompose(info, funcNodes, groupByColumns, node); - return CompletableFuture.supplyAsync(() -> (Map) queryColumnMapCompose(info, funcNodes, groupByColumns, node).join(), getExecutor()); - } - - protected CompletableFuture> queryColumnMapCompose(final EntityInfo info, final ColumnNode[] funcNodes, final String[] groupByColumns, final FilterNode node) { - final StringBuilder groupBySqlColumns = new StringBuilder(); - if (groupByColumns != null && groupByColumns.length > 0) { - for (int i = 0; i < groupByColumns.length; i++) { - if (groupBySqlColumns.length() > 0) groupBySqlColumns.append(", "); - groupBySqlColumns.append(info.getSQLColumn("a", groupByColumns[i])); - } - } - final StringBuilder funcSqlColumns = new StringBuilder(); - for (int i = 0; i < funcNodes.length; i++) { - if (funcSqlColumns.length() > 0) funcSqlColumns.append(", "); - if (funcNodes[i] instanceof ColumnFuncNode) { - funcSqlColumns.append(info.formatSQLValue((Attribute) null, "a", (ColumnFuncNode) funcNodes[i], sqlFormatter)); - } else { - funcSqlColumns.append(info.formatSQLValue((Attribute) null, "a", (ColumnNodeValue) funcNodes[i], sqlFormatter)); - } - } - final Map joinTabalis = node == null ? null : node.getJoinTabalis(); - final Set haset = new HashSet<>(); - final CharSequence join = node == null ? null : node.createSQLJoin(this, false, joinTabalis, haset, info); - final CharSequence where = node == null ? null : node.createSQLExpress(this, info, joinTabalis); - String sql = "SELECT "; - if (groupBySqlColumns.length() > 0) sql += groupBySqlColumns + ", "; - sql += funcSqlColumns + " FROM " + info.getTable(node) + " a" + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where)); - if (groupBySqlColumns.length() > 0) sql += " GROUP BY " + groupBySqlColumns; - if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " querycolumnmap sql=" + sql); - return queryColumnMapDB(info, sql, funcNodes, groupByColumns); - } - - @Local - protected CompletableFuture> queryColumnMapDBApply(EntityInfo info, CompletableFuture future, final ColumnNode[] funcNodes, final String[] groupByColumns) { - return future.thenApply((DataResultSet dataset) -> { - Map rs = new LinkedHashMap<>(); - while (dataset.next()) { - int index = 0; - Serializable[] keys = new Serializable[groupByColumns.length]; - for (int i = 0; i < keys.length; i++) { - keys[i] = (Serializable) dataset.getObject(++index); - } - Number[] vals = new Number[funcNodes.length]; - for (int i = 0; i < vals.length; i++) { - vals[i] = (Number) dataset.getObject(++index); - } - rs.put(keys, vals); - } - dataset.close(); - return rs; - }); - } - - //----------------------------- find ----------------------------- - @Override - public T[] finds(Class clazz, final SelectColumn selects, Serializable... pks) { - return findsAsync(clazz, selects, pks).join(); - } - - @Override - public CompletableFuture findsAsync(Class clazz, final SelectColumn selects, Serializable... pks) { - final EntityInfo info = loadEntityInfo(clazz); - if (pks == null || pks.length == 0) return CompletableFuture.completedFuture(info.getArrayer().apply(0)); - final EntityCache cache = info.getCache(); - if (cache != null) { - T[] rs = selects == null ? cache.finds(pks) : cache.finds(selects, pks); - if (cache.isFullLoaded() || rs != null) return CompletableFuture.completedFuture(rs); - } - return findsComposeAsync(info, selects, pks); - } - - protected CompletableFuture findsComposeAsync(final EntityInfo info, final SelectColumn selects, Serializable... pks) { - final Attribute primary = info.getPrimary(); - return queryListAsync(info.getType(), selects, null, FilterNode.create(info.getPrimarySQLColumn(), FilterExpress.IN, pks)).thenApply(list -> { - T[] rs = info.getArrayer().apply(pks.length); - for (int i = 0; i < rs.length; i++) { - T t = null; - Serializable pk = pks[i]; - for (T item : list) { - if (pk.equals(primary.get(item))) { - t = item; - break; - } - } - rs[i] = t; - } - return rs; - }); - } - - @Override - public T find(Class clazz, final SelectColumn selects, Serializable pk) { - final EntityInfo info = loadEntityInfo(clazz); - final EntityCache cache = info.getCache(); - if (cache != null) { - T rs = selects == null ? cache.find(pk) : cache.find(selects, pk); - if (cache.isFullLoaded() || rs != null) return rs; - } - return findCompose(info, selects, pk).join(); - } - - @Override - public CompletableFuture findAsync(final Class clazz, final SelectColumn selects, final Serializable pk) { - final EntityInfo info = loadEntityInfo(clazz); - final EntityCache cache = info.getCache(); - if (cache != null) { - T rs = selects == null ? cache.find(pk) : cache.find(selects, pk); - if (cache.isFullLoaded() || rs != null) return CompletableFuture.completedFuture(rs); - } - if (isAsync()) return findCompose(info, selects, pk); - return CompletableFuture.supplyAsync(() -> findCompose(info, selects, pk).join(), getExecutor()); - } - - protected CompletableFuture findCompose(final EntityInfo info, final SelectColumn selects, Serializable pk) { - String column = info.getPrimarySQLColumn(); - final String sql = "SELECT " + info.getQueryColumns(null, selects) + " FROM " + info.getTable(pk) + " WHERE " + column + "=" + info.formatSQLValue(column, pk, sqlFormatter); - if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " find sql=" + sql); - return findDB(info, sql, true, selects); - } - - @Override - public T find(final Class clazz, final SelectColumn selects, final FilterNode node) { - final EntityInfo info = loadEntityInfo(clazz); - final EntityCache cache = info.getCache(); - if (cache != null && cache.isFullLoaded() && (node == null || isCacheUseable(node, this))) return cache.find(selects, node); - return this.findCompose(info, selects, node).join(); - } - - @Override - public CompletableFuture findAsync(final Class clazz, final SelectColumn selects, final FilterNode node) { - final EntityInfo info = loadEntityInfo(clazz); - final EntityCache cache = info.getCache(); - if (cache != null && cache.isFullLoaded() && (node == null || isCacheUseable(node, this))) { - return CompletableFuture.completedFuture(cache.find(selects, node)); - } - if (isAsync()) return this.findCompose(info, selects, node); - return CompletableFuture.supplyAsync(() -> this.findCompose(info, selects, node).join(), getExecutor()); - } - - protected CompletableFuture findCompose(final EntityInfo info, final SelectColumn selects, final FilterNode node) { - final Map joinTabalis = node == null ? null : node.getJoinTabalis(); - final CharSequence join = node == null ? null : node.createSQLJoin(this, false, joinTabalis, new HashSet<>(), info); - final CharSequence where = node == null ? null : node.createSQLExpress(this, info, joinTabalis); - final String sql = "SELECT " + info.getQueryColumns("a", selects) + " FROM " + info.getTable(node) + " a" + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where)); - if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " find sql=" + sql); - return findDB(info, sql, false, selects); - } - - @Local - protected CompletableFuture findDBApply(EntityInfo info, CompletableFuture future, boolean onlypk, SelectColumn selects) { - return future.thenApply((DataResultSet pgset) -> { - T rs = pgset.next() ? (onlypk && selects == null ? getEntityValue(info, null, pgset) : getEntityValue(info, selects, pgset)) : null; - pgset.close(); - return rs; - }); - } - - @Override - public Serializable findColumn(final Class clazz, final String column, final Serializable defValue, final Serializable pk) { - final EntityInfo info = loadEntityInfo(clazz); - final EntityCache cache = info.getCache(); - if (cache != null) { - Serializable val = cache.findColumn(column, defValue, pk); - if (cache.isFullLoaded() || val != null) return val; - } - return findColumnCompose(info, column, defValue, pk).join(); - } - - @Override - public CompletableFuture findColumnAsync(final Class clazz, final String column, final Serializable defValue, final Serializable pk) { - final EntityInfo info = loadEntityInfo(clazz); - final EntityCache cache = info.getCache(); - if (cache != null) { - Serializable val = cache.findColumn(column, defValue, pk); - if (cache.isFullLoaded() || val != null) return CompletableFuture.completedFuture(val); - } - if (isAsync()) return findColumnCompose(info, column, defValue, pk); - return CompletableFuture.supplyAsync(() -> findColumnCompose(info, column, defValue, pk).join(), getExecutor()); - } - - protected CompletableFuture findColumnCompose(final EntityInfo info, String column, final Serializable defValue, final Serializable pk) { - final String sql = "SELECT " + info.getSQLColumn(null, column) + " FROM " + info.getTable(pk) + " WHERE " + info.getPrimarySQLColumn() + "=" + info.formatSQLValue(info.getPrimarySQLColumn(), pk, sqlFormatter); - if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " find sql=" + sql); - return findColumnDB(info, sql, true, column, defValue); - } - - @Override - public Serializable findColumn(final Class clazz, final String column, final Serializable defValue, final FilterNode node) { - final EntityInfo info = loadEntityInfo(clazz); - final EntityCache cache = info.getCache(); - if (cache != null) { - Serializable val = cache.findColumn(column, defValue, node); - if (cache.isFullLoaded() || val != null) return val; - } - return this.findColumnCompose(info, column, defValue, node).join(); - } - - @Override - public CompletableFuture findColumnAsync(final Class clazz, final String column, final Serializable defValue, final FilterNode node) { - final EntityInfo info = loadEntityInfo(clazz); - final EntityCache cache = info.getCache(); - if (cache != null) { - Serializable val = cache.findColumn(column, defValue, node); - if (cache.isFullLoaded() || val != null) return CompletableFuture.completedFuture(val); - } - if (isAsync()) return this.findColumnCompose(info, column, defValue, node); - return CompletableFuture.supplyAsync(() -> this.findColumnCompose(info, column, defValue, node).join(), getExecutor()); - } - - protected CompletableFuture findColumnCompose(final EntityInfo info, String column, final Serializable defValue, final FilterNode node) { - final Map joinTabalis = node == null ? null : node.getJoinTabalis(); - final CharSequence join = node == null ? null : node.createSQLJoin(this, false, joinTabalis, new HashSet<>(), info); - final CharSequence where = node == null ? null : node.createSQLExpress(this, info, joinTabalis); - final String sql = "SELECT " + info.getSQLColumn("a", column) + " FROM " + info.getTable(node) + " a" + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where)); - if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " find sql=" + sql); - return findColumnDB(info, sql, false, column, defValue); - } - - @Local - protected CompletableFuture findColumnDBApply(EntityInfo info, CompletableFuture future, boolean onlypk, String column, Serializable defValue) { - return future.thenApply((DataResultSet dataset) -> { - Serializable val = defValue; - if (dataset.next()) { - final Attribute attr = info.getAttribute(column); - val = dataset.getObject(attr, 1, null); - } - dataset.close(); - return val == null ? defValue : val; - }); - } - - //---------------------------- existsCompose ---------------------------- - @Override - public boolean exists(Class clazz, Serializable pk) { - final EntityInfo info = loadEntityInfo(clazz); - final EntityCache cache = info.getCache(); - if (cache != null) { - boolean rs = cache.exists(pk); - if (rs || cache.isFullLoaded()) return rs; - } - return existsCompose(info, pk).join(); - } - - @Override - public CompletableFuture existsAsync(final Class clazz, final Serializable pk) { - final EntityInfo info = loadEntityInfo(clazz); - final EntityCache cache = info.getCache(); - if (cache != null) { - boolean rs = cache.exists(pk); - if (rs || cache.isFullLoaded()) return CompletableFuture.completedFuture(rs); - } - if (isAsync()) return existsCompose(info, pk); - return CompletableFuture.supplyAsync(() -> existsCompose(info, pk).join(), getExecutor()); - } - - protected CompletableFuture existsCompose(final EntityInfo info, Serializable pk) { - final String sql = "SELECT COUNT(*) FROM " + info.getTable(pk) + " WHERE " + info.getPrimarySQLColumn() + "=" + info.formatSQLValue(info.getPrimarySQLColumn(), pk, sqlFormatter); - if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " exists sql=" + sql); - return existsDB(info, sql, true); - } - - @Override - public boolean exists(final Class clazz, final FilterNode node) { - final EntityInfo info = loadEntityInfo(clazz); - final EntityCache cache = info.getCache(); - if (cache != null) { - boolean rs = cache.exists(node); - if (rs || cache.isFullLoaded()) return rs; - } - return this.existsCompose(info, node).join(); - } - - @Override - public CompletableFuture existsAsync(final Class clazz, final FilterNode node) { - final EntityInfo info = loadEntityInfo(clazz); - final EntityCache cache = info.getCache(); - if (cache != null) { - boolean rs = cache.exists(node); - if (rs || cache.isFullLoaded()) return CompletableFuture.completedFuture(rs); - } - if (isAsync()) return this.existsCompose(info, node); - return CompletableFuture.supplyAsync(() -> this.existsCompose(info, node).join(), getExecutor()); - } - - protected CompletableFuture existsCompose(final EntityInfo info, FilterNode node) { - final Map joinTabalis = node == null ? null : node.getJoinTabalis(); - final CharSequence join = node == null ? null : node.createSQLJoin(this, false, joinTabalis, new HashSet<>(), info); - final CharSequence where = node == null ? null : node.createSQLExpress(this, info, joinTabalis); - final String sql = "SELECT COUNT(" + info.getPrimarySQLColumn("a") + ") FROM " + info.getTable(node) + " a" + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where)); - if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " exists sql=" + sql); - return existsDB(info, sql, false); - } - - @Local - protected CompletableFuture existsDBApply(EntityInfo info, CompletableFuture future, boolean onlypk) { - return future.thenApply((DataResultSet pgset) -> { - boolean rs = pgset.next() ? (((Number) pgset.getObject(1)).intValue() > 0) : false; - pgset.close(); - return rs; - }); - } - - //-----------------------list set---------------------------- - @Override - public Set queryColumnSet(final String selectedColumn, final Class clazz, final Flipper flipper, final FilterNode node) { - final Set list = querySet(clazz, SelectColumn.includes(selectedColumn), flipper, node); - final Set rs = new LinkedHashSet<>(); - if (list.isEmpty()) return rs; - final EntityInfo info = loadEntityInfo(clazz); - final Attribute selected = (Attribute) info.getAttribute(selectedColumn); - for (T t : list) { - rs.add(selected.get(t)); - } - return rs; - } - - @Override - public CompletableFuture> queryColumnSetAsync(final String selectedColumn, final Class clazz, final Flipper flipper, final FilterNode node) { - return querySetAsync(clazz, SelectColumn.includes(selectedColumn), flipper, node).thenApply((Set list) -> { - final Set rs = new LinkedHashSet<>(); - if (list.isEmpty()) return rs; - final EntityInfo info = loadEntityInfo(clazz); - final Attribute selected = (Attribute) info.getAttribute(selectedColumn); - for (T t : list) { - rs.add(selected.get(t)); - } - return rs; - }); - } - - @Override - public List queryColumnList(final String selectedColumn, final Class clazz, final Flipper flipper, final FilterNode node) { - final List list = queryList(clazz, SelectColumn.includes(selectedColumn), flipper, node); - final List rs = new ArrayList<>(); - if (list.isEmpty()) return rs; - final EntityInfo info = loadEntityInfo(clazz); - final Attribute selected = (Attribute) info.getAttribute(selectedColumn); - for (T t : list) { - rs.add(selected.get(t)); - } - return rs; - } - - @Override - public CompletableFuture> queryColumnListAsync(final String selectedColumn, final Class clazz, final Flipper flipper, final FilterNode node) { - return queryListAsync(clazz, SelectColumn.includes(selectedColumn), flipper, node).thenApply((List list) -> { - final List rs = new ArrayList<>(); - if (list.isEmpty()) return rs; - final EntityInfo info = loadEntityInfo(clazz); - final Attribute selected = (Attribute) info.getAttribute(selectedColumn); - for (T t : list) { - rs.add(selected.get(t)); - } - return rs; - }); - } - - @Override - public Sheet queryColumnSheet(final String selectedColumn, final Class clazz, final Flipper flipper, final FilterNode node) { - Sheet sheet = querySheet(clazz, SelectColumn.includes(selectedColumn), flipper, node); - final Sheet rs = new Sheet<>(); - if (sheet.isEmpty()) return rs; - rs.setTotal(sheet.getTotal()); - final EntityInfo info = loadEntityInfo(clazz); - final Attribute selected = (Attribute) info.getAttribute(selectedColumn); - final List list = new ArrayList<>(); - for (T t : sheet.getRows()) { - list.add(selected.get(t)); - } - rs.setRows(list); - return rs; - } - - @Override - public CompletableFuture> queryColumnSheetAsync(final String selectedColumn, final Class clazz, final Flipper flipper, final FilterNode node) { - return querySheetAsync(clazz, SelectColumn.includes(selectedColumn), flipper, node).thenApply((Sheet sheet) -> { - final Sheet rs = new Sheet<>(); - if (sheet.isEmpty()) return rs; - rs.setTotal(sheet.getTotal()); - final EntityInfo info = loadEntityInfo(clazz); - final Attribute selected = (Attribute) info.getAttribute(selectedColumn); - final List list = new ArrayList<>(); - for (T t : sheet.getRows()) { - list.add(selected.get(t)); - } - rs.setRows(list); - return rs; - }); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凪ap闆嗗悎, 涓婚敭鍊间负key
- * 绛変环SQL: SELECT * FROM {table} WHERE {column} = {key} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param 涓婚敭娉涘瀷 - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param selects 鎸囧畾瀛楁 - * @param keyStream 涓婚敭Stream - * - * @return Entity鐨勯泦鍚 - */ - @Override - public Map queryMap(final Class clazz, final SelectColumn selects, final Stream keyStream) { - if (keyStream == null) return new LinkedHashMap<>(); - final EntityInfo info = loadEntityInfo(clazz); - final ArrayList ids = new ArrayList<>(); - keyStream.forEach(k -> ids.add(k)); - final Attribute primary = info.getPrimary(); - List rs = queryList(clazz, FilterNode.create(primary.field(), ids)); - Map map = new LinkedHashMap<>(); - if (rs.isEmpty()) return new LinkedHashMap<>(); - for (T item : rs) { - map.put((K) primary.get(item), item); - } - return map; - } - - @Override - public CompletableFuture> queryMapAsync(final Class clazz, final SelectColumn selects, final Stream keyStream) { - if (keyStream == null) return CompletableFuture.completedFuture(new LinkedHashMap<>()); - final EntityInfo info = loadEntityInfo(clazz); - final ArrayList pks = new ArrayList<>(); - keyStream.forEach(k -> pks.add(k)); - final Attribute primary = info.getPrimary(); - return queryListAsync(clazz, FilterNode.create(primary.field(), pks)).thenApply((List rs) -> { - Map map = new LinkedHashMap<>(); - if (rs.isEmpty()) return new LinkedHashMap<>(); - for (T item : rs) { - map.put((K) primary.get(item), item); - } - return map; - }); - } - - /** - * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凪ap闆嗗悎, 涓婚敭鍊间负key
- * 绛変环SQL: SELECT * FROM {table} WHERE {column} = {key} ORDER BY {flipper.sort} LIMIT {flipper.limit}
- * - * @param 涓婚敭娉涘瀷 - * @param Entity娉涘瀷 - * @param clazz Entity绫 - * @param selects 鎸囧畾瀛楁 - * @param node FilterNode - * - * @return Entity鐨勯泦鍚 - */ - @Override - public Map queryMap(final Class clazz, final SelectColumn selects, final FilterNode node) { - List rs = queryList(clazz, selects, node); - final EntityInfo info = loadEntityInfo(clazz); - final Attribute primary = info.getPrimary(); - Map map = new LinkedHashMap<>(); - if (rs.isEmpty()) return new LinkedHashMap<>(); - for (T item : rs) { - map.put((K) primary.get(item), item); - } - return map; - } - - @Override - public CompletableFuture> queryMapAsync(final Class clazz, final SelectColumn selects, final FilterNode node) { - return queryListAsync(clazz, selects, node).thenApply((List rs) -> { - final EntityInfo info = loadEntityInfo(clazz); - final Attribute primary = info.getPrimary(); - Map map = new LinkedHashMap<>(); - if (rs.isEmpty()) return new LinkedHashMap<>(); - for (T item : rs) { - map.put((K) primary.get(item), item); - } - return map; - }); - } - - @Override - public Set querySet(final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node) { - return new LinkedHashSet<>(querySheetCompose(true, false, true, clazz, selects, flipper, node).join().list(true)); - } - - @Override - public CompletableFuture> querySetAsync(final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node) { - return querySheetCompose(true, false, true, clazz, selects, flipper, node).thenApply((rs) -> new LinkedHashSet<>(rs.list(true))); - } - - @Override - public List queryList(final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node) { - return querySheetCompose(true, false, false, clazz, selects, flipper, node).join().list(true); - } - - @Override - public CompletableFuture> queryListAsync(final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node) { - return querySheetCompose(true, false, false, clazz, selects, flipper, node).thenApply((rs) -> rs.list(true)); - } - - @Override - public Sheet querySheet(final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node) { - return querySheetCompose(true, true, false, clazz, selects, flipper, node).join(); - } - - @Override - public CompletableFuture> querySheetAsync(final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node) { - if (isAsync()) return querySheetCompose(true, true, false, clazz, selects, flipper, node); - return CompletableFuture.supplyAsync(() -> querySheetCompose(true, true, false, clazz, selects, flipper, node).join(), getExecutor()); - } - - protected CompletableFuture> querySheetCompose(final boolean readcache, final boolean needtotal, final boolean distinct, final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node) { - final EntityInfo info = loadEntityInfo(clazz); - final EntityCache cache = info.getCache(); - if (readcache && cache != null && cache.isFullLoaded()) { - if (node == null || isCacheUseable(node, this)) { - if (info.isLoggable(logger, Level.FINEST, " cache query predicate = ")) logger.finest(clazz.getSimpleName() + " cache query predicate = " + (node == null ? null : createPredicate(node, cache))); - return CompletableFuture.completedFuture(cache.querySheet(needtotal, distinct, selects, flipper, node)); - } - } - return querySheetDB(info, readcache, needtotal, distinct, selects, flipper, node); - } - - protected static enum UpdateMode { - INSERT, DELETE, UPDATE, CLEAR, DROP, ALTER, OTHER; - } -} +/* + * 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.source; + +import java.io.Serializable; +import java.math.*; +import java.net.URL; +import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.*; +import java.util.function.*; +import java.util.logging.*; +import java.util.stream.Stream; +import javax.annotation.Resource; +import static org.redkale.boot.Application.*; +import org.redkale.net.AsyncGroup; +import org.redkale.service.*; +import static org.redkale.source.DataSources.*; +import org.redkale.source.EntityInfo.EntityColumn; +import org.redkale.util.*; + +/** + * DataSource鐨凷QL鎶借薄瀹炵幇绫
+ * 娉ㄦ剰: 鎵鏈夌殑鎿嶄綔鍙兘浣滅敤鍦ㄤ竴寮犺〃涓婏紝涓嶈兘鍚屾椂鍙樻洿澶氬紶琛 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@Local +@AutoLoad(false) +@SuppressWarnings("unchecked") +@ResourceType(DataSource.class) +public abstract class DataSqlSource extends AbstractDataSource implements Function { + + protected static final Flipper FLIPPER_ONE = new Flipper(1); + + protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); + + protected String name; + + protected URL persistFile; + + protected boolean cacheForbidden; + + private final String dbtype; + + private final boolean autoddl; + + protected Properties readConfProps; + + protected Properties writeConfProps; + + @Resource(name = RESNAME_APP_ASYNCGROUP) + protected AsyncGroup asyncGroup; + + @Resource(name = RESNAME_APP_EXECUTOR) + protected ExecutorService workExecutor; + + protected final BiFunction sqlFormatter; + + protected BiConsumer futureCompleteConsumer = (r, t) -> { + if (t != null) logger.log(Level.INFO, "CompletableFuture complete error", (Throwable) t); + }; + + protected final BiFunction> fullloader = (s, i) + -> ((CompletableFuture) querySheetDB(i, false, false, false, null, null, (FilterNode) null)).thenApply(e -> e == null ? new ArrayList() : e.list(true)); + + //鐢ㄤ簬鍙嶅悜LIKE浣跨敤 + protected final String containSQL; + + //鐢ㄤ簬鍙嶅悜LIKE浣跨敤 + protected final String notcontainSQL; + + //鐢ㄤ簬鍒ゆ柇琛ㄤ笉瀛樺湪鐨勪娇鐢, 澶氫釜SQLState鐢;闅斿紑 + protected final String tablenotexistSqlstates; + + //鐢ㄤ簬澶嶅埗琛ㄧ粨鏋勪娇鐢 + protected final String tablecopySQL; + + @SuppressWarnings({"OverridableMethodCallInConstructor", "LeakingThisInConstructor"}) + public DataSqlSource(String unitName, URL persistFile, String dbtype, Properties readConf, Properties writeConf) { + if (readConf == null) readConf = new Properties(); + if (writeConf == null) writeConf = readConf; + this.dbtype = dbtype; + initProperties(readConf); + if (writeConf != readConf) initProperties(writeConf); + this.name = unitName; + this.persistFile = persistFile; + this.readConfProps = readConf; + this.writeConfProps = writeConf; + this.sqlFormatter = (info, val) -> formatValueToString(info, val); + this.autoddl = "true".equals(readConf.getProperty(DataSources.JDBC_TABLE_AUTODDL, "false").trim()); + + this.containSQL = readConf.getProperty(DataSources.JDBC_CONTAIN_SQLTEMPLATE, "LOCATE(${keystr}, ${column}) > 0"); + this.notcontainSQL = readConf.getProperty(DataSources.JDBC_NOTCONTAIN_SQLTEMPLATE, "LOCATE(${keystr}, ${column}) = 0"); + + this.tablenotexistSqlstates = ";" + readConf.getProperty(DataSources.JDBC_TABLENOTEXIST_SQLSTATES, "42000;42S02") + ";"; + this.tablecopySQL = readConf.getProperty(DataSources.JDBC_TABLECOPY_SQLTEMPLATE, "CREATE TABLE IF NOT EXISTS ${newtable} LIKE ${oldtable}"); + } + + protected void initProperties(Properties props) { + if ("oracle".equals(this.dbtype)) { + props.setProperty(JDBC_CONTAIN_SQLTEMPLATE, "INSTR(${keystr}, ${column}) > 0"); + props.setProperty(JDBC_NOTCONTAIN_SQLTEMPLATE, "INSTR(${keystr}, ${column}) = 0"); + if (!props.containsKey(JDBC_TABLENOTEXIST_SQLSTATES)) { + props.setProperty(JDBC_TABLENOTEXIST_SQLSTATES, "42000;42S02"); + } + if (!props.containsKey(JDBC_TABLECOPY_SQLTEMPLATE)) { + //娉ㄦ剰锛氭璇彞澶嶅埗琛ㄧ粨鏋勪細瀵艰嚧榛樿鍊煎拰涓婚敭淇℃伅鐨勪涪澶 + props.setProperty(JDBC_TABLECOPY_SQLTEMPLATE, "CREATE TABLE IF NOT EXISTS ${newtable} AS SELECT * FROM ${oldtable} WHERE 1=2"); + } + } else if ("sqlserver".equals(this.dbtype)) { + props.setProperty(JDBC_CONTAIN_SQLTEMPLATE, "CHARINDEX(${column}, ${keystr}) > 0"); + props.setProperty(JDBC_NOTCONTAIN_SQLTEMPLATE, "CHARINDEX(${column}, ${keystr}) = 0"); + } else if ("postgresql".equals(this.dbtype)) { + if (!props.containsKey(JDBC_TABLECOPY_SQLTEMPLATE)) { //娉ㄦ剰锛氭璇彞澶嶅埗琛ㄧ粨鏋勪細瀵艰嚧榛樿鍊煎拰涓婚敭淇℃伅鐨勪涪澶 + //娉ㄦ剰锛歱ostgresql涓嶆敮鎸佽法搴撳鍒惰〃缁撴瀯 + //props.setProperty(JDBC_TABLECOPY_SQLTEMPLATE, "CREATE TABLE ${newtable} AS (SELECT * FROM ${oldtable} LIMIT 0)"); + props.setProperty(JDBC_TABLECOPY_SQLTEMPLATE, "CREATE TABLE IF NOT EXISTS ${newtable} (LIKE ${oldtable} INCLUDING DEFAULTS INCLUDING CONSTRAINTS INCLUDING COMMENTS INCLUDING INDEXES)"); + } + if (!props.containsKey(JDBC_TABLENOTEXIST_SQLSTATES)) { + props.setProperty(JDBC_TABLENOTEXIST_SQLSTATES, "42P01;3F000"); + } + } + } + + //鐢熸垚鍒涘缓琛ㄧ殑SQL + protected String createTableSql(EntityInfo info) { + if (info == null || !autoddl) return null; + javax.persistence.Table table = info.getType().getAnnotation(javax.persistence.Table.class); + if ("mysql".equals(dbtype())) { //mysql + StringBuilder sb = new StringBuilder(); + sb.append("CREATE TABLE IF NOT EXISTS `").append(info.getOriginTable()).append("`(\n"); + EntityColumn primary = null; + T one = info.constructorAttributes == null ? info.getCreator().create() : null; + for (EntityColumn column : info.getDDLColumns()) { + if (column.primary) primary = column; + String sqltype = "VARCHAR(" + column.length + ")"; + String sqlnull = column.primary ? "NOT NULL" : "NULL"; + if (column.type == boolean.class || column.type == Boolean.class) { + sqltype = "TINYINT(1)"; + Boolean val = one == null ? null : (Boolean) info.getAttribute(column.field).get(one); + sqlnull = "NOT NULL DEFAULT " + (val != null && val ? 1 : 0); + } else if (column.type == byte.class || column.type == Byte.class) { + sqltype = "TINYINT"; + Number val = one == null ? null : (Number) info.getAttribute(column.field).get(one); + sqlnull = "NOT NULL DEFAULT " + (val == null ? 0 : val.byteValue()); + } else if (column.type == short.class || column.type == Short.class) { + sqltype = "SMALLINT"; + Number val = one == null ? null : (Number) info.getAttribute(column.field).get(one); + sqlnull = "NOT NULL DEFAULT " + (val == null ? 0 : val); + } else if (column.type == char.class || column.type == Character.class) { + sqltype = "SMALLINT UNSIGNED"; + Number val = one == null ? null : (Number) info.getAttribute(column.field).get(one); + sqlnull = "NOT NULL DEFAULT " + (val == null ? 0 : val.intValue()); + } else if (column.type == int.class || column.type == Integer.class || column.type == AtomicInteger.class) { + sqltype = "INT"; + Number val = one == null ? null : (Number) info.getAttribute(column.field).get(one); + sqlnull = "NOT NULL DEFAULT " + (val == null ? 0 : val); + } else if (column.type == long.class || column.type == Long.class || column.type == AtomicLong.class || column.type == LongAdder.class) { + sqltype = "BIGINT"; + Number val = one == null ? null : (Number) info.getAttribute(column.field).get(one); + sqlnull = "NOT NULL DEFAULT " + (val == null ? 0 : val); + } else if (column.type == float.class || column.type == Float.class) { + sqltype = "FLOAT"; + if (column.precision > 0) sqltype += "(" + column.precision + "," + column.scale + ")"; + Number val = one == null ? null : (Number) info.getAttribute(column.field).get(one); + sqlnull = "NOT NULL DEFAULT " + (val == null ? 0 : val); + } else if (column.type == double.class || column.type == Double.class) { + sqltype = "DOUBLE"; + if (column.precision > 0) sqltype += "(" + column.precision + "," + column.scale + ")"; + Number val = one == null ? null : (Number) info.getAttribute(column.field).get(one); + sqlnull = "NOT NULL DEFAULT " + (val == null ? 0 : val); + } else if (column.type == BigInteger.class) { + sqltype = "DECIMAL"; + if (column.precision > 0) { + sqltype += "(" + column.precision + "," + column.scale + ")"; + } else { + sqltype += "(19,2)"; + } + Number val = one == null ? null : (Number) info.getAttribute(column.field).get(one); + sqlnull = "NOT NULL DEFAULT " + (val == null ? 0 : val); + } else if (column.type == BigDecimal.class) { + sqltype = "DECIMAL"; + if (column.precision > 0) sqltype += "(" + column.precision + "," + column.scale + ")"; + Number val = one == null ? null : (Number) info.getAttribute(column.field).get(one); + sqlnull = "NOT NULL DEFAULT " + (val == null ? 0 : val); + } else if (column.type == String.class) { + if (column.length < 65535) { + String val = one == null ? null : (String) info.getAttribute(column.field).get(one); + if (val != null) { + sqlnull = "NOT NULL DEFAULT '" + val.replace('\'', '"') + "'"; + } else if (column.primary) { + sqlnull = "NOT NULL DEFAULT ''"; + } + } else if (column.length == 65535) { + sqltype = "TEXT"; + if (!column.nullable) sqlnull = "NOT NULL"; + } else if (column.length <= 16777215) { + sqltype = "MEDIUMTEXT"; + if (!column.nullable) sqlnull = "NOT NULL"; + } else { + sqltype = "LONGTEXT"; + if (!column.nullable) sqlnull = "NOT NULL"; + } + } else if (column.type == byte[].class) { + if (column.length <= 65535) { + sqltype = "BLOB"; + if (!column.nullable) sqlnull = "NOT NULL"; + } else if (column.length <= 16777215) { + sqltype = "MEDIUMBLOB"; + if (!column.nullable) sqlnull = "NOT NULL"; + } else { + sqltype = "LONGBLOB"; + if (!column.nullable) sqlnull = "NOT NULL"; + } + } else if (column.type == java.time.LocalDate.class || column.type == java.util.Date.class || "java.sql.Date".equals(column.type.getName())) { + sqltype = "DATE"; + } else if (column.type == java.time.LocalTime.class || "java.sql.Time".equals(column.type.getName())) { + sqltype = "TIME"; + } else if (column.type == java.time.LocalDateTime.class || "java.sql.Timestamp".equals(column.type.getName())) { + sqltype = "DATETIME"; + } else { //JavaBean + sqltype = column.length >= 65535 ? "TEXT" : ("VARCHAR(" + column.length + ")"); + sqlnull = !column.nullable ? "NOT NULL DEFAULT ''" : "NULL"; + } + sb.append(" `").append(column.column).append("` ").append(sqltype).append(" ").append(sqlnull); + if (column.comment != null && !column.comment.isEmpty()) { + sb.append(" COMMENT '").append(column.comment.replace('\'', '"')).append("'"); + } + sb.append(",\n"); + } + sb.append(" PRIMARY KEY (`").append(primary.column).append("`)\n"); + sb.append(")ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4"); + if (table != null && !table.comment().isEmpty()) { + sb.append(" COMMENT '").append(table.comment().replace('\'', '"')).append("'"); + } + return sb.toString(); + } else if ("postgresql".equals(dbtype())) { //postgresql + StringBuilder sb = new StringBuilder(); + sb.append("CREATE TABLE IF NOT EXISTS ").append(info.getOriginTable()).append("(\n"); + EntityColumn primary = null; + T one = info.constructorAttributes == null ? info.getCreator().create() : null; + for (EntityColumn column : info.getDDLColumns()) { + if (column.primary) primary = column; + String sqltype = "VARCHAR(" + column.length + ")"; + String sqlnull = column.primary ? "NOT NULL" : "NULL"; + if (column.type == boolean.class || column.type == Boolean.class) { + sqltype = "BOOL"; + Boolean val = one == null ? null : (Boolean) info.getAttribute(column.field).get(one); + sqlnull = "NOT NULL DEFAULT " + (val != null && val ? 1 : 0); + } else if (column.type == byte.class || column.type == Byte.class) { + sqltype = "INT2"; + Number val = one == null ? null : (Number) info.getAttribute(column.field).get(one); + sqlnull = "NOT NULL DEFAULT " + (val == null ? 0 : val.byteValue()); + } else if (column.type == short.class || column.type == Short.class) { + sqltype = "INT2"; + Number val = one == null ? null : (Number) info.getAttribute(column.field).get(one); + sqlnull = "NOT NULL DEFAULT " + (val == null ? 0 : val); + } else if (column.type == char.class || column.type == Character.class) { + sqltype = "INT2 UNSIGNED"; + Number val = one == null ? null : (Number) info.getAttribute(column.field).get(one); + sqlnull = "NOT NULL DEFAULT " + (val == null ? 0 : val.intValue()); + } else if (column.type == int.class || column.type == Integer.class || column.type == AtomicInteger.class) { + sqltype = "INT4"; + Number val = one == null ? null : (Number) info.getAttribute(column.field).get(one); + sqlnull = "NOT NULL DEFAULT " + (val == null ? 0 : val); + } else if (column.type == long.class || column.type == Long.class || column.type == AtomicLong.class || column.type == LongAdder.class) { + sqltype = "INT8"; + Number val = one == null ? null : (Number) info.getAttribute(column.field).get(one); + sqlnull = "NOT NULL DEFAULT " + (val == null ? 0 : val); + } else if (column.type == float.class || column.type == Float.class) { + sqltype = "FLOAT4"; + if (column.precision > 0) sqltype += "(" + column.precision + "," + column.scale + ")"; + Number val = one == null ? null : (Number) info.getAttribute(column.field).get(one); + sqlnull = "NOT NULL DEFAULT " + (val == null ? 0 : val); + } else if (column.type == double.class || column.type == Double.class) { + sqltype = "FLOAT8"; + if (column.precision > 0) sqltype += "(" + column.precision + "," + column.scale + ")"; + Number val = one == null ? null : (Number) info.getAttribute(column.field).get(one); + sqlnull = "NOT NULL DEFAULT " + (val == null ? 0 : val); + } else if (column.type == BigInteger.class) { + sqltype = "NUMERIC"; + if (column.precision > 0) { + sqltype += "(" + column.precision + "," + column.scale + ")"; + } else { + sqltype += "(19,2)"; + } + Number val = one == null ? null : (Number) info.getAttribute(column.field).get(one); + sqlnull = "NOT NULL DEFAULT " + (val == null ? 0 : val); + } else if (column.type == BigDecimal.class) { + sqltype = "NUMERIC"; + if (column.precision > 0) sqltype += "(" + column.precision + "," + column.scale + ")"; + Number val = one == null ? null : (Number) info.getAttribute(column.field).get(one); + sqlnull = "NOT NULL DEFAULT " + (val == null ? 0 : val); + } else if (column.type == String.class) { + if (column.length < 65535) { + String val = one == null ? null : (String) info.getAttribute(column.field).get(one); + if (val != null) { + sqlnull = "NOT NULL DEFAULT '" + val.replace('\'', '"') + "'"; + } else if (column.primary) { + sqlnull = "NOT NULL DEFAULT ''"; + } + } else { + sqltype = "TEXT"; + if (!column.nullable) sqlnull = "NOT NULL"; + } + } else if (column.type == byte[].class) { + sqltype = "OID"; + if (!column.nullable) sqlnull = "NOT NULL"; + } else if (column.type == java.time.LocalDate.class || column.type == java.util.Date.class || "java.sql.Date".equals(column.type.getName())) { + sqltype = "DATE"; + } else if (column.type == java.time.LocalTime.class || "java.sql.Time".equals(column.type.getName())) { + sqltype = "TIME"; + } else if (column.type == java.time.LocalDateTime.class || "java.sql.Timestamp".equals(column.type.getName())) { + sqltype = "TIMESTAMP"; + } else { //JavaBean + sqltype = column.length >= 65535 ? "TEXT" : ("VARCHAR(" + column.length + ")"); + sqlnull = !column.nullable ? "NOT NULL DEFAULT ''" : "NULL"; + } + sb.append(" ").append(column.column).append(" ").append(sqltype).append(" ").append(sqlnull); + if (column.comment != null && !column.comment.isEmpty()) { + //postgresql涓嶆敮鎸丏DL涓甫comment + } + sb.append(",\n"); + } + sb.append(" PRIMARY KEY (").append(primary.column).append(")\n"); + sb.append(")"); + return sb.toString(); + } + return null; + } + + @Local + protected boolean isTableNotExist(EntityInfo info, String code) { + if (code == null || code.isEmpty()) return false; + return tablenotexistSqlstates.contains(';' + code + ';'); + } + + @Local + protected String getTableCopySQL(EntityInfo info, String newTable) { + return tablecopySQL.replace("${newtable}", newTable).replace("${oldtable}", info.table); + } + + @Override + public void init(AnyValue conf) { + this.cacheForbidden = "NONE".equalsIgnoreCase(readConfProps.getProperty(JDBC_CACHE_MODE)); + } + + @Override + public void destroy(AnyValue config) { + super.destroy(config); + } + + @Override + @Local + public void compile(Class clazz) { + EntityInfo.compile(clazz, this); + } + + @Local + public final String dbtype() { + if (dbtype == null) throw new NullPointerException("dbtype is null"); + return dbtype; + } + + @Local + public final boolean autoddl() { + return autoddl; + } + + @Local + public abstract int directExecute(String sql); + + @Local + public abstract int[] directExecute(String... sqls); + + @Local + public abstract V directQuery(String sql, Function handler); + + //鏄惁寮傛 + protected abstract boolean isAsync(); + + //index浠1寮濮 + protected abstract String prepareParamSign(int index); + + //鎻掑叆绾綍 + protected abstract CompletableFuture insertDB(final EntityInfo info, T... entitys); + + //鍒犻櫎璁板綍 + protected abstract CompletableFuture deleteDB(final EntityInfo info, Flipper flipper, final String sql); + + //娓呯┖琛 + protected abstract CompletableFuture clearTableDB(final EntityInfo info, final String table, final String sql); + + //鍒犻櫎琛 + protected abstract CompletableFuture dropTableDB(final EntityInfo info, final String table, final String sql); + + //鏇存柊绾綍 + protected abstract CompletableFuture updateEntityDB(final EntityInfo info, T... entitys); + + //鏇存柊绾綍 + protected abstract CompletableFuture updateColumnDB(final EntityInfo info, Flipper flipper, final String sql, final boolean prepared, Object... params); + + //鏌ヨNumber Map鏁版嵁 + protected abstract CompletableFuture> getNumberMapDB(final EntityInfo info, final String sql, final FilterFuncColumn... columns); + + //鏌ヨNumber鏁版嵁 + protected abstract CompletableFuture getNumberResultDB(final EntityInfo info, final String sql, final Number defVal, final String column); + + //鏌ヨMap鏁版嵁 + protected abstract CompletableFuture> queryColumnMapDB(final EntityInfo info, final String sql, final String keyColumn); + + //鏌ヨMap鏁版嵁 + protected abstract CompletableFuture> queryColumnMapDB(final EntityInfo info, final String sql, final ColumnNode[] funcNodes, final String[] groupByColumns); + + //鏌ヨ鍗曟潯璁板綍 + protected abstract CompletableFuture findDB(final EntityInfo info, final String sql, final boolean onlypk, final SelectColumn selects); + + //鏌ヨ鍗曟潯璁板綍鐨勫崟涓瓧娈 + protected abstract CompletableFuture findColumnDB(final EntityInfo info, final String sql, final boolean onlypk, final String column, final Serializable defValue); + + //鍒ゆ柇璁板綍鏄惁瀛樺湪 + protected abstract CompletableFuture existsDB(final EntityInfo info, final String sql, final boolean onlypk); + + //鏌ヨ涓椤垫暟鎹 + protected abstract CompletableFuture> querySheetDB(final EntityInfo info, final boolean readcache, final boolean needtotal, final boolean distinct, final SelectColumn selects, final Flipper flipper, final FilterNode node); + + protected CharSequence createSQLJoin(FilterNode node, final Function func, final boolean update, final Map joinTabalis, final Set haset, final EntityInfo info) { + return node == null ? null : node.createSQLJoin(func, update, joinTabalis, haset, info); + } + + protected CharSequence createSQLExpress(FilterNode node, final EntityInfo info, final Map joinTabalis) { + return node == null ? null : node.createSQLExpress(this, info, joinTabalis); + } + + @Local + @Override + public String getType() { + return "sql"; + } + + @Override + public final String resourceName() { + return name; + } + + @Local + @Override + public EntityInfo apply(Class t) { + return loadEntityInfo(t); + } + + @Local + @Override + public void close() throws Exception { + } + + protected EntityInfo loadEntityInfo(Class clazz) { + return loadEntityInfo(clazz, this.cacheForbidden, readConfProps, fullloader); + } + + public EntityCache loadCache(Class clazz) { + EntityInfo info = loadEntityInfo(clazz); + return info.getCache(); + } + + /** + * 灏唀ntity鐨勫璞″叏閮ㄥ姞杞藉埌Cache涓幓锛屽鏋渃lazz娌℃湁琚獲javax.persistence.Cacheable娉ㄨВ鍒欎笉鍋氫换浣曚簨 + * + * @param Entity绫绘硾鍨 + * @param clazz Entity绫 + */ + public void refreshCache(Class clazz) { + EntityInfo info = loadEntityInfo(clazz); + EntityCache cache = info.getCache(); + if (cache == null) return; + cache.fullLoadAsync(); + } + + protected CharSequence formatValueToString(final EntityInfo info, Object value) { + final String dbtype = dbtype(); + if ("mysql".equals(dbtype)) { + if (value == null) return null; + if (value instanceof CharSequence) { + return new StringBuilder().append('\'').append(value.toString().replace("\\", "\\\\").replace("'", "\\'")).append('\'').toString(); + } else if (!(value instanceof Number) && !(value instanceof java.util.Date) + && !value.getClass().getName().startsWith("java.sql.") && !value.getClass().getName().startsWith("java.time.")) { + return new StringBuilder().append('\'').append(info.getJsonConvert().convertTo(value).replace("\\", "\\\\").replace("'", "\\'")).append('\'').toString(); + } + return String.valueOf(value); + } else if (value != null && value instanceof CharSequence && "postgresql".equals(dbtype)) { + String s = String.valueOf(value); + int pos = s.indexOf('\''); + if (pos >= 0) return new StringBuilder().append("E'").append(value.toString().replace("\\", "\\\\").replace("'", "\\'")).append('\'').toString(); + } + return info.formatSQLValue(value, null); + } + + //----------------------------- insert ----------------------------- + /** + * 鏂板瀵硅薄锛 蹇呴』鏄疎ntity瀵硅薄 + * + * @param Entity绫绘硾鍨 + * @param entitys Entity瀵硅薄 + * + * @return 褰卞搷鐨勮褰曟潯鏁 + */ + @Override + public int insert(T... entitys) { + if (entitys.length == 0) return 0; + checkEntity("insert", false, entitys); + final EntityInfo info = loadEntityInfo((Class) entitys[0].getClass()); + if (isOnlyCache(info)) return insertCache(info, entitys); + return insertDB(info, entitys).whenComplete((rs, t) -> { + if (t != null) { + futureCompleteConsumer.accept(rs, t); + } else { + insertCache(info, entitys); + } + }).join(); + } + + @Override + public CompletableFuture insertAsync(T... entitys) { + if (entitys.length == 0) return CompletableFuture.completedFuture(0); + CompletableFuture future = checkEntity("insert", true, entitys); + if (future != null) return future; + final EntityInfo info = loadEntityInfo((Class) entitys[0].getClass()); + if (isOnlyCache(info)) { + return CompletableFuture.completedFuture(insertCache(info, entitys)); + } + if (isAsync()) return insertDB(info, entitys).whenComplete((rs, t) -> { + if (t != null) { + futureCompleteConsumer.accept(rs, t); + } else { + insertCache(info, entitys); + } + }); + return CompletableFuture.supplyAsync(() -> insertDB(info, entitys).join(), getExecutor()).whenComplete((rs, t) -> { + if (t != null) { + futureCompleteConsumer.accept(rs, t); + } else { + insertCache(info, entitys); + } + }); + } + + protected int insertCache(final EntityInfo info, T... entitys) { + final EntityCache cache = info.getCache(); + if (cache == null) return 0; + int c = 0; + for (final T value : entitys) { + c += cache.insert(value); + } + return c; + } + + //----------------------------- deleteCompose ----------------------------- + /** + * 鍒犻櫎瀵硅薄锛 蹇呴』鏄疎ntity瀵硅薄 + * + * @param Entity绫绘硾鍨 + * @param entitys Entity瀵硅薄 + * + * @return 鍒犻櫎鐨勬暟鎹潯鏁 + */ + @Override + public int delete(T... entitys) { + if (entitys.length == 0) return -1; + checkEntity("delete", false, entitys); + final Class clazz = (Class) entitys[0].getClass(); + final EntityInfo info = loadEntityInfo(clazz); + final Attribute primary = info.getPrimary(); + Serializable[] ids = new Serializable[entitys.length]; + int i = 0; + for (final T value : entitys) { + ids[i++] = (Serializable) primary.get(value); + } + return delete(clazz, ids); + } + + @Override + public CompletableFuture deleteAsync(final T... entitys) { + if (entitys.length == 0) return CompletableFuture.completedFuture(-1); + CompletableFuture future = checkEntity("delete", true, entitys); + if (future != null) return future; + final Class clazz = (Class) entitys[0].getClass(); + final EntityInfo info = loadEntityInfo(clazz); + final Attribute primary = info.getPrimary(); + Serializable[] ids = new Serializable[entitys.length]; + int i = 0; + for (final T value : entitys) { + ids[i++] = (Serializable) primary.get(value); + } + return deleteAsync(clazz, ids); + } + + @Override + public int delete(Class clazz, Serializable... pks) { + if (pks.length == 0) return -1; + final EntityInfo info = loadEntityInfo(clazz); + if (isOnlyCache(info)) return deleteCache(info, -1, pks); + return deleteCompose(info, pks).whenComplete((rs, t) -> { + if (t != null) { + futureCompleteConsumer.accept(rs, t); + } else { + deleteCache(info, rs, pks); + } + }).join(); + } + + @Override + public CompletableFuture deleteAsync(final Class clazz, final Serializable... pks) { + if (pks.length == 0) return CompletableFuture.completedFuture(-1); + final EntityInfo info = loadEntityInfo(clazz); + if (isOnlyCache(info)) { + return CompletableFuture.completedFuture(deleteCache(info, -1, pks)); + } + if (isAsync()) return deleteCompose(info, pks).whenComplete((rs, t) -> { + if (t != null) { + futureCompleteConsumer.accept(rs, t); + } else { + deleteCache(info, rs, pks); + } + }); + return CompletableFuture.supplyAsync(() -> deleteCompose(info, pks).join(), getExecutor()).whenComplete((rs, t) -> { + if (t != null) { + futureCompleteConsumer.accept(rs, t); + } else { + deleteCache(info, rs, pks); + } + }); + } + + @Override + public int delete(Class clazz, FilterNode node) { + return delete(clazz, (Flipper) null, node); + } + + @Override + public CompletableFuture deleteAsync(final Class clazz, final FilterNode node) { + return deleteAsync(clazz, (Flipper) null, node); + } + + @Override + public int delete(Class clazz, final Flipper flipper, FilterNode node) { + final EntityInfo info = loadEntityInfo(clazz); + if (isOnlyCache(info)) return deleteCache(info, -1, flipper, node); + return this.deleteCompose(info, flipper, node).whenComplete((rs, t) -> { + if (t != null) { + futureCompleteConsumer.accept(rs, t); + } else { + deleteCache(info, rs, flipper, node); + } + }).join(); + } + + @Override + public CompletableFuture deleteAsync(final Class clazz, final Flipper flipper, FilterNode node) { + final EntityInfo info = loadEntityInfo(clazz); + if (isOnlyCache(info)) { + return CompletableFuture.completedFuture(deleteCache(info, -1, flipper, node)); + } + if (isAsync()) return this.deleteCompose(info, flipper, node).whenComplete((rs, t) -> { + if (t != null) { + futureCompleteConsumer.accept(rs, t); + } else { + deleteCache(info, rs, flipper, node); + } + }); + return CompletableFuture.supplyAsync(() -> this.deleteCompose(info, flipper, node).join(), getExecutor()).whenComplete((rs, t) -> { + if (t != null) { + futureCompleteConsumer.accept(rs, t); + } else { + deleteCache(info, rs, flipper, node); + } + }); + } + + protected CompletableFuture deleteCompose(final EntityInfo info, final Serializable... pks) { + if (pks.length == 1) { + String sql = "DELETE FROM " + info.getTable(pks[0]) + " WHERE " + info.getPrimarySQLColumn() + "=" + info.formatSQLValue(info.getPrimarySQLColumn(), pks[0], sqlFormatter); + return deleteDB(info, null, sql); + } + String sql = "DELETE FROM " + info.getTable(pks[0]) + " WHERE " + info.getPrimarySQLColumn() + " IN ("; + for (int i = 0; i < pks.length; i++) { + if (i > 0) sql += ','; + sql += info.formatSQLValue(info.getPrimarySQLColumn(), pks[i], sqlFormatter); + } + sql += ")"; + if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " delete sql=" + sql); + return deleteDB(info, null, sql); + } + + protected CompletableFuture deleteCompose(final EntityInfo info, final Flipper flipper, final FilterNode node) { + Map joinTabalis = null; + CharSequence join = null; + CharSequence where = null; + if (node != null) { + joinTabalis = node.getJoinTabalis(); + join = node.createSQLJoin(this, true, joinTabalis, new HashSet<>(), info); + where = node.createSQLExpress(this, info, joinTabalis); + } + StringBuilder join1 = null; + StringBuilder join2 = null; + if (join != null) { + String joinstr = join.toString(); + join1 = multisplit('[', ']', ",", new StringBuilder(), joinstr, 0); + join2 = multisplit('{', '}', " AND ", new StringBuilder(), joinstr, 0); + } + String sql = "DELETE " + ("mysql".equals(dbtype()) ? "a" : "") + " FROM " + info.getTable(node) + " a" + (join1 == null ? "" : (", " + join1)) + + ((where == null || where.length() == 0) ? (join2 == null ? "" : (" WHERE " + join2)) + : (" WHERE " + where + (join2 == null ? "" : (" AND " + join2)))) + info.createSQLOrderby(flipper); + if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " delete sql=" + + (sql + ((flipper == null || flipper.getLimit() < 1) ? "" : (" LIMIT " + flipper.getLimit())))); + return deleteDB(info, flipper, sql); + } + + //----------------------------- clearTableCompose ----------------------------- + @Override + public int clearTable(Class clazz) { + return clearTable(clazz, (FilterNode) null); + } + + @Override + public int clearTable(Class clazz, FilterNode node) { + final EntityInfo info = loadEntityInfo(clazz); + if (isOnlyCache(info)) return clearTableCache(info, node); + return this.clearTableCompose(info, node).whenComplete((rs, t) -> { + if (t != null) { + futureCompleteConsumer.accept(rs, t); + } else { + clearTableCache(info, node); + } + }).join(); + } + + @Override + public CompletableFuture clearTableAsync(final Class clazz, FilterNode node) { + final EntityInfo info = loadEntityInfo(clazz); + if (isOnlyCache(info)) { + return CompletableFuture.completedFuture(clearTableCache(info, node)); + } + if (isAsync()) return this.clearTableCompose(info, node).whenComplete((rs, t) -> { + if (t != null) { + futureCompleteConsumer.accept(rs, t); + } else { + clearTableCache(info, node); + } + }); + return CompletableFuture.supplyAsync(() -> this.clearTableCompose(info, node).join(), getExecutor()).whenComplete((rs, t) -> { + if (t != null) { + futureCompleteConsumer.accept(rs, t); + } else { + clearTableCache(info, node); + } + }); + } + + protected CompletableFuture clearTableCompose(final EntityInfo info, final FilterNode node) { + final String table = info.getTable(node); + String sql = "TRUNCATE TABLE " + table; + if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " clearTable sql=" + sql); + return clearTableDB(info, table, sql); + } + + //----------------------------- dropTableCompose ----------------------------- + @Override + public int dropTable(Class clazz, FilterNode node) { + final EntityInfo info = loadEntityInfo(clazz); + if (isOnlyCache(info)) return dropTableCache(info, node); + return this.dropTableCompose(info, node).whenComplete((rs, t) -> { + if (t != null) { + futureCompleteConsumer.accept(rs, t); + } else { + dropTableCache(info, node); + } + }).join(); + } + + @Override + public CompletableFuture dropTableAsync(final Class clazz, FilterNode node) { + final EntityInfo info = loadEntityInfo(clazz); + if (isOnlyCache(info)) { + return CompletableFuture.completedFuture(dropTableCache(info, node)); + } + if (isAsync()) return this.dropTableCompose(info, node).whenComplete((rs, t) -> { + if (t != null) { + futureCompleteConsumer.accept(rs, t); + } else { + dropTableCache(info, node); + } + }); + return CompletableFuture.supplyAsync(() -> this.dropTableCompose(info, node).join(), getExecutor()).whenComplete((rs, t) -> { + if (t != null) { + futureCompleteConsumer.accept(rs, t); + } else { + dropTableCache(info, node); + } + }); + } + + protected CompletableFuture dropTableCompose(final EntityInfo info, final FilterNode node) { + final String table = info.getTable(node); + String sql = "DROP TABLE " + table; + if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " dropTable sql=" + sql); + return dropTableDB(info, table, sql); + } + + protected int clearTableCache(final EntityInfo info, FilterNode node) { + final EntityCache cache = info.getCache(); + if (cache == null) return -1; + return cache.clear(); + } + + protected int dropTableCache(final EntityInfo info, FilterNode node) { + final EntityCache cache = info.getCache(); + if (cache == null) return -1; + return cache.drop(); + } + + protected int deleteCache(final EntityInfo info, int count, Flipper flipper, FilterNode node) { + final EntityCache cache = info.getCache(); + if (cache == null) return -1; + Serializable[] ids = cache.delete(flipper, node); + return count >= 0 ? count : (ids == null ? 0 : ids.length); + } + + protected int deleteCache(final EntityInfo info, int count, Serializable... pks) { + final EntityCache cache = info.getCache(); + if (cache == null) return -1; + int c = 0; + for (Serializable key : pks) { + c += cache.delete(key); + } + return count >= 0 ? count : c; + } + + protected static StringBuilder multisplit(char ch1, char ch2, String split, StringBuilder sb, String str, int from) { + if (str == null) return sb; + int pos1 = str.indexOf(ch1, from); + if (pos1 < 0) return sb; + int pos2 = str.indexOf(ch2, from); + if (pos2 < 0) return sb; + if (sb.length() > 0) sb.append(split); + sb.append(str.substring(pos1 + 1, pos2)); + return multisplit(ch1, ch2, split, sb, str, pos2 + 1); + } + + //---------------------------- update ---------------------------- + /** + * 鏇存柊瀵硅薄锛 蹇呴』鏄疎ntity瀵硅薄 + * + * @param Entity绫绘硾鍨 + * @param entitys Entity瀵硅薄 + * + * @return 鏇存柊鐨勬暟鎹潯鏁 + */ + @Override + public int update(T... entitys) { + if (entitys.length == 0) return -1; + checkEntity("update", false, entitys); + final Class clazz = (Class) entitys[0].getClass(); + final EntityInfo info = loadEntityInfo(clazz); + if (isOnlyCache(info)) return updateCache(info, -1, entitys); + return updateEntityDB(info, entitys).whenComplete((rs, t) -> { + if (t != null) { + futureCompleteConsumer.accept(rs, t); + } else { + updateCache(info, rs, entitys); + } + }).join(); + } + + @Override + public CompletableFuture updateAsync(final T... entitys) { + if (entitys.length == 0) return CompletableFuture.completedFuture(-1); + CompletableFuture future = checkEntity("update", true, entitys); + if (future != null) return future; + final Class clazz = (Class) entitys[0].getClass(); + final EntityInfo info = loadEntityInfo(clazz); + if (isOnlyCache(info)) { + return CompletableFuture.completedFuture(updateCache(info, -1, entitys)); + } + if (isAsync()) return updateEntityDB(info, entitys).whenComplete((rs, t) -> { + if (t != null) { + futureCompleteConsumer.accept(rs, t); + } else { + updateCache(info, rs, entitys); + } + }); + return CompletableFuture.supplyAsync(() -> updateEntityDB(info, entitys).join(), getExecutor()).whenComplete((rs, t) -> { + if (t != null) { + futureCompleteConsumer.accept(rs, t); + } else { + updateCache(info, rs, entitys); + } + }); + } + + /** + * 鏍规嵁涓婚敭鍊兼洿鏂板璞$殑column瀵瑰簲鐨勫硷紝 蹇呴』鏄疎ntity Class + * + * @param Entity绫荤殑娉涘瀷 + * @param clazz Entity绫 + * @param pk 涓婚敭鍊 + * @param column 杩囨护瀛楁鍚 + * @param colval 杩囨护瀛楁鍊 + * + * @return 鏇存柊鐨勬暟鎹潯鏁 + */ + @Override + public int updateColumn(Class clazz, Serializable pk, String column, Serializable colval) { + final EntityInfo info = loadEntityInfo(clazz); + if (isOnlyCache(info)) return updateCache(info, -1, pk, column, colval); + return updateColumnCompose(info, pk, column, colval).whenComplete((rs, t) -> { + if (t != null) { + futureCompleteConsumer.accept(rs, t); + } else { + updateCache(info, rs, pk, column, colval); + } + }).join(); + } + + @Override + public CompletableFuture updateColumnAsync(final Class clazz, final Serializable pk, final String column, final Serializable colval) { + final EntityInfo info = loadEntityInfo(clazz); + if (isOnlyCache(info)) { + return CompletableFuture.completedFuture(updateCache(info, -1, pk, column, colval)); + } + if (isAsync()) return updateColumnCompose(info, pk, column, colval).whenComplete((rs, t) -> { + if (t != null) { + futureCompleteConsumer.accept(rs, t); + } else { + updateCache(info, rs, pk, column, colval); + } + }); + return CompletableFuture.supplyAsync(() -> updateColumnCompose(info, pk, column, colval).join(), getExecutor()).whenComplete((rs, t) -> { + if (t != null) { + futureCompleteConsumer.accept(rs, t); + } else { + updateCache(info, rs, pk, column, colval); + } + }); + } + + protected CompletableFuture updateColumnCompose(final EntityInfo info, Serializable pk, String column, final Serializable colval) { + if (colval instanceof byte[]) { + String sql = "UPDATE " + info.getTable(pk) + " SET " + info.getSQLColumn(null, column) + "=" + prepareParamSign(1) + " WHERE " + info.getPrimarySQLColumn() + "=" + info.formatSQLValue(info.getPrimarySQLColumn(), pk, sqlFormatter); + return updateColumnDB(info, null, sql, true, colval); + } else { + String sql = "UPDATE " + info.getTable(pk) + " SET " + info.getSQLColumn(null, column) + "=" + + info.formatSQLValue(column, colval, sqlFormatter) + " WHERE " + info.getPrimarySQLColumn() + "=" + info.formatSQLValue(info.getPrimarySQLColumn(), pk, sqlFormatter); + return updateColumnDB(info, null, sql, false); + } + } + + /** + * 鏍规嵁涓婚敭鍊兼洿鏂板璞$殑column瀵瑰簲鐨勫硷紝 蹇呴』鏄疎ntity Class + * + * @param Entity绫荤殑娉涘瀷 + * @param clazz Entity绫 + * @param column 杩囨护瀛楁鍚 + * @param colval 杩囨护瀛楁鍊 + * @param node 杩囨护node 涓嶈兘涓簄ull + * + * @return 鏇存柊鐨勬暟鎹潯鏁 + */ + @Override + public int updateColumn(Class clazz, String column, Serializable colval, FilterNode node) { + final EntityInfo info = loadEntityInfo(clazz); + if (isOnlyCache(info)) return updateCache(info, -1, column, colval, node); + return this.updateColumnCompose(info, column, colval, node).whenComplete((rs, t) -> { + if (t != null) { + futureCompleteConsumer.accept(rs, t); + } else { + updateCache(info, rs, column, colval, node); + } + }).join(); + } + + @Override + public CompletableFuture updateColumnAsync(final Class clazz, final String column, final Serializable colval, final FilterNode node) { + final EntityInfo info = loadEntityInfo(clazz); + if (isOnlyCache(info)) { + return CompletableFuture.completedFuture(updateCache(info, -1, column, colval, node)); + } + if (isAsync()) return this.updateColumnCompose(info, column, colval, node).whenComplete((rs, t) -> { + if (t != null) { + futureCompleteConsumer.accept(rs, t); + } else { + updateCache(info, rs, column, colval, node); + } + }); + return CompletableFuture.supplyAsync(() -> this.updateColumnCompose(info, column, colval, node).join(), getExecutor()).whenComplete((rs, t) -> { + if (t != null) { + futureCompleteConsumer.accept(rs, t); + } else { + updateCache(info, rs, column, colval, node); + } + }); + } + + protected CompletableFuture updateColumnCompose(final EntityInfo info, final String column, final Serializable colval, final FilterNode node) { + Map joinTabalis = node.getJoinTabalis(); + CharSequence join = node.createSQLJoin(this, true, joinTabalis, new HashSet<>(), info); + CharSequence where = node.createSQLExpress(this, info, joinTabalis); + + StringBuilder join1 = null; + StringBuilder join2 = null; + if (join != null) { + String joinstr = join.toString(); + join1 = multisplit('[', ']', ",", new StringBuilder(), joinstr, 0); + join2 = multisplit('{', '}', " AND ", new StringBuilder(), joinstr, 0); + } + String alias = "postgresql".equals(dbtype()) ? null : "a"; //postgresql鐨凚UG锛 UPDATE鐨凷ET涓笉鑳藉惈鍒悕 + if (colval instanceof byte[]) { + String sql = "UPDATE " + info.getTable(node) + " a " + (join1 == null ? "" : (", " + join1)) + + " SET " + info.getSQLColumn(alias, column) + "=" + prepareParamSign(1) + + ((where == null || where.length() == 0) ? (join2 == null ? "" : (" WHERE " + join2)) + : (" WHERE " + where + (join2 == null ? "" : (" AND " + join2)))); + return updateColumnDB(info, null, sql, true, colval); + } else { + String sql = "UPDATE " + info.getTable(node) + " a " + (join1 == null ? "" : (", " + join1)) + + " SET " + info.getSQLColumn(alias, column) + "=" + info.formatSQLValue(colval, sqlFormatter) + + ((where == null || where.length() == 0) ? (join2 == null ? "" : (" WHERE " + join2)) + : (" WHERE " + where + (join2 == null ? "" : (" AND " + join2)))); + return updateColumnDB(info, null, sql, false); + } + } + + /** + * 鏍规嵁涓婚敭鍊兼洿鏂板璞$殑澶氫釜column瀵瑰簲鐨勫硷紝 蹇呴』鏄疎ntity Class + * + * @param Entity绫荤殑娉涘瀷 + * @param clazz Entity绫 + * @param pk 涓婚敭鍊 + * @param values 瀛楁鍊 + * + * @return 鏇存柊鐨勬暟鎹潯鏁 + */ + @Override + public int updateColumn(final Class clazz, final Serializable pk, final ColumnValue... values) { + if (values == null || values.length < 1) return -1; + final EntityInfo info = loadEntityInfo(clazz); + if (isOnlyCache(info)) return updateCache(info, -1, pk, values); + return this.updateColumnCompose(info, pk, values).whenComplete((rs, t) -> { + if (t != null) { + futureCompleteConsumer.accept(rs, t); + } else { + updateCache(info, rs, pk, values); + } + }).join(); + } + + @Override + public CompletableFuture updateColumnAsync(final Class clazz, final Serializable pk, final ColumnValue... values) { + if (values == null || values.length < 1) return CompletableFuture.completedFuture(-1); + final EntityInfo info = loadEntityInfo(clazz); + if (isOnlyCache(info)) { + return CompletableFuture.completedFuture(updateCache(info, -1, pk, values)); + } + if (isAsync()) return this.updateColumnCompose(info, pk, values).whenComplete((rs, t) -> { + if (t != null) { + futureCompleteConsumer.accept(rs, t); + } else { + updateCache(info, rs, pk, values); + } + }); + return CompletableFuture.supplyAsync(() -> this.updateColumnCompose(info, pk, values).join(), getExecutor()).whenComplete((rs, t) -> { + if (t != null) { + futureCompleteConsumer.accept(rs, t); + } else { + updateCache(info, rs, pk, values); + } + }); + } + + protected CompletableFuture updateColumnCompose(final EntityInfo info, final Serializable pk, final ColumnValue... values) { + StringBuilder setsql = new StringBuilder(); + List blobs = null; + int index = 0; + for (ColumnValue col : values) { + if (col == null) continue; + Attribute attr = info.getUpdateAttribute(col.getColumn()); + if (attr == null) throw new RuntimeException(info.getType() + " cannot found column " + col.getColumn()); + if (setsql.length() > 0) setsql.append(", "); + String sqlColumn = info.getSQLColumn(null, col.getColumn()); + if (col.getValue() instanceof byte[]) { + if (blobs == null) blobs = new ArrayList<>(); + blobs.add((byte[]) col.getValue()); + setsql.append(sqlColumn).append("=").append(prepareParamSign(++index)); + } else { + setsql.append(sqlColumn).append("=").append(info.formatSQLValue(sqlColumn, attr, col, sqlFormatter)); + } + } + if (setsql.length() < 1) return CompletableFuture.completedFuture(0); + String sql = "UPDATE " + info.getTable(pk) + " SET " + setsql + " WHERE " + info.getPrimarySQLColumn() + "=" + info.formatSQLValue(info.getPrimarySQLColumn(), pk, sqlFormatter); + if (blobs == null) return updateColumnDB(info, null, sql, false); + return updateColumnDB(info, null, sql, true, blobs.toArray()); + } + + @Override + public int updateColumn(final Class clazz, final FilterNode node, final Flipper flipper, final ColumnValue... values) { + if (values == null || values.length < 1) return -1; + final EntityInfo info = loadEntityInfo(clazz); + if (isOnlyCache(info)) return updateCache(info, -1, node, flipper, values); + return this.updateColumnCompose(info, node, flipper, values).whenComplete((rs, t) -> { + if (t != null) { + futureCompleteConsumer.accept(rs, t); + } else { + updateCache(info, rs, node, flipper, values); + } + }).join(); + } + + @Override + public CompletableFuture updateColumnAsync(final Class clazz, final FilterNode node, final Flipper flipper, final ColumnValue... values) { + if (values == null || values.length < 1) return CompletableFuture.completedFuture(-1); + final EntityInfo info = loadEntityInfo(clazz); + if (isOnlyCache(info)) { + return CompletableFuture.completedFuture(updateCache(info, -1, node, flipper, values)); + } + if (isAsync()) return this.updateColumnCompose(info, node, flipper, values).whenComplete((rs, t) -> { + if (t != null) { + futureCompleteConsumer.accept(rs, t); + } else { + updateCache(info, rs, node, flipper, values); + } + }); + return CompletableFuture.supplyAsync(() -> this.updateColumnCompose(info, node, flipper, values).join(), getExecutor()).whenComplete((rs, t) -> { + if (t != null) { + futureCompleteConsumer.accept(rs, t); + } else { + updateCache(info, rs, node, flipper, values); + } + }); + } + + protected CompletableFuture updateColumnCompose(final EntityInfo info, final FilterNode node, final Flipper flipper, final ColumnValue... values) { + StringBuilder setsql = new StringBuilder(); + List blobs = null; + int index = 0; + String alias = "postgresql".equals(dbtype()) ? null : "a"; //postgresql鐨凚UG锛 UPDATE鐨凷ET涓笉鑳藉惈鍒悕 + for (ColumnValue col : values) { + if (col == null) continue; + Attribute attr = info.getUpdateAttribute(col.getColumn()); + if (attr == null) continue; + if (setsql.length() > 0) setsql.append(", "); + String sqlColumn = info.getSQLColumn(alias, col.getColumn()); + if (col.getValue() instanceof byte[]) { + if (blobs == null) blobs = new ArrayList<>(); + blobs.add((byte[]) col.getValue()); + setsql.append(sqlColumn).append("=").append(prepareParamSign(++index)); + } else { + setsql.append(sqlColumn).append("=").append(info.formatSQLValue(sqlColumn, attr, col, sqlFormatter)); + } + } + if (setsql.length() < 1) return CompletableFuture.completedFuture(0); + Map joinTabalis = node == null ? null : node.getJoinTabalis(); + CharSequence join = node == null ? null : node.createSQLJoin(this, true, joinTabalis, new HashSet<>(), info); + CharSequence where = node == null ? null : node.createSQLExpress(this, info, joinTabalis); + StringBuilder join1 = null; + StringBuilder join2 = null; + if (join != null) { + String joinstr = join.toString(); + join1 = multisplit('[', ']', ",", new StringBuilder(), joinstr, 0); + join2 = multisplit('{', '}', " AND ", new StringBuilder(), joinstr, 0); + } + String sql = "UPDATE " + info.getTable(node) + " a " + (join1 == null ? "" : (", " + join1)) + " SET " + setsql + + ((where == null || where.length() == 0) ? (join2 == null ? "" : (" WHERE " + join2)) + : (" WHERE " + where + (join2 == null ? "" : (" AND " + join2)))) + + info.createSQLOrderby(flipper); + if (blobs == null) return updateColumnDB(info, null, sql, false); + return updateColumnDB(info, flipper, sql, true, blobs.toArray()); + } + + @Override + public int updateColumn(final T entity, final SelectColumn selects) { + if (entity == null || selects == null) return -1; + Class clazz = (Class) entity.getClass(); + final EntityInfo info = loadEntityInfo(clazz); + if (isOnlyCache(info)) return updateCache(info, -1, false, entity, null, selects); + return this.updateColumnCompose(info, false, entity, null, selects).whenComplete((rs, t) -> { + if (t != null) { + futureCompleteConsumer.accept(rs, t); + } else { + updateCache(info, rs, false, entity, null, selects); + } + }).join(); + } + + @Override + public CompletableFuture updateColumnAsync(final T entity, final SelectColumn selects) { + if (entity == null || selects == null) return CompletableFuture.completedFuture(-1); + Class clazz = (Class) entity.getClass(); + final EntityInfo info = loadEntityInfo(clazz); + if (isOnlyCache(info)) { + return CompletableFuture.completedFuture(updateCache(info, -1, false, entity, null, selects)); + } + if (isAsync()) return this.updateColumnCompose(info, false, entity, null, selects).whenComplete((rs, t) -> { + if (t != null) { + futureCompleteConsumer.accept(rs, t); + } else { + updateCache(info, rs, false, entity, null, selects); + } + }); + return CompletableFuture.supplyAsync(() -> this.updateColumnCompose(info, false, entity, null, selects).join(), getExecutor()).whenComplete((rs, t) -> { + if (t != null) { + futureCompleteConsumer.accept(rs, t); + } else { + updateCache(info, rs, false, entity, null, selects); + } + }); + } + + @Override + public int updateColumn(final T entity, final FilterNode node, final SelectColumn selects) { + if (entity == null || node == null || selects == null) return -1; + Class clazz = (Class) entity.getClass(); + final EntityInfo info = loadEntityInfo(clazz); + if (isOnlyCache(info)) return updateCache(info, -1, true, entity, node, selects); + return this.updateColumnCompose(info, true, entity, node, selects).whenComplete((rs, t) -> { + if (t != null) { + futureCompleteConsumer.accept(rs, t); + } else { + updateCache(info, rs, true, entity, node, selects); + } + }).join(); + } + + @Override + public CompletableFuture updateColumnAsync(final T entity, final FilterNode node, final SelectColumn selects) { + if (entity == null || node == null || selects == null) return CompletableFuture.completedFuture(-1); + Class clazz = (Class) entity.getClass(); + final EntityInfo info = loadEntityInfo(clazz); + if (isOnlyCache(info)) { + return CompletableFuture.completedFuture(updateCache(info, -1, true, entity, node, selects)); + } + if (isAsync()) return this.updateColumnCompose(info, true, entity, node, selects).whenComplete((rs, t) -> { + if (t != null) { + futureCompleteConsumer.accept(rs, t); + } else { + updateCache(info, rs, true, entity, node, selects); + } + }); + return CompletableFuture.supplyAsync(() -> this.updateColumnCompose(info, true, entity, node, selects).join(), getExecutor()).whenComplete((rs, t) -> { + if (t != null) { + futureCompleteConsumer.accept(rs, t); + } else { + updateCache(info, rs, true, entity, node, selects); + } + }); + } + + protected CompletableFuture updateColumnCompose(final EntityInfo info, final boolean neednode, final T entity, final FilterNode node, final SelectColumn selects) { + StringBuilder setsql = new StringBuilder(); + List blobs = null; + int index = 0; + String alias = "postgresql".equals(dbtype()) ? null : "a"; //postgresql鐨凚UG锛 UPDATE鐨凷ET涓笉鑳藉惈鍒悕 + for (Attribute attr : info.updateAttributes) { + if (!selects.test(attr.field())) continue; + if (setsql.length() > 0) setsql.append(", "); + setsql.append(info.getSQLColumn(alias, attr.field())); + Serializable val = info.getFieldValue(attr, entity); + if (val instanceof byte[]) { + if (blobs == null) blobs = new ArrayList<>(); + blobs.add((byte[]) val); + setsql.append("=").append(prepareParamSign(++index)); + } else { + CharSequence sqlval = info.formatSQLValue(val, sqlFormatter); + if (sqlval == null && info.isNotNullJson(attr)) sqlval = "''"; + setsql.append("=").append(sqlval); + } + } + if (neednode) { + Map joinTabalis = node.getJoinTabalis(); + CharSequence join = node.createSQLJoin(this, true, joinTabalis, new HashSet<>(), info); + CharSequence where = node.createSQLExpress(this, info, joinTabalis); + StringBuilder join1 = null; + StringBuilder join2 = null; + if (join != null) { + String joinstr = join.toString(); + join1 = multisplit('[', ']', ",", new StringBuilder(), joinstr, 0); + join2 = multisplit('{', '}', " AND ", new StringBuilder(), joinstr, 0); + } + String sql = "UPDATE " + info.getTable(node) + " a " + (join1 == null ? "" : (", " + join1)) + " SET " + setsql + + ((where == null || where.length() == 0) ? (join2 == null ? "" : (" WHERE " + join2)) + : (" WHERE " + where + (join2 == null ? "" : (" AND " + join2)))); + if (blobs == null) return updateColumnDB(info, null, sql, false); + return updateColumnDB(info, null, sql, true, blobs.toArray()); + } else { + final Serializable id = (Serializable) info.getSQLValue(info.getPrimary(), entity); + String sql = "UPDATE " + info.getTable(id) + " a SET " + setsql + " WHERE " + info.getPrimarySQLColumn() + "=" + info.formatSQLValue(id, sqlFormatter); + if (blobs == null) return updateColumnDB(info, null, sql, false); + return updateColumnDB(info, null, sql, true, blobs.toArray()); + } + } + + protected int updateCache(final EntityInfo info, int count, final boolean neednode, final T entity, final FilterNode node, final SelectColumn selects) { + final EntityCache cache = info.getCache(); + if (cache == null) return count; + final List> attrs = new ArrayList<>(); + for (Attribute attr : info.updateAttributes) { + if (!selects.test(attr.field())) continue; + attrs.add(attr); + } + if (neednode) { + T[] rs = cache.update(entity, attrs, node); + return count >= 0 ? count : (rs == null ? 0 : rs.length); + } else { + T rs = cache.update(entity, attrs); + return count >= 0 ? count : (rs == null ? 0 : 1); + } + } + + protected int updateCache(final EntityInfo info, int count, final FilterNode node, final Flipper flipper, final ColumnValue... values) { + final EntityCache cache = info.getCache(); + if (cache == null) return count; + final List> attrs = new ArrayList<>(); + final List cols = new ArrayList<>(); + for (ColumnValue col : values) { + if (col == null) continue; + Attribute attr = info.getUpdateAttribute(col.getColumn()); + if (attr == null) continue; + attrs.add(attr); + cols.add(col); + } + T[] rs = cache.updateColumn(node, flipper, attrs, cols); + return count >= 0 ? count : (rs == null ? 0 : 1); + } + + protected int updateCache(final EntityInfo info, int count, final Serializable pk, final ColumnValue... values) { + final EntityCache cache = info.getCache(); + if (cache == null) return count; + final List> attrs = new ArrayList<>(); + final List cols = new ArrayList<>(); + for (ColumnValue col : values) { + if (col == null) continue; + Attribute attr = info.getUpdateAttribute(col.getColumn()); + if (attr == null) continue; + attrs.add(attr); + cols.add(col); + } + T rs = cache.updateColumn(pk, attrs, cols); + return count >= 0 ? count : (rs == null ? 0 : 1); + } + + protected int updateCache(final EntityInfo info, int count, String column, final Serializable colval, FilterNode node) { + final EntityCache cache = info.getCache(); + if (cache == null) return count; + T[] rs = cache.update(info.getAttribute(column), colval, node); + return count >= 0 ? count : (rs == null ? 0 : 1); + } + + protected int updateCache(final EntityInfo info, int count, final Serializable pk, final String column, final Serializable colval) { + final EntityCache cache = info.getCache(); + if (cache == null) return count; + T rs = cache.update(pk, info.getAttribute(column), colval); + return count >= 0 ? count : (rs == null ? 0 : 1); + } + + protected int updateCache(final EntityInfo info, int count, T... entitys) { + final EntityCache cache = info.getCache(); + if (cache == null) return -1; + int c2 = 0; + for (final T value : entitys) { + c2 += cache.update(value); + } + return count >= 0 ? count : c2; + } + + public int reloadCache(Class clazz, Serializable... pks) { + final EntityInfo info = loadEntityInfo(clazz); + final EntityCache cache = info.getCache(); + if (cache == null) return -1; + String column = info.getPrimary().field(); + int c = 0; + for (Serializable id : pks) { + Sheet sheet = querySheetCompose(false, true, false, clazz, null, FLIPPER_ONE, FilterNode.create(column, id)).join(); + T value = sheet.isEmpty() ? null : sheet.list().get(0); + if (value != null) c += cache.update(value); + } + return c; + } + + //------------------------- getNumberMapCompose ------------------------- + @Override + public Map getNumberMap(final Class entityClass, final FilterNode node, final FilterFuncColumn... columns) { + final EntityInfo info = loadEntityInfo(entityClass); + final EntityCache cache = info.getCache(); + if (cache != null && (isOnlyCache(info) || cache.isFullLoaded())) { + final Map map = new HashMap<>(); + if (node == null || isCacheUseable(node, this)) { + for (FilterFuncColumn ffc : columns) { + for (String col : ffc.cols()) { + map.put(ffc.col(col), cache.getNumberResult(ffc.func, ffc.defvalue, col, node)); + } + } + return map; + } + } + return (Map) getNumberMapCompose(info, node, columns).join(); + } + + @Override + public CompletableFuture> getNumberMapAsync(final Class entityClass, final FilterNode node, final FilterFuncColumn... columns) { + final EntityInfo info = loadEntityInfo(entityClass); + final EntityCache cache = info.getCache(); + if (cache != null && (isOnlyCache(info) || cache.isFullLoaded())) { + final Map map = new HashMap<>(); + if (node == null || isCacheUseable(node, this)) { + for (FilterFuncColumn ffc : columns) { + for (String col : ffc.cols()) { + map.put(ffc.col(col), cache.getNumberResult(ffc.getFunc(), ffc.getDefvalue(), col, node)); + } + } + return CompletableFuture.completedFuture(map); + } + } + if (isAsync()) return getNumberMapCompose(info, node, columns); + return CompletableFuture.supplyAsync(() -> (Map) getNumberMapCompose(info, node, columns).join(), getExecutor()); + } + + protected CompletableFuture> getNumberMapCompose(final EntityInfo info, final FilterNode node, final FilterFuncColumn... columns) { + final Map joinTabalis = node == null ? null : node.getJoinTabalis(); + final Set haset = new HashSet<>(); + final CharSequence join = node == null ? null : node.createSQLJoin(this, false, joinTabalis, haset, info); + final CharSequence where = node == null ? null : node.createSQLExpress(this, info, joinTabalis); + StringBuilder sb = new StringBuilder(); + for (FilterFuncColumn ffc : columns) { + for (String col : ffc.cols()) { + if (sb.length() > 0) sb.append(", "); + sb.append(ffc.func.getColumn((col == null || col.isEmpty() ? "*" : info.getSQLColumn("a", col)))); + } + } + final String sql = "SELECT " + sb + " FROM " + info.getTable(node) + " a" + + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where)); + if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " getnumbermap sql=" + sql); + return getNumberMapDB(info, sql, columns); + } + + @Local + protected CompletableFuture> getNumberMapDBApply(EntityInfo info, CompletableFuture future, FilterFuncColumn... columns) { + return future.thenApply((DataResultSet dataset) -> { + final Map map = new HashMap<>(); + if (dataset.next()) { + int index = 0; + for (FilterFuncColumn ffc : columns) { + for (String col : ffc.cols()) { + Object o = dataset.getObject(++index); + Number rs = ffc.getDefvalue(); + if (o != null) rs = (Number) o; + map.put(ffc.col(col), rs); + } + } + } + dataset.close(); + return map; + }); + } + + //------------------------ getNumberResultCompose ----------------------- + @Override + public Number getNumberResult(final Class entityClass, final FilterFunc func, final Number defVal, final String column, final FilterNode node) { + final EntityInfo info = loadEntityInfo(entityClass); + final EntityCache cache = info.getCache(); + if (cache != null && (isOnlyCache(info) || cache.isFullLoaded())) { + if (node == null || isCacheUseable(node, this)) { + return cache.getNumberResult(func, defVal, column, node); + } + } + return getNumberResultCompose(info, entityClass, func, defVal, column, node).join(); + } + + @Override + public CompletableFuture getNumberResultAsync(final Class entityClass, final FilterFunc func, final Number defVal, final String column, final FilterNode node) { + final EntityInfo info = loadEntityInfo(entityClass); + final EntityCache cache = info.getCache(); + if (cache != null && (isOnlyCache(info) || cache.isFullLoaded())) { + if (node == null || isCacheUseable(node, this)) { + return CompletableFuture.completedFuture(cache.getNumberResult(func, defVal, column, node)); + } + } + if (isAsync()) return getNumberResultCompose(info, entityClass, func, defVal, column, node); + return CompletableFuture.supplyAsync(() -> getNumberResultCompose(info, entityClass, func, defVal, column, node).join(), getExecutor()); + } + + protected CompletableFuture getNumberResultCompose(final EntityInfo info, final Class entityClass, final FilterFunc func, final Number defVal, final String column, final FilterNode node) { + final Map joinTabalis = node == null ? null : node.getJoinTabalis(); + final Set haset = new HashSet<>(); + final CharSequence join = node == null ? null : node.createSQLJoin(this, false, joinTabalis, haset, info); + final CharSequence where = node == null ? null : node.createSQLExpress(this, info, joinTabalis); + final String sql = "SELECT " + func.getColumn((column == null || column.isEmpty() ? "*" : info.getSQLColumn("a", column))) + " FROM " + info.getTable(node) + " a" + + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where)); + if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(entityClass.getSimpleName() + " getnumberresult sql=" + sql); + return getNumberResultDB(info, sql, defVal, column); + } + + @Local + protected CompletableFuture getNumberResultDBApply(EntityInfo info, CompletableFuture future, Number defVal, String column) { + return future.thenApply((DataResultSet dataset) -> { + Number rs = defVal; + if (dataset.next()) { + Object o = dataset.getObject(1); + if (o != null) rs = (Number) o; + } + dataset.close(); + return rs; + }); + } + + //------------------------ queryColumnMapCompose ------------------------ + @Override + public Map queryColumnMap(final Class entityClass, final String keyColumn, final FilterFunc func, final String funcColumn, FilterNode node) { + final EntityInfo info = loadEntityInfo(entityClass); + final EntityCache cache = info.getCache(); + if (cache != null && (isOnlyCache(info) || cache.isFullLoaded())) { + if (node == null || isCacheUseable(node, this)) { + return cache.queryColumnMap(keyColumn, func, funcColumn, node); + } + } + return (Map) queryColumnMapCompose(info, keyColumn, func, funcColumn, node).join(); + } + + @Override + public CompletableFuture> queryColumnMapAsync(final Class entityClass, final String keyColumn, final FilterFunc func, final String funcColumn, FilterNode node) { + final EntityInfo info = loadEntityInfo(entityClass); + final EntityCache cache = info.getCache(); + if (cache != null && (isOnlyCache(info) || cache.isFullLoaded())) { + if (node == null || isCacheUseable(node, this)) { + return CompletableFuture.completedFuture(cache.queryColumnMap(keyColumn, func, funcColumn, node)); + } + } + if (isAsync()) return queryColumnMapCompose(info, keyColumn, func, funcColumn, node); + return CompletableFuture.supplyAsync(() -> (Map) queryColumnMapCompose(info, keyColumn, func, funcColumn, node).join(), getExecutor()); + } + + protected CompletableFuture> queryColumnMapCompose(final EntityInfo info, final String keyColumn, final FilterFunc func, final String funcColumn, FilterNode node) { + final String keySqlColumn = info.getSQLColumn(null, keyColumn); + final Map joinTabalis = node == null ? null : node.getJoinTabalis(); + final Set haset = new HashSet<>(); + final CharSequence join = node == null ? null : node.createSQLJoin(this, false, joinTabalis, haset, info); + final CharSequence where = node == null ? null : node.createSQLExpress(this, info, joinTabalis); + final String funcSqlColumn = func == null ? info.getSQLColumn("a", funcColumn) : func.getColumn((funcColumn == null || funcColumn.isEmpty() ? "*" : info.getSQLColumn("a", funcColumn))); + final String sql = "SELECT a." + keySqlColumn + ", " + funcSqlColumn + + " FROM " + info.getTable(node) + " a" + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where)) + " GROUP BY a." + keySqlColumn; + if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " querycolumnmap sql=" + sql); + return queryColumnMapDB(info, sql, keyColumn); + } + + @Local + protected CompletableFuture> queryColumnMapDBApply(EntityInfo info, CompletableFuture future, final String keyColumn) { + return future.thenApply((DataResultSet dataset) -> { + Map rs = new LinkedHashMap<>(); + while (dataset.next()) { + rs.put((K) dataset.getObject(1), (N) dataset.getObject(2)); + } + dataset.close(); + return rs; + }); + } + + @Override + public Map queryColumnMap(final Class entityClass, final ColumnNode[] funcNodes, final String groupByColumn, final FilterNode node) { + Map map = queryColumnMap(entityClass, funcNodes, Utility.ofArray(groupByColumn), node); + final Map rs = new LinkedHashMap<>(); + map.forEach((keys, values) -> rs.put(keys[0], values)); + return rs; + } + + @Override + public CompletableFuture> queryColumnMapAsync(final Class entityClass, final ColumnNode[] funcNodes, final String groupByColumn, final FilterNode node) { + CompletableFuture> future = queryColumnMapAsync(entityClass, funcNodes, Utility.ofArray(groupByColumn), node); + return future.thenApply(map -> { + final Map rs = new LinkedHashMap<>(); + map.forEach((keys, values) -> rs.put(keys[0], values)); + return rs; + }); + } + + @Override + public Map queryColumnMap(final Class entityClass, final ColumnNode[] funcNodes, final String[] groupByColumns, final FilterNode node) { + final EntityInfo info = loadEntityInfo(entityClass); + final EntityCache cache = info.getCache(); + if (cache != null && (isOnlyCache(info) || cache.isFullLoaded())) { + if (node == null || isCacheUseable(node, this)) { + return cache.queryColumnMap(funcNodes, groupByColumns, node); + } + } + return (Map) queryColumnMapCompose(info, funcNodes, groupByColumns, node).join(); + } + + @Override + public CompletableFuture> queryColumnMapAsync(final Class entityClass, final ColumnNode[] funcNodes, final String[] groupByColumns, final FilterNode node) { + final EntityInfo info = loadEntityInfo(entityClass); + final EntityCache cache = info.getCache(); + if (cache != null && (isOnlyCache(info) || cache.isFullLoaded())) { + if (node == null || isCacheUseable(node, this)) { + return CompletableFuture.completedFuture(cache.queryColumnMap(funcNodes, groupByColumns, node)); + } + } + if (isAsync()) return queryColumnMapCompose(info, funcNodes, groupByColumns, node); + return CompletableFuture.supplyAsync(() -> (Map) queryColumnMapCompose(info, funcNodes, groupByColumns, node).join(), getExecutor()); + } + + protected CompletableFuture> queryColumnMapCompose(final EntityInfo info, final ColumnNode[] funcNodes, final String[] groupByColumns, final FilterNode node) { + final StringBuilder groupBySqlColumns = new StringBuilder(); + if (groupByColumns != null && groupByColumns.length > 0) { + for (int i = 0; i < groupByColumns.length; i++) { + if (groupBySqlColumns.length() > 0) groupBySqlColumns.append(", "); + groupBySqlColumns.append(info.getSQLColumn("a", groupByColumns[i])); + } + } + final StringBuilder funcSqlColumns = new StringBuilder(); + for (int i = 0; i < funcNodes.length; i++) { + if (funcSqlColumns.length() > 0) funcSqlColumns.append(", "); + if (funcNodes[i] instanceof ColumnFuncNode) { + funcSqlColumns.append(info.formatSQLValue((Attribute) null, "a", (ColumnFuncNode) funcNodes[i], sqlFormatter)); + } else { + funcSqlColumns.append(info.formatSQLValue((Attribute) null, "a", (ColumnNodeValue) funcNodes[i], sqlFormatter)); + } + } + final Map joinTabalis = node == null ? null : node.getJoinTabalis(); + final Set haset = new HashSet<>(); + final CharSequence join = node == null ? null : node.createSQLJoin(this, false, joinTabalis, haset, info); + final CharSequence where = node == null ? null : node.createSQLExpress(this, info, joinTabalis); + String sql = "SELECT "; + if (groupBySqlColumns.length() > 0) sql += groupBySqlColumns + ", "; + sql += funcSqlColumns + " FROM " + info.getTable(node) + " a" + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where)); + if (groupBySqlColumns.length() > 0) sql += " GROUP BY " + groupBySqlColumns; + if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " querycolumnmap sql=" + sql); + return queryColumnMapDB(info, sql, funcNodes, groupByColumns); + } + + @Local + protected CompletableFuture> queryColumnMapDBApply(EntityInfo info, CompletableFuture future, final ColumnNode[] funcNodes, final String[] groupByColumns) { + return future.thenApply((DataResultSet dataset) -> { + Map rs = new LinkedHashMap<>(); + while (dataset.next()) { + int index = 0; + Serializable[] keys = new Serializable[groupByColumns.length]; + for (int i = 0; i < keys.length; i++) { + keys[i] = (Serializable) dataset.getObject(++index); + } + Number[] vals = new Number[funcNodes.length]; + for (int i = 0; i < vals.length; i++) { + vals[i] = (Number) dataset.getObject(++index); + } + rs.put(keys, vals); + } + dataset.close(); + return rs; + }); + } + + //----------------------------- find ----------------------------- + @Override + public T[] finds(Class clazz, final SelectColumn selects, Serializable... pks) { + return findsAsync(clazz, selects, pks).join(); + } + + @Override + public CompletableFuture findsAsync(Class clazz, final SelectColumn selects, Serializable... pks) { + final EntityInfo info = loadEntityInfo(clazz); + if (pks == null || pks.length == 0) return CompletableFuture.completedFuture(info.getArrayer().apply(0)); + final EntityCache cache = info.getCache(); + if (cache != null) { + T[] rs = selects == null ? cache.finds(pks) : cache.finds(selects, pks); + if (cache.isFullLoaded() || rs != null) return CompletableFuture.completedFuture(rs); + } + return findsComposeAsync(info, selects, pks); + } + + protected CompletableFuture findsComposeAsync(final EntityInfo info, final SelectColumn selects, Serializable... pks) { + final Attribute primary = info.getPrimary(); + return queryListAsync(info.getType(), selects, null, FilterNode.create(info.getPrimarySQLColumn(), FilterExpress.IN, pks)).thenApply(list -> { + T[] rs = info.getArrayer().apply(pks.length); + for (int i = 0; i < rs.length; i++) { + T t = null; + Serializable pk = pks[i]; + for (T item : list) { + if (pk.equals(primary.get(item))) { + t = item; + break; + } + } + rs[i] = t; + } + return rs; + }); + } + + @Override + public T find(Class clazz, final SelectColumn selects, Serializable pk) { + final EntityInfo info = loadEntityInfo(clazz); + final EntityCache cache = info.getCache(); + if (cache != null) { + T rs = selects == null ? cache.find(pk) : cache.find(selects, pk); + if (cache.isFullLoaded() || rs != null) return rs; + } + return findCompose(info, selects, pk).join(); + } + + @Override + public CompletableFuture findAsync(final Class clazz, final SelectColumn selects, final Serializable pk) { + final EntityInfo info = loadEntityInfo(clazz); + final EntityCache cache = info.getCache(); + if (cache != null) { + T rs = selects == null ? cache.find(pk) : cache.find(selects, pk); + if (cache.isFullLoaded() || rs != null) return CompletableFuture.completedFuture(rs); + } + if (isAsync()) return findCompose(info, selects, pk); + return CompletableFuture.supplyAsync(() -> findCompose(info, selects, pk).join(), getExecutor()); + } + + protected CompletableFuture findCompose(final EntityInfo info, final SelectColumn selects, Serializable pk) { + String column = info.getPrimarySQLColumn(); + final String sql = "SELECT " + info.getQueryColumns(null, selects) + " FROM " + info.getTable(pk) + " WHERE " + column + "=" + info.formatSQLValue(column, pk, sqlFormatter); + if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " find sql=" + sql); + return findDB(info, sql, true, selects); + } + + @Override + public T find(final Class clazz, final SelectColumn selects, final FilterNode node) { + final EntityInfo info = loadEntityInfo(clazz); + final EntityCache cache = info.getCache(); + if (cache != null && cache.isFullLoaded() && (node == null || isCacheUseable(node, this))) return cache.find(selects, node); + return this.findCompose(info, selects, node).join(); + } + + @Override + public CompletableFuture findAsync(final Class clazz, final SelectColumn selects, final FilterNode node) { + final EntityInfo info = loadEntityInfo(clazz); + final EntityCache cache = info.getCache(); + if (cache != null && cache.isFullLoaded() && (node == null || isCacheUseable(node, this))) { + return CompletableFuture.completedFuture(cache.find(selects, node)); + } + if (isAsync()) return this.findCompose(info, selects, node); + return CompletableFuture.supplyAsync(() -> this.findCompose(info, selects, node).join(), getExecutor()); + } + + protected CompletableFuture findCompose(final EntityInfo info, final SelectColumn selects, final FilterNode node) { + final Map joinTabalis = node == null ? null : node.getJoinTabalis(); + final CharSequence join = node == null ? null : node.createSQLJoin(this, false, joinTabalis, new HashSet<>(), info); + final CharSequence where = node == null ? null : node.createSQLExpress(this, info, joinTabalis); + final String sql = "SELECT " + info.getQueryColumns("a", selects) + " FROM " + info.getTable(node) + " a" + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where)); + if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " find sql=" + sql); + return findDB(info, sql, false, selects); + } + + @Local + protected CompletableFuture findDBApply(EntityInfo info, CompletableFuture future, boolean onlypk, SelectColumn selects) { + return future.thenApply((DataResultSet pgset) -> { + T rs = pgset.next() ? (onlypk && selects == null ? getEntityValue(info, null, pgset) : getEntityValue(info, selects, pgset)) : null; + pgset.close(); + return rs; + }); + } + + @Override + public Serializable findColumn(final Class clazz, final String column, final Serializable defValue, final Serializable pk) { + final EntityInfo info = loadEntityInfo(clazz); + final EntityCache cache = info.getCache(); + if (cache != null) { + Serializable val = cache.findColumn(column, defValue, pk); + if (cache.isFullLoaded() || val != null) return val; + } + return findColumnCompose(info, column, defValue, pk).join(); + } + + @Override + public CompletableFuture findColumnAsync(final Class clazz, final String column, final Serializable defValue, final Serializable pk) { + final EntityInfo info = loadEntityInfo(clazz); + final EntityCache cache = info.getCache(); + if (cache != null) { + Serializable val = cache.findColumn(column, defValue, pk); + if (cache.isFullLoaded() || val != null) return CompletableFuture.completedFuture(val); + } + if (isAsync()) return findColumnCompose(info, column, defValue, pk); + return CompletableFuture.supplyAsync(() -> findColumnCompose(info, column, defValue, pk).join(), getExecutor()); + } + + protected CompletableFuture findColumnCompose(final EntityInfo info, String column, final Serializable defValue, final Serializable pk) { + final String sql = "SELECT " + info.getSQLColumn(null, column) + " FROM " + info.getTable(pk) + " WHERE " + info.getPrimarySQLColumn() + "=" + info.formatSQLValue(info.getPrimarySQLColumn(), pk, sqlFormatter); + if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " find sql=" + sql); + return findColumnDB(info, sql, true, column, defValue); + } + + @Override + public Serializable findColumn(final Class clazz, final String column, final Serializable defValue, final FilterNode node) { + final EntityInfo info = loadEntityInfo(clazz); + final EntityCache cache = info.getCache(); + if (cache != null) { + Serializable val = cache.findColumn(column, defValue, node); + if (cache.isFullLoaded() || val != null) return val; + } + return this.findColumnCompose(info, column, defValue, node).join(); + } + + @Override + public CompletableFuture findColumnAsync(final Class clazz, final String column, final Serializable defValue, final FilterNode node) { + final EntityInfo info = loadEntityInfo(clazz); + final EntityCache cache = info.getCache(); + if (cache != null) { + Serializable val = cache.findColumn(column, defValue, node); + if (cache.isFullLoaded() || val != null) return CompletableFuture.completedFuture(val); + } + if (isAsync()) return this.findColumnCompose(info, column, defValue, node); + return CompletableFuture.supplyAsync(() -> this.findColumnCompose(info, column, defValue, node).join(), getExecutor()); + } + + protected CompletableFuture findColumnCompose(final EntityInfo info, String column, final Serializable defValue, final FilterNode node) { + final Map joinTabalis = node == null ? null : node.getJoinTabalis(); + final CharSequence join = node == null ? null : node.createSQLJoin(this, false, joinTabalis, new HashSet<>(), info); + final CharSequence where = node == null ? null : node.createSQLExpress(this, info, joinTabalis); + final String sql = "SELECT " + info.getSQLColumn("a", column) + " FROM " + info.getTable(node) + " a" + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where)); + if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " find sql=" + sql); + return findColumnDB(info, sql, false, column, defValue); + } + + @Local + protected CompletableFuture findColumnDBApply(EntityInfo info, CompletableFuture future, boolean onlypk, String column, Serializable defValue) { + return future.thenApply((DataResultSet dataset) -> { + Serializable val = defValue; + if (dataset.next()) { + final Attribute attr = info.getAttribute(column); + val = dataset.getObject(attr, 1, null); + } + dataset.close(); + return val == null ? defValue : val; + }); + } + + //---------------------------- existsCompose ---------------------------- + @Override + public boolean exists(Class clazz, Serializable pk) { + final EntityInfo info = loadEntityInfo(clazz); + final EntityCache cache = info.getCache(); + if (cache != null) { + boolean rs = cache.exists(pk); + if (rs || cache.isFullLoaded()) return rs; + } + return existsCompose(info, pk).join(); + } + + @Override + public CompletableFuture existsAsync(final Class clazz, final Serializable pk) { + final EntityInfo info = loadEntityInfo(clazz); + final EntityCache cache = info.getCache(); + if (cache != null) { + boolean rs = cache.exists(pk); + if (rs || cache.isFullLoaded()) return CompletableFuture.completedFuture(rs); + } + if (isAsync()) return existsCompose(info, pk); + return CompletableFuture.supplyAsync(() -> existsCompose(info, pk).join(), getExecutor()); + } + + protected CompletableFuture existsCompose(final EntityInfo info, Serializable pk) { + final String sql = "SELECT COUNT(*) FROM " + info.getTable(pk) + " WHERE " + info.getPrimarySQLColumn() + "=" + info.formatSQLValue(info.getPrimarySQLColumn(), pk, sqlFormatter); + if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " exists sql=" + sql); + return existsDB(info, sql, true); + } + + @Override + public boolean exists(final Class clazz, final FilterNode node) { + final EntityInfo info = loadEntityInfo(clazz); + final EntityCache cache = info.getCache(); + if (cache != null) { + boolean rs = cache.exists(node); + if (rs || cache.isFullLoaded()) return rs; + } + return this.existsCompose(info, node).join(); + } + + @Override + public CompletableFuture existsAsync(final Class clazz, final FilterNode node) { + final EntityInfo info = loadEntityInfo(clazz); + final EntityCache cache = info.getCache(); + if (cache != null) { + boolean rs = cache.exists(node); + if (rs || cache.isFullLoaded()) return CompletableFuture.completedFuture(rs); + } + if (isAsync()) return this.existsCompose(info, node); + return CompletableFuture.supplyAsync(() -> this.existsCompose(info, node).join(), getExecutor()); + } + + protected CompletableFuture existsCompose(final EntityInfo info, FilterNode node) { + final Map joinTabalis = node == null ? null : node.getJoinTabalis(); + final CharSequence join = node == null ? null : node.createSQLJoin(this, false, joinTabalis, new HashSet<>(), info); + final CharSequence where = node == null ? null : node.createSQLExpress(this, info, joinTabalis); + final String sql = "SELECT COUNT(" + info.getPrimarySQLColumn("a") + ") FROM " + info.getTable(node) + " a" + (join == null ? "" : join) + ((where == null || where.length() == 0) ? "" : (" WHERE " + where)); + if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " exists sql=" + sql); + return existsDB(info, sql, false); + } + + @Local + protected CompletableFuture existsDBApply(EntityInfo info, CompletableFuture future, boolean onlypk) { + return future.thenApply((DataResultSet pgset) -> { + boolean rs = pgset.next() ? (((Number) pgset.getObject(1)).intValue() > 0) : false; + pgset.close(); + return rs; + }); + } + + //-----------------------list set---------------------------- + @Override + public Set queryColumnSet(final String selectedColumn, final Class clazz, final Flipper flipper, final FilterNode node) { + final Set list = querySet(clazz, SelectColumn.includes(selectedColumn), flipper, node); + final Set rs = new LinkedHashSet<>(); + if (list.isEmpty()) return rs; + final EntityInfo info = loadEntityInfo(clazz); + final Attribute selected = (Attribute) info.getAttribute(selectedColumn); + for (T t : list) { + rs.add(selected.get(t)); + } + return rs; + } + + @Override + public CompletableFuture> queryColumnSetAsync(final String selectedColumn, final Class clazz, final Flipper flipper, final FilterNode node) { + return querySetAsync(clazz, SelectColumn.includes(selectedColumn), flipper, node).thenApply((Set list) -> { + final Set rs = new LinkedHashSet<>(); + if (list.isEmpty()) return rs; + final EntityInfo info = loadEntityInfo(clazz); + final Attribute selected = (Attribute) info.getAttribute(selectedColumn); + for (T t : list) { + rs.add(selected.get(t)); + } + return rs; + }); + } + + @Override + public List queryColumnList(final String selectedColumn, final Class clazz, final Flipper flipper, final FilterNode node) { + final List list = queryList(clazz, SelectColumn.includes(selectedColumn), flipper, node); + final List rs = new ArrayList<>(); + if (list.isEmpty()) return rs; + final EntityInfo info = loadEntityInfo(clazz); + final Attribute selected = (Attribute) info.getAttribute(selectedColumn); + for (T t : list) { + rs.add(selected.get(t)); + } + return rs; + } + + @Override + public CompletableFuture> queryColumnListAsync(final String selectedColumn, final Class clazz, final Flipper flipper, final FilterNode node) { + return queryListAsync(clazz, SelectColumn.includes(selectedColumn), flipper, node).thenApply((List list) -> { + final List rs = new ArrayList<>(); + if (list.isEmpty()) return rs; + final EntityInfo info = loadEntityInfo(clazz); + final Attribute selected = (Attribute) info.getAttribute(selectedColumn); + for (T t : list) { + rs.add(selected.get(t)); + } + return rs; + }); + } + + @Override + public Sheet queryColumnSheet(final String selectedColumn, final Class clazz, final Flipper flipper, final FilterNode node) { + Sheet sheet = querySheet(clazz, SelectColumn.includes(selectedColumn), flipper, node); + final Sheet rs = new Sheet<>(); + if (sheet.isEmpty()) return rs; + rs.setTotal(sheet.getTotal()); + final EntityInfo info = loadEntityInfo(clazz); + final Attribute selected = (Attribute) info.getAttribute(selectedColumn); + final List list = new ArrayList<>(); + for (T t : sheet.getRows()) { + list.add(selected.get(t)); + } + rs.setRows(list); + return rs; + } + + @Override + public CompletableFuture> queryColumnSheetAsync(final String selectedColumn, final Class clazz, final Flipper flipper, final FilterNode node) { + return querySheetAsync(clazz, SelectColumn.includes(selectedColumn), flipper, node).thenApply((Sheet sheet) -> { + final Sheet rs = new Sheet<>(); + if (sheet.isEmpty()) return rs; + rs.setTotal(sheet.getTotal()); + final EntityInfo info = loadEntityInfo(clazz); + final Attribute selected = (Attribute) info.getAttribute(selectedColumn); + final List list = new ArrayList<>(); + for (T t : sheet.getRows()) { + list.add(selected.get(t)); + } + rs.setRows(list); + return rs; + }); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凪ap闆嗗悎, 涓婚敭鍊间负key
+ * 绛変环SQL: SELECT * FROM {table} WHERE {column} = {key} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param 涓婚敭娉涘瀷 + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param selects 鎸囧畾瀛楁 + * @param keyStream 涓婚敭Stream + * + * @return Entity鐨勯泦鍚 + */ + @Override + public Map queryMap(final Class clazz, final SelectColumn selects, final Stream keyStream) { + if (keyStream == null) return new LinkedHashMap<>(); + final EntityInfo info = loadEntityInfo(clazz); + final ArrayList ids = new ArrayList<>(); + keyStream.forEach(k -> ids.add(k)); + final Attribute primary = info.getPrimary(); + List rs = queryList(clazz, FilterNode.create(primary.field(), ids)); + Map map = new LinkedHashMap<>(); + if (rs.isEmpty()) return new LinkedHashMap<>(); + for (T item : rs) { + map.put((K) primary.get(item), item); + } + return map; + } + + @Override + public CompletableFuture> queryMapAsync(final Class clazz, final SelectColumn selects, final Stream keyStream) { + if (keyStream == null) return CompletableFuture.completedFuture(new LinkedHashMap<>()); + final EntityInfo info = loadEntityInfo(clazz); + final ArrayList pks = new ArrayList<>(); + keyStream.forEach(k -> pks.add(k)); + final Attribute primary = info.getPrimary(); + return queryListAsync(clazz, FilterNode.create(primary.field(), pks)).thenApply((List rs) -> { + Map map = new LinkedHashMap<>(); + if (rs.isEmpty()) return new LinkedHashMap<>(); + for (T item : rs) { + map.put((K) primary.get(item), item); + } + return map; + }); + } + + /** + * 鏌ヨ绗﹀悎杩囨护鏉′欢璁板綍鐨凪ap闆嗗悎, 涓婚敭鍊间负key
+ * 绛変环SQL: SELECT * FROM {table} WHERE {column} = {key} ORDER BY {flipper.sort} LIMIT {flipper.limit}
+ * + * @param 涓婚敭娉涘瀷 + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param selects 鎸囧畾瀛楁 + * @param node FilterNode + * + * @return Entity鐨勯泦鍚 + */ + @Override + public Map queryMap(final Class clazz, final SelectColumn selects, final FilterNode node) { + List rs = queryList(clazz, selects, node); + final EntityInfo info = loadEntityInfo(clazz); + final Attribute primary = info.getPrimary(); + Map map = new LinkedHashMap<>(); + if (rs.isEmpty()) return new LinkedHashMap<>(); + for (T item : rs) { + map.put((K) primary.get(item), item); + } + return map; + } + + @Override + public CompletableFuture> queryMapAsync(final Class clazz, final SelectColumn selects, final FilterNode node) { + return queryListAsync(clazz, selects, node).thenApply((List rs) -> { + final EntityInfo info = loadEntityInfo(clazz); + final Attribute primary = info.getPrimary(); + Map map = new LinkedHashMap<>(); + if (rs.isEmpty()) return new LinkedHashMap<>(); + for (T item : rs) { + map.put((K) primary.get(item), item); + } + return map; + }); + } + + @Override + public Set querySet(final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node) { + return new LinkedHashSet<>(querySheetCompose(true, false, true, clazz, selects, flipper, node).join().list(true)); + } + + @Override + public CompletableFuture> querySetAsync(final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node) { + return querySheetCompose(true, false, true, clazz, selects, flipper, node).thenApply((rs) -> new LinkedHashSet<>(rs.list(true))); + } + + @Override + public List queryList(final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node) { + return querySheetCompose(true, false, false, clazz, selects, flipper, node).join().list(true); + } + + @Override + public CompletableFuture> queryListAsync(final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node) { + return querySheetCompose(true, false, false, clazz, selects, flipper, node).thenApply((rs) -> rs.list(true)); + } + + @Override + public Sheet querySheet(final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node) { + return querySheetCompose(true, true, false, clazz, selects, flipper, node).join(); + } + + @Override + public CompletableFuture> querySheetAsync(final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node) { + if (isAsync()) return querySheetCompose(true, true, false, clazz, selects, flipper, node); + return CompletableFuture.supplyAsync(() -> querySheetCompose(true, true, false, clazz, selects, flipper, node).join(), getExecutor()); + } + + protected CompletableFuture> querySheetCompose(final boolean readcache, final boolean needtotal, final boolean distinct, final Class clazz, final SelectColumn selects, final Flipper flipper, final FilterNode node) { + final EntityInfo info = loadEntityInfo(clazz); + final EntityCache cache = info.getCache(); + if (readcache && cache != null && cache.isFullLoaded()) { + if (node == null || isCacheUseable(node, this)) { + if (info.isLoggable(logger, Level.FINEST, " cache query predicate = ")) logger.finest(clazz.getSimpleName() + " cache query predicate = " + (node == null ? null : createPredicate(node, cache))); + return CompletableFuture.completedFuture(cache.querySheet(needtotal, distinct, selects, flipper, node)); + } + } + return querySheetDB(info, readcache, needtotal, distinct, selects, flipper, node); + } + + protected static enum UpdateMode { + INSERT, DELETE, UPDATE, CLEAR, DROP, ALTER, OTHER; + } +} diff --git a/src/main/java/org/redkale/source/DistributeTable.java b/src/main/java/org/redkale/source/DistributeTable.java index da70af068..c4345a256 100644 --- a/src/main/java/org/redkale/source/DistributeTable.java +++ b/src/main/java/org/redkale/source/DistributeTable.java @@ -1,26 +1,26 @@ -/* - * 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.source; - -import java.lang.annotation.*; -import static java.lang.annotation.ElementType.*; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * Entity鍒嗗簱鍒嗚〃鐨勬敞瑙o紝闇瑕佺粨鍚圖istributeTableStrategy浣跨敤
- * 鏍囪涓 @DistributeTable鐨凟ntity绫昏涓洪渶瑕佽繘琛屽垎搴撳垎琛ㄦ搷浣
- * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@Target({TYPE}) -@Retention(RUNTIME) -public @interface DistributeTable { - - Class strategy(); -} +/* + * 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.source; + +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * Entity鍒嗗簱鍒嗚〃鐨勬敞瑙o紝闇瑕佺粨鍚圖istributeTableStrategy浣跨敤
+ * 鏍囪涓 @DistributeTable鐨凟ntity绫昏涓洪渶瑕佽繘琛屽垎搴撳垎琛ㄦ搷浣
+ * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@Target({TYPE}) +@Retention(RUNTIME) +public @interface DistributeTable { + + Class strategy(); +} diff --git a/src/main/java/org/redkale/source/DistributeTableStrategy.java b/src/main/java/org/redkale/source/DistributeTableStrategy.java index a1146fbcb..5bce05353 100644 --- a/src/main/java/org/redkale/source/DistributeTableStrategy.java +++ b/src/main/java/org/redkale/source/DistributeTableStrategy.java @@ -1,57 +1,57 @@ -/* - * 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.source; - -import java.io.Serializable; - -/** - * 鍒嗚〃鍒嗗簱绛栫暐锛岀粨鍚@DistributeTable浣跨敤
- * 涓嶈兘涓@Cacheable鍚屾椂浣跨敤
- * 浣跨敤鍒嗚〃鍒嗗簱鍔熻兘閲嶇偣鏄富閿殑鐢熸垚绛栫暐锛屼笉鍚屽満鏅敓鎴愮瓥鐣ヤ笉涓鏍
- * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Entity绫诲瀷 - */ -public interface DistributeTableStrategy { - - /** - * 鑾峰彇瀵硅薄鐨勮〃鍚
- * 鏌ヨ鍗曚釜瀵硅薄锛圖ataSource.find锛夋椂璋冪敤鏈柟娉曡幏鍙栬〃鍚
- * - * @param table 妯℃澘琛ㄧ殑琛ㄥ悕 - * @param primary 璁板綍涓婚敭 - * - * @return 甯﹀簱鍚嶇殑鍏ㄨ〃鍚 - */ - public String getTable(String table, Serializable primary); - - /** - * 鑾峰彇瀵硅薄鐨勮〃鍚
- * 鏂板瀵硅薄鎴栨洿鏂板崟涓璞★紙DataSource.insert銆丏ataSource.update锛夋椂璋冪敤鏈柟娉曡幏鍙栬〃鍚
- * - * @param table 妯℃澘琛ㄧ殑琛ㄥ悕 - * @param bean 瀹炰綋瀵硅薄 - * - * @return 甯﹀簱鍚嶇殑鍏ㄨ〃鍚 - */ - public String getTable(String table, T bean); - - /** - * 鑾峰彇瀵硅薄鐨勮〃鍚
- * 鏌ヨ銆佷慨鏀广佸垹闄ゅ璞★紙DataSource.find銆丏ataSource.query銆丏ataSource.delete銆丏ataSource.update锛夋椂璋冪敤鏈柟娉曡幏鍙栬〃鍚
- * 娉ㄦ剰锛 闇淇濊瘉FilterNode杩囨护鐨勭粨鏋滈泦鍚堝繀椤诲湪涓涓暟鎹簱琛ㄤ腑
- * - * @param table 妯℃澘琛ㄧ殑琛ㄥ悕 - * @param node 杩囨护鏉′欢 - * - * @return 甯﹀簱鍚嶇殑鍏ㄨ〃鍚 - */ - public String getTable(String table, FilterNode node); - -} +/* + * 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.source; + +import java.io.Serializable; + +/** + * 鍒嗚〃鍒嗗簱绛栫暐锛岀粨鍚@DistributeTable浣跨敤
+ * 涓嶈兘涓@Cacheable鍚屾椂浣跨敤
+ * 浣跨敤鍒嗚〃鍒嗗簱鍔熻兘閲嶇偣鏄富閿殑鐢熸垚绛栫暐锛屼笉鍚屽満鏅敓鎴愮瓥鐣ヤ笉涓鏍
+ * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Entity绫诲瀷 + */ +public interface DistributeTableStrategy { + + /** + * 鑾峰彇瀵硅薄鐨勮〃鍚
+ * 鏌ヨ鍗曚釜瀵硅薄锛圖ataSource.find锛夋椂璋冪敤鏈柟娉曡幏鍙栬〃鍚
+ * + * @param table 妯℃澘琛ㄧ殑琛ㄥ悕 + * @param primary 璁板綍涓婚敭 + * + * @return 甯﹀簱鍚嶇殑鍏ㄨ〃鍚 + */ + public String getTable(String table, Serializable primary); + + /** + * 鑾峰彇瀵硅薄鐨勮〃鍚
+ * 鏂板瀵硅薄鎴栨洿鏂板崟涓璞★紙DataSource.insert銆丏ataSource.update锛夋椂璋冪敤鏈柟娉曡幏鍙栬〃鍚
+ * + * @param table 妯℃澘琛ㄧ殑琛ㄥ悕 + * @param bean 瀹炰綋瀵硅薄 + * + * @return 甯﹀簱鍚嶇殑鍏ㄨ〃鍚 + */ + public String getTable(String table, T bean); + + /** + * 鑾峰彇瀵硅薄鐨勮〃鍚
+ * 鏌ヨ銆佷慨鏀广佸垹闄ゅ璞★紙DataSource.find銆丏ataSource.query銆丏ataSource.delete銆丏ataSource.update锛夋椂璋冪敤鏈柟娉曡幏鍙栬〃鍚
+ * 娉ㄦ剰锛 闇淇濊瘉FilterNode杩囨护鐨勭粨鏋滈泦鍚堝繀椤诲湪涓涓暟鎹簱琛ㄤ腑
+ * + * @param table 妯℃澘琛ㄧ殑琛ㄥ悕 + * @param node 杩囨护鏉′欢 + * + * @return 甯﹀簱鍚嶇殑鍏ㄨ〃鍚 + */ + public String getTable(String table, FilterNode node); + +} diff --git a/src/main/java/org/redkale/source/EntityCache.java b/src/main/java/org/redkale/source/EntityCache.java index 6de3d1823..076938bf6 100644 --- a/src/main/java/org/redkale/source/EntityCache.java +++ b/src/main/java/org/redkale/source/EntityCache.java @@ -1,1078 +1,1078 @@ -/* - * 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.source; - -import java.io.Serializable; -import java.lang.reflect.Array; -import java.util.*; -import java.util.concurrent.*; -import java.util.concurrent.atomic.*; -import java.util.function.*; -import java.util.logging.*; -import java.util.stream.*; -import javax.persistence.*; -import static org.redkale.source.FilterFunc.*; -import org.redkale.util.*; - -/** - * Entity鏁版嵁鐨勭紦瀛樼被 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Entity绫荤殑娉涘瀷 - */ -@SuppressWarnings("unchecked") -public final class EntityCache { - - //鏃ュ織 - private static final Logger logger = Logger.getLogger(EntityCache.class.getName()); - - //涓婚敭涓庡璞$殑閿煎 - private ConcurrentHashMap map = new ConcurrentHashMap(); - - // CopyOnWriteArrayList 鎻掑叆鎱€佹煡璇㈠揩; 10w鏁版嵁鎻掑叆闇瑕3.2绉; ConcurrentLinkedQueue 鎻掑叆蹇佹煡璇㈡參锛10w鏁版嵁鏌ヨ闇瑕 0.062绉掞紝 鏌ヨ鎱40%; - private Collection list = new ConcurrentLinkedQueue(); - - //Flipper.sort杞崲鎴怌omparator鐨勭紦瀛 - private final Map> sortComparators = new ConcurrentHashMap<>(); - - //Entity绫 - private final Class type; - - //鎺ュ彛杩斿洖鐨勫璞℃槸鍚﹂渶瑕佸鍒朵竴浠 - private final boolean needcopy; - - //Entity鏋勫缓鍣 - private final Creator creator; - - //Entity鏁板兼瀯寤哄櫒 - private final IntFunction arrayer; - - //涓婚敭瀛楁 - private final Attribute primary; - - //鏂板鏃剁殑澶嶅埗鍣紝 鎺掗櫎浜嗘爣璁颁负@Transient鐨勫瓧娈 - private final Reproduce newReproduce; - - //淇敼鏃剁殑澶嶅埗鍣紝 鎺掗櫎浜嗘爣璁颁负@Transient鎴@Column(updatable=false)鐨勫瓧娈 - private final Reproduce chgReproduce; - - //鏄惁宸茬粡鍏ㄩ噺鍔犺浇杩 - private volatile boolean fullloaded; - - private final AtomicBoolean loading = new AtomicBoolean(); - - //Entity淇℃伅 - final EntityInfo info; - - //@Cacheable鐨勫畾鏃舵洿鏂扮鏁帮紝涓0琛ㄧず涓嶅畾鏃舵洿鏂 - final int interval; - - //@Cacheable鐨勫畾鏃跺櫒 - private ScheduledThreadPoolExecutor scheduler; - - private CompletableFuture> loadFuture; - - public EntityCache(final EntityInfo info, final Cacheable c) { - this.info = info; - this.interval = c == null ? 0 : c.interval(); - this.type = info.getType(); - this.arrayer = info.getArrayer(); - this.creator = info.getCreator(); - this.primary = info.primary; - VirtualEntity ve = info.getType().getAnnotation(VirtualEntity.class); - boolean direct = c != null && c.direct(); - if (!direct) direct = ve != null && ve.direct(); - this.needcopy = !direct; - this.newReproduce = Reproduce.create(type, type, (m) -> { - try { - return type.getDeclaredField(m).getAnnotation(Transient.class) == null; - } catch (Exception e) { - return true; - } - }); - this.chgReproduce = Reproduce.create(type, type, (m) -> { - try { - java.lang.reflect.Field field = type.getDeclaredField(m); - if (field.getAnnotation(Transient.class) != null) return false; - Column column = field.getAnnotation(Column.class); - return (column == null || column.updatable()); - } catch (Exception e) { - return true; - } - }); - } - - public CompletableFuture> fullLoadAsync() { - if (this.fullloaded) return this.loadFuture; - if (loading.getAndSet(true)) return this.loadFuture; - if (info.fullloader == null) { - this.list = new ConcurrentLinkedQueue(); - this.map = new ConcurrentHashMap(); - this.fullloaded = true; - loading.set(false); - return this.loadFuture; - } - this.fullloaded = false; - CompletableFuture allFuture = info.fullloader.apply(info.source, info); - this.loadFuture = (CompletableFuture) allFuture; - if (allFuture == null) { - this.list = new ConcurrentLinkedQueue(); - this.map = new ConcurrentHashMap(); - this.fullloaded = true; - loading.set(false); - return this.loadFuture; - } - if (this.interval > 0 && this.scheduler == null && info.fullloader != null) { - this.scheduler = new ScheduledThreadPoolExecutor(1, (Runnable r) -> { - final Thread t = new Thread(r, "Redkale-EntityCache-" + type + "-Thread"); - t.setDaemon(true); - return t; - }); - this.scheduler.scheduleAtFixedRate(() -> { - try { - ConcurrentHashMap newmap2 = new ConcurrentHashMap(); - List all2 = info.fullloader.apply(info.source, info).join(); - if (all2 != null) { - all2.stream().filter(x -> x != null).forEach(x -> { - newmap2.put(this.primary.get(x), x); - }); - } - this.list = all2 == null ? new ConcurrentLinkedQueue() : new ConcurrentLinkedQueue(all2); - this.map = newmap2; - } catch (Throwable t) { - logger.log(Level.SEVERE, type + " schedule(interval=" + interval + "s) Cacheable error", t); - } - }, interval - System.currentTimeMillis() / 1000 % interval, interval, TimeUnit.SECONDS); - } - allFuture.whenComplete((l, t) -> { - if (t != null) { - loading.set(false); - return; - } - List all = l; - ConcurrentHashMap newmap = new ConcurrentHashMap(); - if (all != null) { - all.stream().filter(x -> x != null).forEach(x -> { - newmap.put(this.primary.get(x), x); - }); - } - this.list = new ConcurrentLinkedQueue(all); - this.map = newmap; - this.fullloaded = true; - loading.set(false); - }); - return this.loadFuture; - } - - public Class getType() { - return type; - } - - public int clear() { - this.fullloaded = false; - this.list = new ConcurrentLinkedQueue(); - this.map = new ConcurrentHashMap(); - if (this.scheduler != null) { - this.scheduler.shutdownNow(); - this.scheduler = null; - } - return 1; - } - - public boolean isFullLoaded() { - return fullloaded; - } - - public T find(Serializable pk) { - if (pk == null) return null; - T rs = map.get(pk); - return rs == null ? null : (needcopy ? newReproduce.apply(this.creator.create(), rs) : rs); - } - - public T[] finds(Serializable... pks) { - if (pks == null || pks.length == 0) return arrayer.apply(0); - if (pks.length == 1) { - Class t = pks[0].getClass(); - if (t == int[].class) { - int[] ids = (int[]) pks[0]; - T[] array = arrayer.apply(ids.length); - for (int i = 0; i < array.length; i++) { - T rs = map.get(ids[i]); - array[i] = rs == null ? null : (needcopy ? newReproduce.apply(this.creator.create(), rs) : rs); - } - return array; - } else if (t == long[].class) { - long[] ids = (long[]) pks[0]; - T[] array = arrayer.apply(ids.length); - for (int i = 0; i < array.length; i++) { - T rs = map.get(ids[i]); - array[i] = rs == null ? null : (needcopy ? newReproduce.apply(this.creator.create(), rs) : rs); - } - return array; - } - } - T[] array = arrayer.apply(pks.length); - for (int i = 0; i < array.length; i++) { - T rs = map.get(pks[i]); - array[i] = rs == null ? null : (needcopy ? newReproduce.apply(this.creator.create(), rs) : rs); - } - return array; - } - - public T find(final SelectColumn selects, final Serializable pk) { - if (pk == null) return null; - T rs = map.get(pk); - if (rs == null) return null; - if (selects == null) return (needcopy ? newReproduce.apply(this.creator.create(), rs) : rs); - T t = this.creator.create(); - for (Attribute attr : this.info.attributes) { - if (selects.test(attr.field())) attr.set(t, attr.get(rs)); - } - return t; - } - - public T[] finds(final SelectColumn selects, Serializable... pks) { - if (pks == null || pks.length == 0) return arrayer.apply(0); - final Creator ctr = this.creator; - final Attribute[] attrs = this.info.attributes; - int size = pks.length; - int[] ids1 = null; - long[] ids2 = null; - if (size == 1) { - if (pks[0].getClass() == int[].class) { - ids1 = (int[]) pks[0]; - } else if (pks[0].getClass() == long[].class) { - ids2 = (long[]) pks[0]; - } - } - T[] array = arrayer.apply(size); - for (int i = 0; i < array.length; i++) { - Serializable id = ids1 == null ? (ids2 == null ? pks[i] : ids2[i]) : ids1[i]; - T rs = map.get(id); - if (rs == null) continue; - if (selects == null) { - if (needcopy) rs = newReproduce.apply(ctr.create(), rs); - } else { - T t = ctr.create(); - for (Attribute attr : attrs) { - if (selects.test(attr.field())) attr.set(t, attr.get(rs)); - } - rs = t; - } - array[i] = rs; - } - return array; - } - - public T find(final SelectColumn selects, FilterNode node) { - final Predicate filter = node == null ? null : node.createPredicate(this); - Stream stream = this.list.stream(); - if (filter != null) stream = stream.filter(filter); - Optional opt = stream.findFirst(); - if (!opt.isPresent()) return null; - if (selects == null) return (needcopy ? newReproduce.apply(this.creator.create(), opt.get()) : opt.get()); - T rs = opt.get(); - T t = this.creator.create(); - for (Attribute attr : this.info.attributes) { - if (selects.test(attr.field())) attr.set(t, attr.get(rs)); - } - return t; - } - - public Serializable findColumn(final String column, final Serializable defValue, final Serializable pk) { - if (pk == null) return defValue; - T rs = map.get(pk); - if (rs == null) return defValue; - for (Attribute attr : this.info.attributes) { - if (column.equals(attr.field())) { - Serializable val = (Serializable) attr.get(rs); - return val == null ? defValue : val; - } - } - return defValue; - } - - public Serializable findColumn(final String column, final Serializable defValue, FilterNode node) { - final Predicate filter = node == null ? null : node.createPredicate(this); - Stream stream = this.list.stream(); - if (filter != null) stream = stream.filter(filter); - Optional opt = stream.findFirst(); - if (!opt.isPresent()) return defValue; - T rs = opt.get(); - for (Attribute attr : this.info.attributes) { - if (column.equals(attr.field())) { - Serializable val = (Serializable) attr.get(rs); - return val == null ? defValue : val; - } - } - return defValue; - } - - public boolean exists(Serializable pk) { - if (pk == null) return false; - final Class atype = this.primary.type(); - if (pk.getClass() != atype && pk instanceof Number) { - if (atype == int.class || atype == Integer.class) { - pk = ((Number) pk).intValue(); - } else if (atype == long.class || atype == Long.class) { - pk = ((Number) pk).longValue(); - } else if (atype == short.class || atype == Short.class) { - pk = ((Number) pk).shortValue(); - } else if (atype == float.class || atype == Float.class) { - pk = ((Number) pk).floatValue(); - } else if (atype == byte.class || atype == Byte.class) { - pk = ((Number) pk).byteValue(); - } else if (atype == double.class || atype == Double.class) { - pk = ((Number) pk).doubleValue(); - } else if (atype == AtomicInteger.class) { - pk = new AtomicInteger(((Number) pk).intValue()); - } else if (atype == AtomicLong.class) { - pk = new AtomicLong(((Number) pk).longValue()); - } else if (atype == LongAdder.class) { - LongAdder la = new LongAdder(); - la.add(((Number) pk).longValue()); - pk = la; - } - } - return this.map.containsKey(pk); - } - - public boolean exists(FilterNode node) { - final Predicate filter = node == null ? null : node.createPredicate(this); - Stream stream = this.list.stream(); - if (filter != null) stream = stream.filter(filter); - return stream.findFirst().isPresent(); - } - - public boolean exists(final Predicate filter) { - return (filter != null) && this.list.stream().filter(filter).findFirst().isPresent(); - } - - public Map queryColumnMap(final String keyColumn, final FilterFunc func, final String funcColumn, FilterNode node) { - final Attribute keyAttr = info.getAttribute(keyColumn); - final Predicate filter = node == null ? null : node.createPredicate(this); - final Attribute funcAttr = funcColumn == null ? null : info.getAttribute(funcColumn); - Stream stream = this.list.stream(); - if (filter != null) stream = stream.filter(filter); - Collector collector = null; - final Class valtype = funcAttr == null ? null : funcAttr.type(); - if (func != null) { - switch (func) { - case AVG: - if (valtype == float.class || valtype == Float.class || valtype == double.class || valtype == Double.class) { - collector = (Collector) Collectors.averagingDouble((T t) -> ((Number) funcAttr.get(t)).doubleValue()); - } else { - collector = (Collector) Collectors.averagingLong((T t) -> ((Number) funcAttr.get(t)).longValue()); - } - break; - case COUNT: - collector = (Collector) Collectors.counting(); - break; - case DISTINCTCOUNT: - collector = (Collector) Collectors.mapping((t) -> funcAttr.get(t), Collectors.toSet()); - break; - case MAX: - case MIN: - Comparator comp = (o1, o2) -> o1 == null ? (o2 == null ? 0 : -1) : ((Comparable) funcAttr.get(o1)).compareTo(funcAttr.get(o2)); - collector = (Collector) ((func == MAX) ? Collectors.maxBy(comp) : Collectors.minBy(comp)); - break; - case SUM: - if (valtype == float.class || valtype == Float.class || valtype == double.class || valtype == Double.class) { - collector = (Collector) Collectors.summingDouble((T t) -> ((Number) funcAttr.get(t)).doubleValue()); - } else { - collector = (Collector) Collectors.summingLong((T t) -> ((Number) funcAttr.get(t)).longValue()); - } - break; - } - } - Map rs = collector == null ? stream.collect(Collectors.toMap(t -> keyAttr.get(t), t -> funcAttr.get(t), (key1, key2) -> key2)) - : stream.collect(Collectors.groupingBy(t -> keyAttr.get(t), LinkedHashMap::new, collector)); - if (func == MAX || func == MIN) { - Map rs2 = new LinkedHashMap(); - rs.forEach((x, y) -> { - if (((Optional) y).isPresent()) rs2.put(x, funcAttr.get((T) ((Optional) y).get())); - }); - rs = rs2; - } else if (func == DISTINCTCOUNT) { - Map rs2 = new LinkedHashMap(); - rs.forEach((x, y) -> rs2.put(x, ((Set) y).size() + 0L)); - rs = rs2; - } - return rs; - } - - public Map queryColumnMap(final ColumnNode[] funcNodes, final String[] groupByColumns, FilterNode node) { - final Predicate filter = node == null ? null : node.createPredicate(this); - Stream stream = this.list.stream(); - if (filter != null) stream = stream.filter(filter); - final Attribute[] attrs = new Attribute[groupByColumns.length]; - for (int i = 0; i < groupByColumns.length; i++) { - attrs[i] = info.getAttribute(groupByColumns[i]); - } - final Map valmap = new HashMap<>(); - Function func = t -> { - StringBuilder sb = new StringBuilder(); - final Serializable[] vals = new Serializable[attrs.length]; - for (int i = 0; i < attrs.length; i++) { - vals[i] = attrs[i].get(t); - sb.append((char) 20).append(vals[i]); - } - final String key = sb.toString(); - if (!valmap.containsKey(key)) valmap.put(key, vals); - return valmap.get(key); - }; - Map> listmap = stream.collect(Collectors.groupingBy(func)); - final Map rsmap = new HashMap<>(listmap.size()); - listmap.forEach((k, l) -> rsmap.put(k, queryColumnNumbers(l, funcNodes))); - return rsmap; - } - - private Number[] queryColumnNumbers(final List list, final ColumnNode[] funcNodes) { - if (true) throw new UnsupportedOperationException("Not supported yet."); - Number[] rs = new Number[funcNodes.length]; - for (int i = 0; i < rs.length; i++) { - rs[i] = queryColumnNumber(list, funcNodes[i]); - } - return rs; - } - - private Number queryColumnNumber(final List list, final ColumnNode funcNode) { - if (funcNode instanceof ColumnFuncNode) { - return queryColumnNumber(list, (ColumnFuncNode) funcNode); - } else if (funcNode instanceof ColumnNodeValue) { - return queryColumnNumber(list, (ColumnNodeValue) funcNode); - } else { - return null; - } - } - - private Number queryColumnNumber(final List list, final ColumnFuncNode funcNode) { - if (funcNode.getValue() instanceof String) { - final Attribute attr = info.getAttribute((String) funcNode.getValue()); - final Function attrFunc = x -> (Number) attr.get(x); - return getNumberResult(list, funcNode.getFunc(), null, attr.type(), attrFunc, (FilterNode) null); - } - Number num = null; - if (funcNode.getValue() instanceof ColumnFuncNode) { - num = queryColumnNumber(list, (ColumnFuncNode) funcNode.getValue()); - } else if (funcNode.getValue() instanceof ColumnNodeValue) { - num = queryColumnNumber(list, (ColumnNodeValue) funcNode.getValue()); - } - return num; - } - - private Number queryColumnNumber(final List list, final ColumnNodeValue nodeValue) { - return null; - } - - private Number getNumberResult(final Collection entityList, final FilterFunc func, final Number defResult, final Class attrType, final Function attrFunc, final FilterNode node) { - final Predicate filter = node == null ? null : node.createPredicate(this); - Stream stream = entityList.stream(); - if (filter != null) stream = stream.filter(filter); - switch (func) { - case AVG: - if (attrType == int.class || attrType == Integer.class || attrType == AtomicInteger.class) { - OptionalDouble rs = stream.mapToInt(x -> ((Number) attrFunc.apply(x)).intValue()).average(); - return rs.isPresent() ? (int) rs.getAsDouble() : defResult; - } else if (attrType == long.class || attrType == Long.class || attrType == AtomicLong.class || attrType == LongAdder.class) { - OptionalDouble rs = stream.mapToLong(x -> ((Number) attrFunc.apply(x)).longValue()).average(); - return rs.isPresent() ? (long) rs.getAsDouble() : defResult; - } else if (attrType == short.class || attrType == Short.class) { - OptionalDouble rs = stream.mapToInt(x -> ((Short) attrFunc.apply(x)).intValue()).average(); - return rs.isPresent() ? (short) rs.getAsDouble() : defResult; - } else if (attrType == float.class || attrType == Float.class) { - OptionalDouble rs = stream.mapToDouble(x -> ((Float) attrFunc.apply(x)).doubleValue()).average(); - return rs.isPresent() ? (float) rs.getAsDouble() : defResult; - } else if (attrType == double.class || attrType == Double.class) { - OptionalDouble rs = stream.mapToDouble(x -> (Double) attrFunc.apply(x)).average(); - return rs.isPresent() ? rs.getAsDouble() : defResult; - } - throw new RuntimeException("getNumberResult error(type:" + type + ", attr.type: " + attrType); - case COUNT: - return stream.count(); - case DISTINCTCOUNT: - return stream.map(x -> attrFunc.apply(x)).distinct().count(); - - case MAX: - if (attrType == int.class || attrType == Integer.class || attrType == AtomicInteger.class) { - OptionalInt rs = stream.mapToInt(x -> ((Number) attrFunc.apply(x)).intValue()).max(); - return rs.isPresent() ? rs.getAsInt() : defResult; - } else if (attrType == long.class || attrType == Long.class || attrType == AtomicLong.class || attrType == LongAdder.class) { - OptionalLong rs = stream.mapToLong(x -> ((Number) attrFunc.apply(x)).longValue()).max(); - return rs.isPresent() ? rs.getAsLong() : defResult; - } else if (attrType == short.class || attrType == Short.class) { - OptionalInt rs = stream.mapToInt(x -> ((Short) attrFunc.apply(x)).intValue()).max(); - return rs.isPresent() ? (short) rs.getAsInt() : defResult; - } else if (attrType == float.class || attrType == Float.class) { - OptionalDouble rs = stream.mapToDouble(x -> ((Float) attrFunc.apply(x)).doubleValue()).max(); - return rs.isPresent() ? (float) rs.getAsDouble() : defResult; - } else if (attrType == double.class || attrType == Double.class) { - OptionalDouble rs = stream.mapToDouble(x -> (Double) attrFunc.apply(x)).max(); - return rs.isPresent() ? rs.getAsDouble() : defResult; - } - throw new RuntimeException("getNumberResult error(type:" + type + ", attr.type: " + attrType); - - case MIN: - if (attrType == int.class || attrType == Integer.class || attrType == AtomicInteger.class) { - OptionalInt rs = stream.mapToInt(x -> ((Number) attrFunc.apply(x)).intValue()).min(); - return rs.isPresent() ? rs.getAsInt() : defResult; - } else if (attrType == long.class || attrType == Long.class || attrType == AtomicLong.class || attrType == LongAdder.class) { - OptionalLong rs = stream.mapToLong(x -> ((Number) attrFunc.apply(x)).longValue()).min(); - return rs.isPresent() ? rs.getAsLong() : defResult; - } else if (attrType == short.class || attrType == Short.class) { - OptionalInt rs = stream.mapToInt(x -> ((Short) attrFunc.apply(x)).intValue()).min(); - return rs.isPresent() ? (short) rs.getAsInt() : defResult; - } else if (attrType == float.class || attrType == Float.class) { - OptionalDouble rs = stream.mapToDouble(x -> ((Float) attrFunc.apply(x)).doubleValue()).min(); - return rs.isPresent() ? (float) rs.getAsDouble() : defResult; - } else if (attrType == double.class || attrType == Double.class) { - OptionalDouble rs = stream.mapToDouble(x -> (Double) attrFunc.apply(x)).min(); - return rs.isPresent() ? rs.getAsDouble() : defResult; - } - throw new RuntimeException("getNumberResult error(type:" + type + ", attr.type: " + attrType); - - case SUM: - if (attrType == int.class || attrType == Integer.class || attrType == AtomicInteger.class) { - return stream.mapToInt(x -> ((Number) attrFunc.apply(x)).intValue()).sum(); - } else if (attrType == long.class || attrType == Long.class || attrType == AtomicLong.class || attrType == LongAdder.class) { - return stream.mapToLong(x -> ((Number) attrFunc.apply(x)).longValue()).sum(); - } else if (attrType == short.class || attrType == Short.class) { - return (short) stream.mapToInt(x -> ((Short) attrFunc.apply(x)).intValue()).sum(); - } else if (attrType == float.class || attrType == Float.class) { - return (float) stream.mapToDouble(x -> ((Float) attrFunc.apply(x)).doubleValue()).sum(); - } else if (attrType == double.class || attrType == Double.class) { - return stream.mapToDouble(x -> (Double) attrFunc.apply(x)).sum(); - } - throw new RuntimeException("getNumberResult error(type:" + type + ", attr.type: " + attrType); - } - return defResult; - } - - public Number getNumberResult(final FilterFunc func, final Number defResult, final String column, final FilterNode node) { - final Attribute attr = column == null ? null : info.getAttribute(column); //COUNT鐨刢olumn=null - final Function attrFunc = attr == null ? null : x -> (Number) attr.get(x); - return getNumberResult(this.list, func, defResult, attr == null ? null : attr.type(), attrFunc, node); - } - - public Sheet querySheet(final SelectColumn selects, final Flipper flipper, final FilterNode node) { - return querySheet(true, false, selects, flipper, node); - } - - protected Stream distinctStream(Stream stream, final List> keyattrs) { - if (keyattrs == null) return stream; - final Set keys = new HashSet<>(); - Predicate filter = t -> { - StringBuilder sb = new StringBuilder(); - for (Attribute attr : keyattrs) { - sb.append(attr.get(t)); - } - String key = sb.toString(); - if (keys.contains(key)) return false; - keys.add(key); - return true; - }; - return stream.filter(filter); - } - - public Sheet querySheet(final boolean needtotal, final boolean distinct, final SelectColumn selects, final Flipper flipper, FilterNode node) { - final Predicate filter = node == null ? null : node.createPredicate(this); - final Comparator comparator = createComparator(flipper); - long total = 0; - List> keyattrs = null; - if (distinct) { - final List> attrs = new ArrayList<>(); - info.forEachAttribute((k, v) -> { - if (selects == null || selects.test(k)) attrs.add(v); - }); - keyattrs = attrs; - } - if (needtotal) { - Stream stream = this.list.stream(); - if (filter != null) stream = stream.filter(filter); - if (distinct) stream = distinctStream(stream, keyattrs); - total = stream.count(); - } - if (needtotal && total == 0) return new Sheet<>(0, new ArrayList()); - Stream stream = this.list.stream(); - if (filter != null) stream = stream.filter(filter); - if (distinct) stream = distinctStream(stream, keyattrs); - if (comparator != null) stream = stream.sorted(comparator); - if (flipper != null && flipper.getOffset() > 0) stream = stream.skip(flipper.getOffset()); - if (flipper != null && flipper.getLimit() > 0) stream = stream.limit(flipper.getLimit()); - final List rs = new ArrayList<>(); - if (selects == null) { - Consumer action = x -> rs.add(needcopy ? newReproduce.apply(creator.create(), x) : x); - if (comparator != null) { - stream.forEachOrdered(action); - } else { - stream.forEach(action); - } - } else { - final List> attrs = new ArrayList<>(); - info.forEachAttribute((k, v) -> { - if (selects.test(k)) attrs.add(v); - }); - Consumer action = x -> { - final T item = creator.create(); - for (Attribute attr : attrs) { - attr.set(item, attr.get(x)); - } - rs.add(item); - }; - if (comparator != null) { - stream.forEachOrdered(action); - } else { - stream.forEach(action); - } - } - if (!needtotal) total = rs.size(); - return new Sheet<>(total, rs); - } - - public int insert(T entity) { - if (entity == null) return 0; - final T rs = newReproduce.apply(this.creator.create(), entity); //纭繚鍚屼竴涓婚敭鍊肩殑map涓巐ist涓殑瀵硅薄蹇呴』鍏辩敤銆 - T old = this.map.putIfAbsent(this.primary.get(rs), rs); - if (old == null) { - this.list.add(rs); - return 1; - } else { - logger.log(Level.WARNING, this.type + " cache repeat insert data: " + entity); - return 0; - } - } - - public int delete(final Serializable pk) { - if (pk == null) return 0; - final T rs = this.map.remove(pk); - if (rs == null) return 0; - this.list.remove(rs); - return 1; - } - - public Serializable[] delete(final Flipper flipper, final FilterNode node) { - if (node == null || this.list.isEmpty()) return new Serializable[0]; - final Comparator comparator = createComparator(flipper); - Stream stream = this.list.stream().filter(node.createPredicate(this)); - if (comparator != null) stream = stream.sorted(comparator); - if (flipper != null && flipper.getOffset() > 0) stream = stream.skip(flipper.getOffset()); - if (flipper != null && flipper.getLimit() > 0) stream = stream.limit(flipper.getLimit()); - Object[] rms = stream.toArray(); - Serializable[] ids = new Serializable[rms.length]; - int i = -1; - for (Object o : rms) { - final T t = (T) o; - ids[++i] = this.primary.get(t); - this.map.remove(ids[i]); - this.list.remove(t); - } - return ids; - } - - public int drop() { - return clear(); - } - - public int update(final T entity) { - if (entity == null) return 0; - T rs = this.map.get(this.primary.get(entity)); - if (rs == null) return 0; - synchronized (rs) { - this.chgReproduce.apply(rs, entity); - } - return 1; - } - - public T update(final T entity, Collection> attrs) { - if (entity == null) return entity; - T rs = this.map.get(this.primary.get(entity)); - if (rs == null) return rs; - synchronized (rs) { - for (Attribute attr : attrs) { - attr.set(rs, attr.get(entity)); - } - } - return rs; - } - - public T[] update(final T entity, final Collection> attrs, final FilterNode node) { - if (entity == null || node == null) return (T[]) Array.newInstance(type, 0); - T[] rms = this.list.stream().filter(node.createPredicate(this)).toArray(len -> (T[]) Array.newInstance(type, len)); - for (T rs : rms) { - synchronized (rs) { - for (Attribute attr : attrs) { - attr.set(rs, attr.get(entity)); - } - } - } - return rms; - } - - public T update(final Serializable pk, Attribute attr, final V fieldValue) { - if (pk == null) return null; - T rs = this.map.get(pk); - if (rs != null) attr.set(rs, fieldValue); - return rs; - } - - public T[] update(Attribute attr, final V fieldValue, final FilterNode node) { - if (attr == null || node == null) return (T[]) Array.newInstance(type, 0); - T[] rms = this.list.stream().filter(node.createPredicate(this)).toArray(len -> (T[]) Array.newInstance(type, len)); - for (T rs : rms) { - attr.set(rs, fieldValue); - } - return rms; - } - - public T updateColumn(final Serializable pk, List> attrs, final List values) { - if (pk == null || attrs == null || attrs.isEmpty()) return null; - T rs = this.map.get(pk); - if (rs == null) return rs; - synchronized (rs) { - for (int i = 0; i < attrs.size(); i++) { - ColumnValue cv = values.get(i); - updateColumn(attrs.get(i), rs, cv.getExpress(), cv.getValue()); - } - } - return rs; - } - - public T[] updateColumn(final FilterNode node, final Flipper flipper, List> attrs, final List values) { - if (attrs == null || attrs.isEmpty() || node == null) return (T[]) Array.newInstance(type, 0); - Stream stream = this.list.stream(); - final Comparator comparator = createComparator(flipper); - if (comparator != null) stream = stream.sorted(comparator); - if (flipper != null && flipper.getLimit() > 0) stream = stream.limit(flipper.getLimit()); - T[] rms = stream.filter(node.createPredicate(this)).toArray(len -> (T[]) Array.newInstance(type, len)); - for (T rs : rms) { - synchronized (rs) { - for (int i = 0; i < attrs.size(); i++) { - ColumnValue cv = values.get(i); - updateColumn(attrs.get(i), rs, cv.getExpress(), cv.getValue()); - } - } - } - return rms; - } - - public T updateColumnOr(final Serializable pk, Attribute attr, final long orvalue) { - if (pk == null) return null; - T rs = this.map.get(pk); - if (rs == null) return rs; - synchronized (rs) { - return updateColumn(attr, rs, ColumnExpress.ORR, orvalue); - } - } - - public T updateColumnAnd(final Serializable pk, Attribute attr, final long andvalue) { - if (pk == null) return null; - T rs = this.map.get(pk); - if (rs == null) return rs; - synchronized (rs) { - return updateColumn(attr, rs, ColumnExpress.AND, andvalue); - } - } - - public T updateColumnIncrement(final Serializable pk, Attribute attr, final long incvalue) { - if (pk == null) return null; - T rs = this.map.get(pk); - if (rs == null) return rs; - synchronized (rs) { - return updateColumn(attr, rs, ColumnExpress.INC, incvalue); - } - } - - public T updateColumnDecrement(final Serializable pk, Attribute attr, final long incvalue) { - if (pk == null) return null; - T rs = this.map.get(pk); - if (rs == null) return rs; - synchronized (rs) { - return updateColumn(attr, rs, ColumnExpress.DEC, incvalue); - } - } - - private T updateColumn(Attribute attr, final T entity, final ColumnExpress express, Serializable val) { - final Class ft = attr.type(); - Number numb = null; - Serializable newval = null; - switch (express) { - case INC: - case DEC: - case MUL: - case DIV: - case MOD: - case AND: - case ORR: - numb = getValue((Number) attr.get(entity), express, val); - break; - case MOV: - if (val instanceof ColumnNodeValue) val = updateColumnNodeValue(attr, entity, (ColumnNodeValue) val); - newval = val; - if (val instanceof Number) numb = (Number) val; - break; - } - if (numb != null) { - if (ft == int.class || ft == Integer.class) { - newval = numb.intValue(); - } else if (ft == long.class || ft == Long.class) { - newval = numb.longValue(); - } else if (ft == short.class || ft == Short.class) { - newval = numb.shortValue(); - } else if (ft == float.class || ft == Float.class) { - newval = numb.floatValue(); - } else if (ft == double.class || ft == Double.class) { - newval = numb.doubleValue(); - } else if (ft == byte.class || ft == Byte.class) { - newval = numb.byteValue(); - } else if (ft == AtomicInteger.class) { - newval = new AtomicInteger(numb.intValue()); - } else if (ft == AtomicLong.class) { - newval = new AtomicLong(numb.longValue()); - } else if (ft == LongAdder.class) { - LongAdder la = new LongAdder(); - la.add(numb.longValue()); - newval = la; - } - } else { - if (ft == AtomicInteger.class && newval != null && newval.getClass() != AtomicInteger.class) { - newval = new AtomicInteger(((Number) newval).intValue()); - } else if (ft == AtomicLong.class && newval != null && newval.getClass() != AtomicLong.class) { - newval = new AtomicLong(((Number) newval).longValue()); - } else if (ft == LongAdder.class && newval != null && newval.getClass() != LongAdder.class) { - LongAdder la = new LongAdder(); - la.add(((Number) newval).longValue()); - newval = la; - } - } - attr.set(entity, (V) newval); - return entity; - } - - private Serializable updateColumnNodeValue(Attribute attr, final T entity, ColumnNodeValue node) { - Serializable left = node.getLeft(); - if (left instanceof CharSequence) { - left = info.getUpdateAttribute(left.toString()).get(entity); - if (node.getExpress() == ColumnExpress.MOV) return left; - } else if (left instanceof ColumnNodeValue) { - left = updateColumnNodeValue(attr, entity, (ColumnNodeValue) left); - } - Serializable right = node.getRight(); - if (left instanceof CharSequence) { - right = info.getUpdateAttribute(right.toString()).get(entity); - } else if (left instanceof ColumnNodeValue) { - right = updateColumnNodeValue(attr, entity, (ColumnNodeValue) right); - } - return getValue((Number) left, node.getExpress(), right); - } - - private Number getValue(Number numb, final ColumnExpress express, Serializable val) { - switch (express) { - case INC: - if (numb == null) { - numb = (Number) val; - } else { - if (numb instanceof Float || ((Number) val) instanceof Float) { - numb = numb.floatValue() + ((Number) val).floatValue(); - } else if (numb instanceof Double || ((Number) val) instanceof Double) { - numb = numb.doubleValue() + ((Number) val).doubleValue(); - } else { - numb = numb.longValue() + ((Number) val).longValue(); - } - } - break; - case DEC: - if (numb == null) { - numb = (Number) val; - } else { - if (numb instanceof Float || ((Number) val) instanceof Float) { - numb = numb.floatValue() - ((Number) val).floatValue(); - } else if (numb instanceof Double || ((Number) val) instanceof Double) { - numb = numb.doubleValue() - ((Number) val).doubleValue(); - } else { - numb = numb.longValue() - ((Number) val).longValue(); - } - } - break; - case MUL: - if (numb == null) { - numb = 0; - } else { - numb = numb.longValue() * ((Number) val).floatValue(); - } - break; - case DIV: - if (numb == null) { - numb = 0; - } else { - numb = numb.longValue() / ((Number) val).floatValue(); - } - break; - case MOD: - if (numb == null) { - numb = 0; - } else { - numb = numb.longValue() % ((Number) val).intValue(); - } - break; - case AND: - if (numb == null) { - numb = 0; - } else { - numb = numb.longValue() & ((Number) val).longValue(); - } - break; - case ORR: - if (numb == null) { - numb = 0; - } else { - numb = numb.longValue() | ((Number) val).longValue(); - } - break; - } - return numb; - } - - public Attribute getAttribute(String fieldname) { - return info.getAttribute(fieldname); - } - - //------------------------------------------------------------------------------------------------------------------------------- - protected Comparator createComparator(Flipper flipper) { - if (flipper == null || flipper.getSort() == null || flipper.getSort().isEmpty() || flipper.getSort().indexOf(';') >= 0 || flipper.getSort().indexOf('\n') >= 0) return null; - final String sort = flipper.getSort(); - Comparator comparator = this.sortComparators.get(sort); - if (comparator != null) return comparator; - for (String item : sort.split(",")) { - if (item.trim().isEmpty()) continue; - String[] sub = item.trim().split("\\s+"); - int pos = sub[0].indexOf('('); - Attribute attr; - if (pos <= 0) { - attr = getAttribute(sub[0]); - } else { //鍚玈QL鍑芥暟 - int pos2 = sub[0].lastIndexOf(')'); - final Attribute pattr = getAttribute(sub[0].substring(pos + 1, pos2)); - final String func = sub[0].substring(0, pos); - if ("ABS".equalsIgnoreCase(func)) { - Function getter = null; - if (pattr.type() == int.class || pattr.type() == Integer.class || pattr.type() == AtomicInteger.class) { - getter = x -> Math.abs(((Number) pattr.get((T) x)).intValue()); - } else if (pattr.type() == long.class || pattr.type() == Long.class || pattr.type() == AtomicLong.class || pattr.type() == LongAdder.class) { - getter = x -> Math.abs(((Number) pattr.get((T) x)).longValue()); - } else if (pattr.type() == float.class || pattr.type() == Float.class) { - getter = x -> Math.abs(((Number) pattr.get((T) x)).floatValue()); - } else if (pattr.type() == double.class || pattr.type() == Double.class) { - getter = x -> Math.abs(((Number) pattr.get((T) x)).doubleValue()); - } else { - throw new RuntimeException("Flipper not supported sort illegal type by ABS (" + flipper.getSort() + ")"); - } - attr = (Attribute) Attribute.create(pattr.declaringClass(), pattr.field(), pattr.type(), getter, (o, v) -> pattr.set(o, v)); - } else if (func.isEmpty()) { - attr = pattr; - } else { - throw new RuntimeException("Flipper not supported sort illegal function (" + flipper.getSort() + ")"); - } - } - Comparator c = (sub.length > 1 && sub[1].equalsIgnoreCase("DESC")) ? (T o1, T o2) -> { - Comparable c1 = (Comparable) attr.get(o1); - Comparable c2 = (Comparable) attr.get(o2); - return c2 == null ? -1 : c2.compareTo(c1); - } : (T o1, T o2) -> { - Comparable c1 = (Comparable) attr.get(o1); - Comparable c2 = (Comparable) attr.get(o2); - return c1 == null ? -1 : c1.compareTo(c2); - }; - - if (comparator == null) { - comparator = c; - } else { - comparator = comparator.thenComparing(c); - } - } - this.sortComparators.put(sort, comparator); - return comparator; - } - - private static class UniqueSequence implements Serializable { - - private final Serializable[] value; - - public UniqueSequence(Serializable[] val) { - this.value = val; - } - - @Override - public int hashCode() { - return Arrays.deepHashCode(this.value); - } - - @Override - public boolean equals(Object obj) { - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; - final UniqueSequence other = (UniqueSequence) obj; - if (value.length != other.value.length) return false; - for (int i = 0; i < value.length; i++) { - if (!value[i].equals(other.value[i])) return false; - } - return true; - } - - } - - private static interface UniqueAttribute extends Predicate { - - public Serializable getValue(T bean); - - @Override - public boolean test(FilterNode node); - - public static UniqueAttribute create(final Attribute[] attributes) { - if (attributes.length == 1) { - final Attribute attribute = attributes[0]; - return new UniqueAttribute() { - - @Override - public Serializable getValue(T bean) { - return attribute.get(bean); - } - - @Override - public boolean test(FilterNode node) { - if (node == null || node.isOr()) return false; - if (!attribute.field().equals(node.column)) return false; - if (node.nodes == null) return true; - for (FilterNode n : node.nodes) { - if (!test(n)) return false; - } - return true; - } - }; - } else { - return new UniqueAttribute() { - - @Override - public Serializable getValue(T bean) { - final Serializable[] rs = new Serializable[attributes.length]; - for (int i = 0; i < rs.length; i++) { - rs[i] = attributes[i].get(bean); - } - return new UniqueSequence(rs); - } - - @Override - public boolean test(FilterNode node) { - return true; - } - }; - } - } - } - -} +/* + * 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.source; + +import java.io.Serializable; +import java.lang.reflect.Array; +import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.*; +import java.util.function.*; +import java.util.logging.*; +import java.util.stream.*; +import javax.persistence.*; +import static org.redkale.source.FilterFunc.*; +import org.redkale.util.*; + +/** + * Entity鏁版嵁鐨勭紦瀛樼被 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Entity绫荤殑娉涘瀷 + */ +@SuppressWarnings("unchecked") +public final class EntityCache { + + //鏃ュ織 + private static final Logger logger = Logger.getLogger(EntityCache.class.getName()); + + //涓婚敭涓庡璞$殑閿煎 + private ConcurrentHashMap map = new ConcurrentHashMap(); + + // CopyOnWriteArrayList 鎻掑叆鎱€佹煡璇㈠揩; 10w鏁版嵁鎻掑叆闇瑕3.2绉; ConcurrentLinkedQueue 鎻掑叆蹇佹煡璇㈡參锛10w鏁版嵁鏌ヨ闇瑕 0.062绉掞紝 鏌ヨ鎱40%; + private Collection list = new ConcurrentLinkedQueue(); + + //Flipper.sort杞崲鎴怌omparator鐨勭紦瀛 + private final Map> sortComparators = new ConcurrentHashMap<>(); + + //Entity绫 + private final Class type; + + //鎺ュ彛杩斿洖鐨勫璞℃槸鍚﹂渶瑕佸鍒朵竴浠 + private final boolean needcopy; + + //Entity鏋勫缓鍣 + private final Creator creator; + + //Entity鏁板兼瀯寤哄櫒 + private final IntFunction arrayer; + + //涓婚敭瀛楁 + private final Attribute primary; + + //鏂板鏃剁殑澶嶅埗鍣紝 鎺掗櫎浜嗘爣璁颁负@Transient鐨勫瓧娈 + private final Reproduce newReproduce; + + //淇敼鏃剁殑澶嶅埗鍣紝 鎺掗櫎浜嗘爣璁颁负@Transient鎴@Column(updatable=false)鐨勫瓧娈 + private final Reproduce chgReproduce; + + //鏄惁宸茬粡鍏ㄩ噺鍔犺浇杩 + private volatile boolean fullloaded; + + private final AtomicBoolean loading = new AtomicBoolean(); + + //Entity淇℃伅 + final EntityInfo info; + + //@Cacheable鐨勫畾鏃舵洿鏂扮鏁帮紝涓0琛ㄧず涓嶅畾鏃舵洿鏂 + final int interval; + + //@Cacheable鐨勫畾鏃跺櫒 + private ScheduledThreadPoolExecutor scheduler; + + private CompletableFuture> loadFuture; + + public EntityCache(final EntityInfo info, final Cacheable c) { + this.info = info; + this.interval = c == null ? 0 : c.interval(); + this.type = info.getType(); + this.arrayer = info.getArrayer(); + this.creator = info.getCreator(); + this.primary = info.primary; + VirtualEntity ve = info.getType().getAnnotation(VirtualEntity.class); + boolean direct = c != null && c.direct(); + if (!direct) direct = ve != null && ve.direct(); + this.needcopy = !direct; + this.newReproduce = Reproduce.create(type, type, (m) -> { + try { + return type.getDeclaredField(m).getAnnotation(Transient.class) == null; + } catch (Exception e) { + return true; + } + }); + this.chgReproduce = Reproduce.create(type, type, (m) -> { + try { + java.lang.reflect.Field field = type.getDeclaredField(m); + if (field.getAnnotation(Transient.class) != null) return false; + Column column = field.getAnnotation(Column.class); + return (column == null || column.updatable()); + } catch (Exception e) { + return true; + } + }); + } + + public CompletableFuture> fullLoadAsync() { + if (this.fullloaded) return this.loadFuture; + if (loading.getAndSet(true)) return this.loadFuture; + if (info.fullloader == null) { + this.list = new ConcurrentLinkedQueue(); + this.map = new ConcurrentHashMap(); + this.fullloaded = true; + loading.set(false); + return this.loadFuture; + } + this.fullloaded = false; + CompletableFuture allFuture = info.fullloader.apply(info.source, info); + this.loadFuture = (CompletableFuture) allFuture; + if (allFuture == null) { + this.list = new ConcurrentLinkedQueue(); + this.map = new ConcurrentHashMap(); + this.fullloaded = true; + loading.set(false); + return this.loadFuture; + } + if (this.interval > 0 && this.scheduler == null && info.fullloader != null) { + this.scheduler = new ScheduledThreadPoolExecutor(1, (Runnable r) -> { + final Thread t = new Thread(r, "Redkale-EntityCache-" + type + "-Thread"); + t.setDaemon(true); + return t; + }); + this.scheduler.scheduleAtFixedRate(() -> { + try { + ConcurrentHashMap newmap2 = new ConcurrentHashMap(); + List all2 = info.fullloader.apply(info.source, info).join(); + if (all2 != null) { + all2.stream().filter(x -> x != null).forEach(x -> { + newmap2.put(this.primary.get(x), x); + }); + } + this.list = all2 == null ? new ConcurrentLinkedQueue() : new ConcurrentLinkedQueue(all2); + this.map = newmap2; + } catch (Throwable t) { + logger.log(Level.SEVERE, type + " schedule(interval=" + interval + "s) Cacheable error", t); + } + }, interval - System.currentTimeMillis() / 1000 % interval, interval, TimeUnit.SECONDS); + } + allFuture.whenComplete((l, t) -> { + if (t != null) { + loading.set(false); + return; + } + List all = l; + ConcurrentHashMap newmap = new ConcurrentHashMap(); + if (all != null) { + all.stream().filter(x -> x != null).forEach(x -> { + newmap.put(this.primary.get(x), x); + }); + } + this.list = new ConcurrentLinkedQueue(all); + this.map = newmap; + this.fullloaded = true; + loading.set(false); + }); + return this.loadFuture; + } + + public Class getType() { + return type; + } + + public int clear() { + this.fullloaded = false; + this.list = new ConcurrentLinkedQueue(); + this.map = new ConcurrentHashMap(); + if (this.scheduler != null) { + this.scheduler.shutdownNow(); + this.scheduler = null; + } + return 1; + } + + public boolean isFullLoaded() { + return fullloaded; + } + + public T find(Serializable pk) { + if (pk == null) return null; + T rs = map.get(pk); + return rs == null ? null : (needcopy ? newReproduce.apply(this.creator.create(), rs) : rs); + } + + public T[] finds(Serializable... pks) { + if (pks == null || pks.length == 0) return arrayer.apply(0); + if (pks.length == 1) { + Class t = pks[0].getClass(); + if (t == int[].class) { + int[] ids = (int[]) pks[0]; + T[] array = arrayer.apply(ids.length); + for (int i = 0; i < array.length; i++) { + T rs = map.get(ids[i]); + array[i] = rs == null ? null : (needcopy ? newReproduce.apply(this.creator.create(), rs) : rs); + } + return array; + } else if (t == long[].class) { + long[] ids = (long[]) pks[0]; + T[] array = arrayer.apply(ids.length); + for (int i = 0; i < array.length; i++) { + T rs = map.get(ids[i]); + array[i] = rs == null ? null : (needcopy ? newReproduce.apply(this.creator.create(), rs) : rs); + } + return array; + } + } + T[] array = arrayer.apply(pks.length); + for (int i = 0; i < array.length; i++) { + T rs = map.get(pks[i]); + array[i] = rs == null ? null : (needcopy ? newReproduce.apply(this.creator.create(), rs) : rs); + } + return array; + } + + public T find(final SelectColumn selects, final Serializable pk) { + if (pk == null) return null; + T rs = map.get(pk); + if (rs == null) return null; + if (selects == null) return (needcopy ? newReproduce.apply(this.creator.create(), rs) : rs); + T t = this.creator.create(); + for (Attribute attr : this.info.attributes) { + if (selects.test(attr.field())) attr.set(t, attr.get(rs)); + } + return t; + } + + public T[] finds(final SelectColumn selects, Serializable... pks) { + if (pks == null || pks.length == 0) return arrayer.apply(0); + final Creator ctr = this.creator; + final Attribute[] attrs = this.info.attributes; + int size = pks.length; + int[] ids1 = null; + long[] ids2 = null; + if (size == 1) { + if (pks[0].getClass() == int[].class) { + ids1 = (int[]) pks[0]; + } else if (pks[0].getClass() == long[].class) { + ids2 = (long[]) pks[0]; + } + } + T[] array = arrayer.apply(size); + for (int i = 0; i < array.length; i++) { + Serializable id = ids1 == null ? (ids2 == null ? pks[i] : ids2[i]) : ids1[i]; + T rs = map.get(id); + if (rs == null) continue; + if (selects == null) { + if (needcopy) rs = newReproduce.apply(ctr.create(), rs); + } else { + T t = ctr.create(); + for (Attribute attr : attrs) { + if (selects.test(attr.field())) attr.set(t, attr.get(rs)); + } + rs = t; + } + array[i] = rs; + } + return array; + } + + public T find(final SelectColumn selects, FilterNode node) { + final Predicate filter = node == null ? null : node.createPredicate(this); + Stream stream = this.list.stream(); + if (filter != null) stream = stream.filter(filter); + Optional opt = stream.findFirst(); + if (!opt.isPresent()) return null; + if (selects == null) return (needcopy ? newReproduce.apply(this.creator.create(), opt.get()) : opt.get()); + T rs = opt.get(); + T t = this.creator.create(); + for (Attribute attr : this.info.attributes) { + if (selects.test(attr.field())) attr.set(t, attr.get(rs)); + } + return t; + } + + public Serializable findColumn(final String column, final Serializable defValue, final Serializable pk) { + if (pk == null) return defValue; + T rs = map.get(pk); + if (rs == null) return defValue; + for (Attribute attr : this.info.attributes) { + if (column.equals(attr.field())) { + Serializable val = (Serializable) attr.get(rs); + return val == null ? defValue : val; + } + } + return defValue; + } + + public Serializable findColumn(final String column, final Serializable defValue, FilterNode node) { + final Predicate filter = node == null ? null : node.createPredicate(this); + Stream stream = this.list.stream(); + if (filter != null) stream = stream.filter(filter); + Optional opt = stream.findFirst(); + if (!opt.isPresent()) return defValue; + T rs = opt.get(); + for (Attribute attr : this.info.attributes) { + if (column.equals(attr.field())) { + Serializable val = (Serializable) attr.get(rs); + return val == null ? defValue : val; + } + } + return defValue; + } + + public boolean exists(Serializable pk) { + if (pk == null) return false; + final Class atype = this.primary.type(); + if (pk.getClass() != atype && pk instanceof Number) { + if (atype == int.class || atype == Integer.class) { + pk = ((Number) pk).intValue(); + } else if (atype == long.class || atype == Long.class) { + pk = ((Number) pk).longValue(); + } else if (atype == short.class || atype == Short.class) { + pk = ((Number) pk).shortValue(); + } else if (atype == float.class || atype == Float.class) { + pk = ((Number) pk).floatValue(); + } else if (atype == byte.class || atype == Byte.class) { + pk = ((Number) pk).byteValue(); + } else if (atype == double.class || atype == Double.class) { + pk = ((Number) pk).doubleValue(); + } else if (atype == AtomicInteger.class) { + pk = new AtomicInteger(((Number) pk).intValue()); + } else if (atype == AtomicLong.class) { + pk = new AtomicLong(((Number) pk).longValue()); + } else if (atype == LongAdder.class) { + LongAdder la = new LongAdder(); + la.add(((Number) pk).longValue()); + pk = la; + } + } + return this.map.containsKey(pk); + } + + public boolean exists(FilterNode node) { + final Predicate filter = node == null ? null : node.createPredicate(this); + Stream stream = this.list.stream(); + if (filter != null) stream = stream.filter(filter); + return stream.findFirst().isPresent(); + } + + public boolean exists(final Predicate filter) { + return (filter != null) && this.list.stream().filter(filter).findFirst().isPresent(); + } + + public Map queryColumnMap(final String keyColumn, final FilterFunc func, final String funcColumn, FilterNode node) { + final Attribute keyAttr = info.getAttribute(keyColumn); + final Predicate filter = node == null ? null : node.createPredicate(this); + final Attribute funcAttr = funcColumn == null ? null : info.getAttribute(funcColumn); + Stream stream = this.list.stream(); + if (filter != null) stream = stream.filter(filter); + Collector collector = null; + final Class valtype = funcAttr == null ? null : funcAttr.type(); + if (func != null) { + switch (func) { + case AVG: + if (valtype == float.class || valtype == Float.class || valtype == double.class || valtype == Double.class) { + collector = (Collector) Collectors.averagingDouble((T t) -> ((Number) funcAttr.get(t)).doubleValue()); + } else { + collector = (Collector) Collectors.averagingLong((T t) -> ((Number) funcAttr.get(t)).longValue()); + } + break; + case COUNT: + collector = (Collector) Collectors.counting(); + break; + case DISTINCTCOUNT: + collector = (Collector) Collectors.mapping((t) -> funcAttr.get(t), Collectors.toSet()); + break; + case MAX: + case MIN: + Comparator comp = (o1, o2) -> o1 == null ? (o2 == null ? 0 : -1) : ((Comparable) funcAttr.get(o1)).compareTo(funcAttr.get(o2)); + collector = (Collector) ((func == MAX) ? Collectors.maxBy(comp) : Collectors.minBy(comp)); + break; + case SUM: + if (valtype == float.class || valtype == Float.class || valtype == double.class || valtype == Double.class) { + collector = (Collector) Collectors.summingDouble((T t) -> ((Number) funcAttr.get(t)).doubleValue()); + } else { + collector = (Collector) Collectors.summingLong((T t) -> ((Number) funcAttr.get(t)).longValue()); + } + break; + } + } + Map rs = collector == null ? stream.collect(Collectors.toMap(t -> keyAttr.get(t), t -> funcAttr.get(t), (key1, key2) -> key2)) + : stream.collect(Collectors.groupingBy(t -> keyAttr.get(t), LinkedHashMap::new, collector)); + if (func == MAX || func == MIN) { + Map rs2 = new LinkedHashMap(); + rs.forEach((x, y) -> { + if (((Optional) y).isPresent()) rs2.put(x, funcAttr.get((T) ((Optional) y).get())); + }); + rs = rs2; + } else if (func == DISTINCTCOUNT) { + Map rs2 = new LinkedHashMap(); + rs.forEach((x, y) -> rs2.put(x, ((Set) y).size() + 0L)); + rs = rs2; + } + return rs; + } + + public Map queryColumnMap(final ColumnNode[] funcNodes, final String[] groupByColumns, FilterNode node) { + final Predicate filter = node == null ? null : node.createPredicate(this); + Stream stream = this.list.stream(); + if (filter != null) stream = stream.filter(filter); + final Attribute[] attrs = new Attribute[groupByColumns.length]; + for (int i = 0; i < groupByColumns.length; i++) { + attrs[i] = info.getAttribute(groupByColumns[i]); + } + final Map valmap = new HashMap<>(); + Function func = t -> { + StringBuilder sb = new StringBuilder(); + final Serializable[] vals = new Serializable[attrs.length]; + for (int i = 0; i < attrs.length; i++) { + vals[i] = attrs[i].get(t); + sb.append((char) 20).append(vals[i]); + } + final String key = sb.toString(); + if (!valmap.containsKey(key)) valmap.put(key, vals); + return valmap.get(key); + }; + Map> listmap = stream.collect(Collectors.groupingBy(func)); + final Map rsmap = new HashMap<>(listmap.size()); + listmap.forEach((k, l) -> rsmap.put(k, queryColumnNumbers(l, funcNodes))); + return rsmap; + } + + private Number[] queryColumnNumbers(final List list, final ColumnNode[] funcNodes) { + if (true) throw new UnsupportedOperationException("Not supported yet."); + Number[] rs = new Number[funcNodes.length]; + for (int i = 0; i < rs.length; i++) { + rs[i] = queryColumnNumber(list, funcNodes[i]); + } + return rs; + } + + private Number queryColumnNumber(final List list, final ColumnNode funcNode) { + if (funcNode instanceof ColumnFuncNode) { + return queryColumnNumber(list, (ColumnFuncNode) funcNode); + } else if (funcNode instanceof ColumnNodeValue) { + return queryColumnNumber(list, (ColumnNodeValue) funcNode); + } else { + return null; + } + } + + private Number queryColumnNumber(final List list, final ColumnFuncNode funcNode) { + if (funcNode.getValue() instanceof String) { + final Attribute attr = info.getAttribute((String) funcNode.getValue()); + final Function attrFunc = x -> (Number) attr.get(x); + return getNumberResult(list, funcNode.getFunc(), null, attr.type(), attrFunc, (FilterNode) null); + } + Number num = null; + if (funcNode.getValue() instanceof ColumnFuncNode) { + num = queryColumnNumber(list, (ColumnFuncNode) funcNode.getValue()); + } else if (funcNode.getValue() instanceof ColumnNodeValue) { + num = queryColumnNumber(list, (ColumnNodeValue) funcNode.getValue()); + } + return num; + } + + private Number queryColumnNumber(final List list, final ColumnNodeValue nodeValue) { + return null; + } + + private Number getNumberResult(final Collection entityList, final FilterFunc func, final Number defResult, final Class attrType, final Function attrFunc, final FilterNode node) { + final Predicate filter = node == null ? null : node.createPredicate(this); + Stream stream = entityList.stream(); + if (filter != null) stream = stream.filter(filter); + switch (func) { + case AVG: + if (attrType == int.class || attrType == Integer.class || attrType == AtomicInteger.class) { + OptionalDouble rs = stream.mapToInt(x -> ((Number) attrFunc.apply(x)).intValue()).average(); + return rs.isPresent() ? (int) rs.getAsDouble() : defResult; + } else if (attrType == long.class || attrType == Long.class || attrType == AtomicLong.class || attrType == LongAdder.class) { + OptionalDouble rs = stream.mapToLong(x -> ((Number) attrFunc.apply(x)).longValue()).average(); + return rs.isPresent() ? (long) rs.getAsDouble() : defResult; + } else if (attrType == short.class || attrType == Short.class) { + OptionalDouble rs = stream.mapToInt(x -> ((Short) attrFunc.apply(x)).intValue()).average(); + return rs.isPresent() ? (short) rs.getAsDouble() : defResult; + } else if (attrType == float.class || attrType == Float.class) { + OptionalDouble rs = stream.mapToDouble(x -> ((Float) attrFunc.apply(x)).doubleValue()).average(); + return rs.isPresent() ? (float) rs.getAsDouble() : defResult; + } else if (attrType == double.class || attrType == Double.class) { + OptionalDouble rs = stream.mapToDouble(x -> (Double) attrFunc.apply(x)).average(); + return rs.isPresent() ? rs.getAsDouble() : defResult; + } + throw new RuntimeException("getNumberResult error(type:" + type + ", attr.type: " + attrType); + case COUNT: + return stream.count(); + case DISTINCTCOUNT: + return stream.map(x -> attrFunc.apply(x)).distinct().count(); + + case MAX: + if (attrType == int.class || attrType == Integer.class || attrType == AtomicInteger.class) { + OptionalInt rs = stream.mapToInt(x -> ((Number) attrFunc.apply(x)).intValue()).max(); + return rs.isPresent() ? rs.getAsInt() : defResult; + } else if (attrType == long.class || attrType == Long.class || attrType == AtomicLong.class || attrType == LongAdder.class) { + OptionalLong rs = stream.mapToLong(x -> ((Number) attrFunc.apply(x)).longValue()).max(); + return rs.isPresent() ? rs.getAsLong() : defResult; + } else if (attrType == short.class || attrType == Short.class) { + OptionalInt rs = stream.mapToInt(x -> ((Short) attrFunc.apply(x)).intValue()).max(); + return rs.isPresent() ? (short) rs.getAsInt() : defResult; + } else if (attrType == float.class || attrType == Float.class) { + OptionalDouble rs = stream.mapToDouble(x -> ((Float) attrFunc.apply(x)).doubleValue()).max(); + return rs.isPresent() ? (float) rs.getAsDouble() : defResult; + } else if (attrType == double.class || attrType == Double.class) { + OptionalDouble rs = stream.mapToDouble(x -> (Double) attrFunc.apply(x)).max(); + return rs.isPresent() ? rs.getAsDouble() : defResult; + } + throw new RuntimeException("getNumberResult error(type:" + type + ", attr.type: " + attrType); + + case MIN: + if (attrType == int.class || attrType == Integer.class || attrType == AtomicInteger.class) { + OptionalInt rs = stream.mapToInt(x -> ((Number) attrFunc.apply(x)).intValue()).min(); + return rs.isPresent() ? rs.getAsInt() : defResult; + } else if (attrType == long.class || attrType == Long.class || attrType == AtomicLong.class || attrType == LongAdder.class) { + OptionalLong rs = stream.mapToLong(x -> ((Number) attrFunc.apply(x)).longValue()).min(); + return rs.isPresent() ? rs.getAsLong() : defResult; + } else if (attrType == short.class || attrType == Short.class) { + OptionalInt rs = stream.mapToInt(x -> ((Short) attrFunc.apply(x)).intValue()).min(); + return rs.isPresent() ? (short) rs.getAsInt() : defResult; + } else if (attrType == float.class || attrType == Float.class) { + OptionalDouble rs = stream.mapToDouble(x -> ((Float) attrFunc.apply(x)).doubleValue()).min(); + return rs.isPresent() ? (float) rs.getAsDouble() : defResult; + } else if (attrType == double.class || attrType == Double.class) { + OptionalDouble rs = stream.mapToDouble(x -> (Double) attrFunc.apply(x)).min(); + return rs.isPresent() ? rs.getAsDouble() : defResult; + } + throw new RuntimeException("getNumberResult error(type:" + type + ", attr.type: " + attrType); + + case SUM: + if (attrType == int.class || attrType == Integer.class || attrType == AtomicInteger.class) { + return stream.mapToInt(x -> ((Number) attrFunc.apply(x)).intValue()).sum(); + } else if (attrType == long.class || attrType == Long.class || attrType == AtomicLong.class || attrType == LongAdder.class) { + return stream.mapToLong(x -> ((Number) attrFunc.apply(x)).longValue()).sum(); + } else if (attrType == short.class || attrType == Short.class) { + return (short) stream.mapToInt(x -> ((Short) attrFunc.apply(x)).intValue()).sum(); + } else if (attrType == float.class || attrType == Float.class) { + return (float) stream.mapToDouble(x -> ((Float) attrFunc.apply(x)).doubleValue()).sum(); + } else if (attrType == double.class || attrType == Double.class) { + return stream.mapToDouble(x -> (Double) attrFunc.apply(x)).sum(); + } + throw new RuntimeException("getNumberResult error(type:" + type + ", attr.type: " + attrType); + } + return defResult; + } + + public Number getNumberResult(final FilterFunc func, final Number defResult, final String column, final FilterNode node) { + final Attribute attr = column == null ? null : info.getAttribute(column); //COUNT鐨刢olumn=null + final Function attrFunc = attr == null ? null : x -> (Number) attr.get(x); + return getNumberResult(this.list, func, defResult, attr == null ? null : attr.type(), attrFunc, node); + } + + public Sheet querySheet(final SelectColumn selects, final Flipper flipper, final FilterNode node) { + return querySheet(true, false, selects, flipper, node); + } + + protected Stream distinctStream(Stream stream, final List> keyattrs) { + if (keyattrs == null) return stream; + final Set keys = new HashSet<>(); + Predicate filter = t -> { + StringBuilder sb = new StringBuilder(); + for (Attribute attr : keyattrs) { + sb.append(attr.get(t)); + } + String key = sb.toString(); + if (keys.contains(key)) return false; + keys.add(key); + return true; + }; + return stream.filter(filter); + } + + public Sheet querySheet(final boolean needtotal, final boolean distinct, final SelectColumn selects, final Flipper flipper, FilterNode node) { + final Predicate filter = node == null ? null : node.createPredicate(this); + final Comparator comparator = createComparator(flipper); + long total = 0; + List> keyattrs = null; + if (distinct) { + final List> attrs = new ArrayList<>(); + info.forEachAttribute((k, v) -> { + if (selects == null || selects.test(k)) attrs.add(v); + }); + keyattrs = attrs; + } + if (needtotal) { + Stream stream = this.list.stream(); + if (filter != null) stream = stream.filter(filter); + if (distinct) stream = distinctStream(stream, keyattrs); + total = stream.count(); + } + if (needtotal && total == 0) return new Sheet<>(0, new ArrayList()); + Stream stream = this.list.stream(); + if (filter != null) stream = stream.filter(filter); + if (distinct) stream = distinctStream(stream, keyattrs); + if (comparator != null) stream = stream.sorted(comparator); + if (flipper != null && flipper.getOffset() > 0) stream = stream.skip(flipper.getOffset()); + if (flipper != null && flipper.getLimit() > 0) stream = stream.limit(flipper.getLimit()); + final List rs = new ArrayList<>(); + if (selects == null) { + Consumer action = x -> rs.add(needcopy ? newReproduce.apply(creator.create(), x) : x); + if (comparator != null) { + stream.forEachOrdered(action); + } else { + stream.forEach(action); + } + } else { + final List> attrs = new ArrayList<>(); + info.forEachAttribute((k, v) -> { + if (selects.test(k)) attrs.add(v); + }); + Consumer action = x -> { + final T item = creator.create(); + for (Attribute attr : attrs) { + attr.set(item, attr.get(x)); + } + rs.add(item); + }; + if (comparator != null) { + stream.forEachOrdered(action); + } else { + stream.forEach(action); + } + } + if (!needtotal) total = rs.size(); + return new Sheet<>(total, rs); + } + + public int insert(T entity) { + if (entity == null) return 0; + final T rs = newReproduce.apply(this.creator.create(), entity); //纭繚鍚屼竴涓婚敭鍊肩殑map涓巐ist涓殑瀵硅薄蹇呴』鍏辩敤銆 + T old = this.map.putIfAbsent(this.primary.get(rs), rs); + if (old == null) { + this.list.add(rs); + return 1; + } else { + logger.log(Level.WARNING, this.type + " cache repeat insert data: " + entity); + return 0; + } + } + + public int delete(final Serializable pk) { + if (pk == null) return 0; + final T rs = this.map.remove(pk); + if (rs == null) return 0; + this.list.remove(rs); + return 1; + } + + public Serializable[] delete(final Flipper flipper, final FilterNode node) { + if (node == null || this.list.isEmpty()) return new Serializable[0]; + final Comparator comparator = createComparator(flipper); + Stream stream = this.list.stream().filter(node.createPredicate(this)); + if (comparator != null) stream = stream.sorted(comparator); + if (flipper != null && flipper.getOffset() > 0) stream = stream.skip(flipper.getOffset()); + if (flipper != null && flipper.getLimit() > 0) stream = stream.limit(flipper.getLimit()); + Object[] rms = stream.toArray(); + Serializable[] ids = new Serializable[rms.length]; + int i = -1; + for (Object o : rms) { + final T t = (T) o; + ids[++i] = this.primary.get(t); + this.map.remove(ids[i]); + this.list.remove(t); + } + return ids; + } + + public int drop() { + return clear(); + } + + public int update(final T entity) { + if (entity == null) return 0; + T rs = this.map.get(this.primary.get(entity)); + if (rs == null) return 0; + synchronized (rs) { + this.chgReproduce.apply(rs, entity); + } + return 1; + } + + public T update(final T entity, Collection> attrs) { + if (entity == null) return entity; + T rs = this.map.get(this.primary.get(entity)); + if (rs == null) return rs; + synchronized (rs) { + for (Attribute attr : attrs) { + attr.set(rs, attr.get(entity)); + } + } + return rs; + } + + public T[] update(final T entity, final Collection> attrs, final FilterNode node) { + if (entity == null || node == null) return (T[]) Array.newInstance(type, 0); + T[] rms = this.list.stream().filter(node.createPredicate(this)).toArray(len -> (T[]) Array.newInstance(type, len)); + for (T rs : rms) { + synchronized (rs) { + for (Attribute attr : attrs) { + attr.set(rs, attr.get(entity)); + } + } + } + return rms; + } + + public T update(final Serializable pk, Attribute attr, final V fieldValue) { + if (pk == null) return null; + T rs = this.map.get(pk); + if (rs != null) attr.set(rs, fieldValue); + return rs; + } + + public T[] update(Attribute attr, final V fieldValue, final FilterNode node) { + if (attr == null || node == null) return (T[]) Array.newInstance(type, 0); + T[] rms = this.list.stream().filter(node.createPredicate(this)).toArray(len -> (T[]) Array.newInstance(type, len)); + for (T rs : rms) { + attr.set(rs, fieldValue); + } + return rms; + } + + public T updateColumn(final Serializable pk, List> attrs, final List values) { + if (pk == null || attrs == null || attrs.isEmpty()) return null; + T rs = this.map.get(pk); + if (rs == null) return rs; + synchronized (rs) { + for (int i = 0; i < attrs.size(); i++) { + ColumnValue cv = values.get(i); + updateColumn(attrs.get(i), rs, cv.getExpress(), cv.getValue()); + } + } + return rs; + } + + public T[] updateColumn(final FilterNode node, final Flipper flipper, List> attrs, final List values) { + if (attrs == null || attrs.isEmpty() || node == null) return (T[]) Array.newInstance(type, 0); + Stream stream = this.list.stream(); + final Comparator comparator = createComparator(flipper); + if (comparator != null) stream = stream.sorted(comparator); + if (flipper != null && flipper.getLimit() > 0) stream = stream.limit(flipper.getLimit()); + T[] rms = stream.filter(node.createPredicate(this)).toArray(len -> (T[]) Array.newInstance(type, len)); + for (T rs : rms) { + synchronized (rs) { + for (int i = 0; i < attrs.size(); i++) { + ColumnValue cv = values.get(i); + updateColumn(attrs.get(i), rs, cv.getExpress(), cv.getValue()); + } + } + } + return rms; + } + + public T updateColumnOr(final Serializable pk, Attribute attr, final long orvalue) { + if (pk == null) return null; + T rs = this.map.get(pk); + if (rs == null) return rs; + synchronized (rs) { + return updateColumn(attr, rs, ColumnExpress.ORR, orvalue); + } + } + + public T updateColumnAnd(final Serializable pk, Attribute attr, final long andvalue) { + if (pk == null) return null; + T rs = this.map.get(pk); + if (rs == null) return rs; + synchronized (rs) { + return updateColumn(attr, rs, ColumnExpress.AND, andvalue); + } + } + + public T updateColumnIncrement(final Serializable pk, Attribute attr, final long incvalue) { + if (pk == null) return null; + T rs = this.map.get(pk); + if (rs == null) return rs; + synchronized (rs) { + return updateColumn(attr, rs, ColumnExpress.INC, incvalue); + } + } + + public T updateColumnDecrement(final Serializable pk, Attribute attr, final long incvalue) { + if (pk == null) return null; + T rs = this.map.get(pk); + if (rs == null) return rs; + synchronized (rs) { + return updateColumn(attr, rs, ColumnExpress.DEC, incvalue); + } + } + + private T updateColumn(Attribute attr, final T entity, final ColumnExpress express, Serializable val) { + final Class ft = attr.type(); + Number numb = null; + Serializable newval = null; + switch (express) { + case INC: + case DEC: + case MUL: + case DIV: + case MOD: + case AND: + case ORR: + numb = getValue((Number) attr.get(entity), express, val); + break; + case MOV: + if (val instanceof ColumnNodeValue) val = updateColumnNodeValue(attr, entity, (ColumnNodeValue) val); + newval = val; + if (val instanceof Number) numb = (Number) val; + break; + } + if (numb != null) { + if (ft == int.class || ft == Integer.class) { + newval = numb.intValue(); + } else if (ft == long.class || ft == Long.class) { + newval = numb.longValue(); + } else if (ft == short.class || ft == Short.class) { + newval = numb.shortValue(); + } else if (ft == float.class || ft == Float.class) { + newval = numb.floatValue(); + } else if (ft == double.class || ft == Double.class) { + newval = numb.doubleValue(); + } else if (ft == byte.class || ft == Byte.class) { + newval = numb.byteValue(); + } else if (ft == AtomicInteger.class) { + newval = new AtomicInteger(numb.intValue()); + } else if (ft == AtomicLong.class) { + newval = new AtomicLong(numb.longValue()); + } else if (ft == LongAdder.class) { + LongAdder la = new LongAdder(); + la.add(numb.longValue()); + newval = la; + } + } else { + if (ft == AtomicInteger.class && newval != null && newval.getClass() != AtomicInteger.class) { + newval = new AtomicInteger(((Number) newval).intValue()); + } else if (ft == AtomicLong.class && newval != null && newval.getClass() != AtomicLong.class) { + newval = new AtomicLong(((Number) newval).longValue()); + } else if (ft == LongAdder.class && newval != null && newval.getClass() != LongAdder.class) { + LongAdder la = new LongAdder(); + la.add(((Number) newval).longValue()); + newval = la; + } + } + attr.set(entity, (V) newval); + return entity; + } + + private Serializable updateColumnNodeValue(Attribute attr, final T entity, ColumnNodeValue node) { + Serializable left = node.getLeft(); + if (left instanceof CharSequence) { + left = info.getUpdateAttribute(left.toString()).get(entity); + if (node.getExpress() == ColumnExpress.MOV) return left; + } else if (left instanceof ColumnNodeValue) { + left = updateColumnNodeValue(attr, entity, (ColumnNodeValue) left); + } + Serializable right = node.getRight(); + if (left instanceof CharSequence) { + right = info.getUpdateAttribute(right.toString()).get(entity); + } else if (left instanceof ColumnNodeValue) { + right = updateColumnNodeValue(attr, entity, (ColumnNodeValue) right); + } + return getValue((Number) left, node.getExpress(), right); + } + + private Number getValue(Number numb, final ColumnExpress express, Serializable val) { + switch (express) { + case INC: + if (numb == null) { + numb = (Number) val; + } else { + if (numb instanceof Float || ((Number) val) instanceof Float) { + numb = numb.floatValue() + ((Number) val).floatValue(); + } else if (numb instanceof Double || ((Number) val) instanceof Double) { + numb = numb.doubleValue() + ((Number) val).doubleValue(); + } else { + numb = numb.longValue() + ((Number) val).longValue(); + } + } + break; + case DEC: + if (numb == null) { + numb = (Number) val; + } else { + if (numb instanceof Float || ((Number) val) instanceof Float) { + numb = numb.floatValue() - ((Number) val).floatValue(); + } else if (numb instanceof Double || ((Number) val) instanceof Double) { + numb = numb.doubleValue() - ((Number) val).doubleValue(); + } else { + numb = numb.longValue() - ((Number) val).longValue(); + } + } + break; + case MUL: + if (numb == null) { + numb = 0; + } else { + numb = numb.longValue() * ((Number) val).floatValue(); + } + break; + case DIV: + if (numb == null) { + numb = 0; + } else { + numb = numb.longValue() / ((Number) val).floatValue(); + } + break; + case MOD: + if (numb == null) { + numb = 0; + } else { + numb = numb.longValue() % ((Number) val).intValue(); + } + break; + case AND: + if (numb == null) { + numb = 0; + } else { + numb = numb.longValue() & ((Number) val).longValue(); + } + break; + case ORR: + if (numb == null) { + numb = 0; + } else { + numb = numb.longValue() | ((Number) val).longValue(); + } + break; + } + return numb; + } + + public Attribute getAttribute(String fieldname) { + return info.getAttribute(fieldname); + } + + //------------------------------------------------------------------------------------------------------------------------------- + protected Comparator createComparator(Flipper flipper) { + if (flipper == null || flipper.getSort() == null || flipper.getSort().isEmpty() || flipper.getSort().indexOf(';') >= 0 || flipper.getSort().indexOf('\n') >= 0) return null; + final String sort = flipper.getSort(); + Comparator comparator = this.sortComparators.get(sort); + if (comparator != null) return comparator; + for (String item : sort.split(",")) { + if (item.trim().isEmpty()) continue; + String[] sub = item.trim().split("\\s+"); + int pos = sub[0].indexOf('('); + Attribute attr; + if (pos <= 0) { + attr = getAttribute(sub[0]); + } else { //鍚玈QL鍑芥暟 + int pos2 = sub[0].lastIndexOf(')'); + final Attribute pattr = getAttribute(sub[0].substring(pos + 1, pos2)); + final String func = sub[0].substring(0, pos); + if ("ABS".equalsIgnoreCase(func)) { + Function getter = null; + if (pattr.type() == int.class || pattr.type() == Integer.class || pattr.type() == AtomicInteger.class) { + getter = x -> Math.abs(((Number) pattr.get((T) x)).intValue()); + } else if (pattr.type() == long.class || pattr.type() == Long.class || pattr.type() == AtomicLong.class || pattr.type() == LongAdder.class) { + getter = x -> Math.abs(((Number) pattr.get((T) x)).longValue()); + } else if (pattr.type() == float.class || pattr.type() == Float.class) { + getter = x -> Math.abs(((Number) pattr.get((T) x)).floatValue()); + } else if (pattr.type() == double.class || pattr.type() == Double.class) { + getter = x -> Math.abs(((Number) pattr.get((T) x)).doubleValue()); + } else { + throw new RuntimeException("Flipper not supported sort illegal type by ABS (" + flipper.getSort() + ")"); + } + attr = (Attribute) Attribute.create(pattr.declaringClass(), pattr.field(), pattr.type(), getter, (o, v) -> pattr.set(o, v)); + } else if (func.isEmpty()) { + attr = pattr; + } else { + throw new RuntimeException("Flipper not supported sort illegal function (" + flipper.getSort() + ")"); + } + } + Comparator c = (sub.length > 1 && sub[1].equalsIgnoreCase("DESC")) ? (T o1, T o2) -> { + Comparable c1 = (Comparable) attr.get(o1); + Comparable c2 = (Comparable) attr.get(o2); + return c2 == null ? -1 : c2.compareTo(c1); + } : (T o1, T o2) -> { + Comparable c1 = (Comparable) attr.get(o1); + Comparable c2 = (Comparable) attr.get(o2); + return c1 == null ? -1 : c1.compareTo(c2); + }; + + if (comparator == null) { + comparator = c; + } else { + comparator = comparator.thenComparing(c); + } + } + this.sortComparators.put(sort, comparator); + return comparator; + } + + private static class UniqueSequence implements Serializable { + + private final Serializable[] value; + + public UniqueSequence(Serializable[] val) { + this.value = val; + } + + @Override + public int hashCode() { + return Arrays.deepHashCode(this.value); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + final UniqueSequence other = (UniqueSequence) obj; + if (value.length != other.value.length) return false; + for (int i = 0; i < value.length; i++) { + if (!value[i].equals(other.value[i])) return false; + } + return true; + } + + } + + private static interface UniqueAttribute extends Predicate { + + public Serializable getValue(T bean); + + @Override + public boolean test(FilterNode node); + + public static UniqueAttribute create(final Attribute[] attributes) { + if (attributes.length == 1) { + final Attribute attribute = attributes[0]; + return new UniqueAttribute() { + + @Override + public Serializable getValue(T bean) { + return attribute.get(bean); + } + + @Override + public boolean test(FilterNode node) { + if (node == null || node.isOr()) return false; + if (!attribute.field().equals(node.column)) return false; + if (node.nodes == null) return true; + for (FilterNode n : node.nodes) { + if (!test(n)) return false; + } + return true; + } + }; + } else { + return new UniqueAttribute() { + + @Override + public Serializable getValue(T bean) { + final Serializable[] rs = new Serializable[attributes.length]; + for (int i = 0; i < rs.length; i++) { + rs[i] = attributes[i].get(bean); + } + return new UniqueSequence(rs); + } + + @Override + public boolean test(FilterNode node) { + return true; + } + }; + } + } + } + +} diff --git a/src/main/java/org/redkale/source/EntityInfo.java b/src/main/java/org/redkale/source/EntityInfo.java index bb493fd5b..3f224b1aa 100644 --- a/src/main/java/org/redkale/source/EntityInfo.java +++ b/src/main/java/org/redkale/source/EntityInfo.java @@ -1,1396 +1,1396 @@ -/* - * 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.source; - -import java.io.Serializable; -import java.lang.reflect.*; -import java.util.*; -import java.util.concurrent.*; -import java.util.function.*; -import java.util.logging.*; -import javax.persistence.*; -import org.redkale.convert.json.*; -import org.redkale.util.*; - -/** - * Entity鎿嶄綔绫 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Entity绫荤殑娉涘瀷 - */ -@SuppressWarnings("unchecked") -public final class EntityInfo { - - private static final JsonConvert DEFAULT_JSON_CONVERT = JsonFactory.create().skipAllIgnore(true).getConvert(); - - //鍏ㄥ眬闈欐佽祫婧 - private static final ConcurrentHashMap entityInfos = new ConcurrentHashMap<>(); - - //鏃ュ織 - private static final Logger logger = Logger.getLogger(EntityInfo.class.getSimpleName()); - - //Entity绫诲悕 - private final Class type; - - //绫诲搴旂殑鏁版嵁琛ㄥ悕, 濡傛灉鏄疺irtualEntity 绫伙紝 鍒欒瀛楁涓簄ull - final String table; - - //JsonConvert - final JsonConvert jsonConvert; - - //Entity鏋勫缓鍣 - private final Creator creator; - - //Entity鏁板兼瀯寤哄櫒 - private final IntFunction arrayer; - - //Entity鏋勫缓鍣ㄥ弬鏁 - private final String[] constructorParameters; - - //Entity鏋勫缓鍣ㄥ弬鏁癆ttribute锛 鏁扮粍涓暟涓巆onstructorParameters鐩稿悓 - final Attribute[] constructorAttributes; - - //Entity鏋勫缓鍣ㄥ弬鏁癆ttribute - final Attribute[] unconstructorAttributes; - - //涓婚敭 - final Attribute primary; - - //DDL瀛楁闆嗗悎 - final EntityColumn[] ddlColumns; - - //Entity缂撳瓨瀵硅薄 - private final EntityCache cache; - - //鐢ㄤ簬瀛樺偍缁戝畾鍦‥ntityInfo涓婄殑瀵硅薄 - private final ConcurrentHashMap subobjectMap = new ConcurrentHashMap<>(); - - //key鏄痜ield鐨刵ame锛 涓嶆槸sql瀛楁銆 - //瀛樻斁鎵鏈変笌鏁版嵁搴撳搴旂殑瀛楁锛 鍖呮嫭涓婚敭 - private final HashMap> attributeMap = new HashMap<>(); - - //瀛樻斁鎵鏈変笌鏁版嵁搴撳搴旂殑瀛楁锛 鍖呮嫭涓婚敭 - final Attribute[] attributes; - - //key鏄痜ield鐨刵ame锛 value鏄疌olumn鐨勫埆鍚嶏紝鍗虫暟鎹簱琛ㄧ殑瀛楁鍚 - //鍙湁field.name 涓 Column.name涓嶅悓鎵嶅瓨鏀惧湪aliasmap閲. - private final Map aliasmap; - - //key鏄痜ield鐨刵ame锛 value鏄疌ryptHandler - //瀛楁閮戒笉瀛樺湪CryptHandler鏃跺煎洜涓轰负null锛屽噺灏戝垽鏂 - private final Map cryptmap; - - //鎵鏈夊彲鏇存柊瀛楁锛屽嵆鎺掗櫎浜嗕富閿瓧娈靛拰鏍囪涓@Column(updatable=false)鐨勫瓧娈 - private final Map> updateAttributeMap = new HashMap<>(); - - //鐢ㄤ簬瀛樺湪database.table_20160202绫讳技杩欑鍒嗗竷寮忚〃 - private final Set tables = new CopyOnWriteArraySet<>(); - - //涓嶈兘涓簄ull鐨勫瓧娈靛悕 - private final Set notNullColumns = new CopyOnWriteArraySet<>(); - - //鍒嗚〃 绛栫暐 - private final DistributeTableStrategy tableStrategy; - - //鏍规嵁涓婚敭鏌ユ壘鎵鏈夊璞$殑SQL - private final String allQueryPrepareSQL; - - //鏍规嵁涓婚敭鏌ユ壘鍗曚釜瀵硅薄鐨凷QL锛 鍚 锛 - private final String findQuestionPrepareSQL; - - //鏍规嵁涓婚敭鏌ユ壘鍗曚釜瀵硅薄鐨凷QL锛 鍚 $ - private final String findDollarPrepareSQL; - - //鏍规嵁涓婚敭鏌ユ壘鍗曚釜瀵硅薄鐨凷QL锛 鍚 :name - private final String findNamesPrepareSQL; - - //鏁版嵁搴撲腑鎵鏈夊瓧娈 - private final String[] querySqlColumns; - - private final String querySqlColumnSequence; - - private final String querySqlColumnSequenceA; - - //鏁版嵁搴撲腑鎵鏈夊瓧娈, 椤哄簭蹇呴』涓巕uerySqlColumns銆乹uerySqlColumnSequence涓鑷 - private final Attribute[] queryAttributes; - - //鏂板SQL锛 鍚 锛燂紝鍗虫帓闄や簡鑷闀夸富閿拰鏍囪涓@Column(insertable=false)鐨勫瓧娈 - private final String insertQuestionPrepareSQL; - - //鏂板SQL锛 鍚 $锛屽嵆鎺掗櫎浜嗚嚜澧為暱涓婚敭鍜屾爣璁颁负@Column(insertable=false)鐨勫瓧娈 - private final String insertDollarPrepareSQL; - - //鏂板SQL锛 鍚 :name锛屽嵆鎺掗櫎浜嗚嚜澧為暱涓婚敭鍜屾爣璁颁负@Column(insertable=false)鐨勫瓧娈 - private final String insertNamesPrepareSQL; - - //鏁版嵁搴撲腑鎵鏈夊彲鏂板瀛楁 - final Attribute[] insertAttributes; - - //鏍规嵁涓婚敭鏇存柊鎵鏈夊彲鏇存柊瀛楁鐨凷QL锛屽惈 锛 - private final String updateQuestionPrepareSQL; - - //鏍规嵁涓婚敭鏇存柊鎵鏈夊彲鏇存柊瀛楁鐨凷QL锛屽惈 $ - private final String updateDollarPrepareSQL; - - //鏍规嵁涓婚敭鏇存柊鎵鏈夊彲鏇存柊瀛楁鐨凷QL锛屽惈 :name - private final String updateNamesPrepareSQL; - - //鏁版嵁搴撲腑鎵鏈夊彲鏇存柊瀛楁 - final Attribute[] updateAttributes; - - //鏍规嵁涓婚敭鍒犻櫎璁板綍鐨凷QL锛屽惈 锛 - private final String deleteQuestionPrepareSQL; - - //鏍规嵁涓婚敭鍒犻櫎璁板綍鐨凷QL锛屽惈 $ - private final String deleteDollarPrepareSQL; - - //鏍规嵁涓婚敭鍒犻櫎璁板綍鐨凷QL锛屽惈 :name - private final String deleteNamesPrepareSQL; - - //鏃ュ織绾у埆锛屼粠LogLevel鑾峰彇 - private final int logLevel; - - //鏃ュ織鎺у埗 - private final Map excludeLogLevels; - - //Flipper.sort杞崲鎴愪互ORDER BY寮澶碨QL鐨勭紦瀛 - private final Map sortOrderbySqls = new ConcurrentHashMap<>(); - - //鎵灞炵殑DataSource - final DataSource source; - - //鍏ㄩ噺鏁版嵁鐨勫姞杞藉櫒 - final BiFunction> fullloader; - //------------------------------------------------------------ - - /** - * 鍔犺浇EntityInfo - * - * @param clazz Entity绫 - * @param cacheForbidden 鏄惁绂佺敤EntityCache - * @param conf 閰嶇疆淇℃伅, persistence.xml涓殑property鑺傜偣鍊 - * @param source DataSource,鍙负null - * @param fullloader 鍏ㄩ噺鍔犺浇鍣,鍙负null - */ - static EntityInfo load(Class clazz, final boolean cacheForbidden, final Properties conf, - DataSource source, BiFunction> fullloader) { - EntityInfo rs = entityInfos.get(clazz); - if (rs != null && (rs.cache == null || rs.cache.isFullLoaded())) return rs; - synchronized (entityInfos) { - rs = entityInfos.get(clazz); - if (rs == null) { - rs = new EntityInfo(clazz, cacheForbidden, conf, source, fullloader); - entityInfos.put(clazz, rs); - } - if (rs.cache != null && !rs.isCacheFullLoaded()) { - if (fullloader == null) throw new IllegalArgumentException(clazz.getName() + " auto loader is illegal"); - rs.cache.fullLoadAsync(); - } - return rs; - } - } - - /** - * 鑾峰彇Entity绫诲搴旂殑EntityInfo瀵硅薄 - * - * @param 娉涘瀷 - * @param clazz Entity绫 - * - * @return EntityInfo - */ - static EntityInfo get(Class clazz) { - return entityInfos.get(clazz); - } - - /** - * 缁橮repareCompiler浣跨敤锛岀敤浜庨鍔ㄦ佺敓鎴怉ttribute - * - * @since 2.5.0 - * @param 娉涘瀷 - * @param clazz Entity瀹炰綋绫 - * @param source 鏁版嵁婧 - * - * @return EntityInfo - */ - public static EntityInfo compile(Class clazz, DataSource source) { - return new EntityInfo<>(clazz, false, null, source, (BiFunction) null); - } - - /** - * 鏋勯犲嚱鏁 - * - * @param type Entity绫 - * @param cacheForbidden 鏄惁绂佺敤EntityCache - * @param conf 閰嶇疆淇℃伅, persistence.xml涓殑property鑺傜偣鍊 - * @param source DataSource,鍙负null - * @param fullloader 鍏ㄩ噺鍔犺浇鍣,鍙负null - */ - private EntityInfo(Class type, final boolean cacheForbidden, - Properties conf, DataSource source, BiFunction> fullloader) { - this.type = type; - this.source = source; - //--------------------------------------------- - - LogLevel ll = type.getAnnotation(LogLevel.class); - this.logLevel = ll == null ? Integer.MIN_VALUE : Level.parse(ll.value()).intValue(); - Map> logmap = new HashMap<>(); - for (LogExcludeLevel lel : type.getAnnotationsByType(LogExcludeLevel.class)) { - for (String onelevel : lel.levels()) { - int level = Level.parse(onelevel).intValue(); - HashSet set = logmap.get(level); - if (set == null) { - set = new HashSet<>(); - logmap.put(level, set); - } - for (String key : lel.keys()) { - set.add(key); - } - } - } - if (logmap.isEmpty()) { - this.excludeLogLevels = null; - } else { - this.excludeLogLevels = new HashMap<>(); - logmap.forEach((l, set) -> excludeLogLevels.put(l, set.toArray(new String[set.size()]))); - } - //--------------------------------------------- - Table t = type.getAnnotation(Table.class); - if (type.getAnnotation(VirtualEntity.class) != null || (source == null || "memory".equalsIgnoreCase(source.getType()))) { - this.table = null; - BiFunction> loader = null; - try { - VirtualEntity ve = type.getAnnotation(VirtualEntity.class); - if (ve != null) { - loader = ve.loader().getDeclaredConstructor().newInstance(); - RedkaleClassLoader.putReflectionDeclaredConstructors(ve.loader(), ve.loader().getName()); - } - } catch (Exception e) { - logger.log(Level.SEVERE, type + " init @VirtualEntity.loader error", e); - } - this.fullloader = loader; - } else { - this.fullloader = fullloader; - if (t != null && !t.name().isEmpty() && t.name().indexOf('.') >= 0) throw new RuntimeException(type + " have illegal table.name on @Table"); - this.table = (t == null) ? type.getSimpleName().toLowerCase() : (t.catalog().isEmpty()) ? (t.name().isEmpty() ? type.getSimpleName().toLowerCase() : t.name()) : (t.catalog() + '.' + (t.name().isEmpty() ? type.getSimpleName().toLowerCase() : t.name())); - } - DistributeTable dt = type.getAnnotation(DistributeTable.class); - DistributeTableStrategy dts = null; - try { - dts = (dt == null) ? null : dt.strategy().getDeclaredConstructor().newInstance(); - if (dts != null) RedkaleClassLoader.putReflectionDeclaredConstructors(dt.strategy(), dt.strategy().getName()); - } catch (Exception e) { - logger.log(Level.SEVERE, type + " init DistributeTableStrategy error", e); - } - this.tableStrategy = dts; - - this.arrayer = Creator.arrayFunction(type); - this.creator = Creator.create(type); - ConstructorParameters cp = null; - try { - Method cm = this.creator.getClass().getMethod("create", Object[].class); - cp = cm.getAnnotation(ConstructorParameters.class); - RedkaleClassLoader.putReflectionPublicMethods(this.creator.getClass().getName()); - RedkaleClassLoader.putReflectionMethod(this.creator.getClass().getName(), cm); - } catch (Exception e) { - logger.log(Level.SEVERE, type + " cannot find ConstructorParameters Creator", e); - } - this.constructorParameters = (cp == null || cp.value().length < 1) ? null : cp.value(); - Attribute idAttr0 = null; - Map cryptmap0 = null; - Map aliasmap0 = null; - Class cltmp = type; - Set fields = new HashSet<>(); - List querycols = new ArrayList<>(); - List> queryattrs = new ArrayList<>(); - List insertcols = new ArrayList<>(); - List> insertattrs = new ArrayList<>(); - List updatecols = new ArrayList<>(); - List> updateattrs = new ArrayList<>(); - List> ddlList = new ArrayList<>(); - Map> cryptCreatorMap = new HashMap<>(); - do { - List ddl = new ArrayList<>(); - ddlList.add(ddl); - RedkaleClassLoader.putReflectionDeclaredFields(cltmp.getName()); - for (Field field : cltmp.getDeclaredFields()) { - if (Modifier.isStatic(field.getModifiers())) continue; - if (Modifier.isFinal(field.getModifiers())) continue; - if (field.getAnnotation(Transient.class) != null) continue; - if (fields.contains(field.getName())) continue; - final String fieldname = field.getName(); - final Column col = field.getAnnotation(Column.class); - final String sqlfield = col == null || col.name().isEmpty() ? fieldname : col.name(); - if (!fieldname.equals(sqlfield)) { - if (aliasmap0 == null) aliasmap0 = new HashMap<>(); - aliasmap0.put(fieldname, sqlfield); - } - final CryptColumn cpt = field.getAnnotation(CryptColumn.class); - CryptHandler cryptHandler = null; - if (cpt != null) { - if (cryptmap0 == null) cryptmap0 = new HashMap<>(); - cryptHandler = cryptCreatorMap.computeIfAbsent(cpt.handler(), c -> (Creator) Creator.create(cpt.handler())).create(); - cryptmap0.put(fieldname, cryptHandler); - } - Attribute attr; - try { - attr = Attribute.create(type, cltmp, field, cryptHandler); - } catch (RuntimeException e) { - continue; - } - if (field.getAnnotation(javax.persistence.Id.class) != null && idAttr0 == null) { - idAttr0 = attr; - insertcols.add(sqlfield); - insertattrs.add(attr); - RedkaleClassLoader.putReflectionField(cltmp.getName(), field); - } else { - if (col == null || col.insertable()) { - insertcols.add(sqlfield); - insertattrs.add(attr); - } - if (col == null || col.updatable()) { - updatecols.add(sqlfield); - updateattrs.add(attr); - updateAttributeMap.put(fieldname, attr); - } - if (col != null && !col.nullable()) { - notNullColumns.add(fieldname); - } - } - ddl.add(new EntityColumn(field.getAnnotation(javax.persistence.Id.class) != null, col, attr.field(), attr.type(), field.getAnnotation(Comment.class))); - querycols.add(sqlfield); - queryattrs.add(attr); - fields.add(fieldname); - attributeMap.put(fieldname, attr); - } - } while ((cltmp = cltmp.getSuperclass()) != Object.class); - if (idAttr0 == null) throw new RuntimeException(type.getName() + " have no primary column by @javax.persistence.Id"); - cltmp = type; - JsonConvert convert = DEFAULT_JSON_CONVERT; - do { - for (Method method : cltmp.getDeclaredMethods()) { - if (method.getAnnotation(SourceConvert.class) == null) continue; - if (!Modifier.isStatic(method.getModifiers())) throw new RuntimeException("@SourceConvert method(" + method + ") must be static"); - if (method.getReturnType() != JsonConvert.class) throw new RuntimeException("@SourceConvert method(" + method + ") must be return JsonConvert.class"); - if (method.getParameterCount() > 0) throw new RuntimeException("@SourceConvert method(" + method + ") must be 0 parameter"); - try { - method.setAccessible(true); - convert = (JsonConvert) method.invoke(null); - } catch (Exception e) { - throw new RuntimeException(method + " invoke error", e); - } - if (convert != null) break; - } - } while ((cltmp = cltmp.getSuperclass()) != Object.class); - this.jsonConvert = convert == null ? DEFAULT_JSON_CONVERT : convert; - - this.primary = idAttr0; - this.aliasmap = aliasmap0; - this.cryptmap = cryptmap0; - List ddls = new ArrayList<>(); - Collections.reverse(ddlList); //鐖剁被鐨勫瓧娈垫帓鍦ㄥ墠闈 - for (List ls : ddlList) { - ddls.addAll(ls); - } - this.ddlColumns = ddls.toArray(new EntityColumn[ddls.size()]); - this.attributes = attributeMap.values().toArray(new Attribute[attributeMap.size()]); - this.insertAttributes = insertattrs.toArray(new Attribute[insertattrs.size()]); - this.updateAttributes = updateattrs.toArray(new Attribute[updateattrs.size()]); - if (this.constructorParameters == null) { - this.constructorAttributes = null; - this.unconstructorAttributes = null; - } else { - this.constructorAttributes = new Attribute[this.constructorParameters.length]; - List> unconstructorAttrs = new ArrayList<>(); - List newquerycols1 = new ArrayList<>(); - List newquerycols2 = new ArrayList<>(); - for (Attribute attr : new ArrayList<>(queryattrs)) { - int pos = -1; - for (int i = 0; i < this.constructorParameters.length; i++) { - if (attr.field().equals(this.constructorParameters[i])) { - pos = i; - break; - } - } - if (pos >= 0) { - this.constructorAttributes[pos] = attr; - newquerycols1.add(querycols.get(queryattrs.indexOf(attr))); - } else { - unconstructorAttrs.add(attr); - newquerycols2.add(querycols.get(queryattrs.indexOf(attr))); - } - } - this.unconstructorAttributes = unconstructorAttrs.toArray(new Attribute[unconstructorAttrs.size()]); - newquerycols1.addAll(newquerycols2); - querycols = newquerycols1; - List> newqueryattrs = new ArrayList<>(); - newqueryattrs.addAll(List.of(constructorAttributes)); - newqueryattrs.addAll(unconstructorAttrs); - queryattrs = newqueryattrs; - } - this.querySqlColumns = querycols.toArray(new String[querycols.size()]); - this.querySqlColumnSequence = Utility.joining(querySqlColumns, ','); - this.querySqlColumnSequenceA = "a." + Utility.joining(querySqlColumns, ",a."); - this.queryAttributes = queryattrs.toArray(new Attribute[queryattrs.size()]); - if (table != null) { - StringBuilder querydb = new StringBuilder(); - int index = 0; - for (String col : querycols) { - if (index > 0) querydb.append(','); - querydb.append(col); - index++; - } - StringBuilder insertsb = new StringBuilder(); - StringBuilder insertsbquestion = new StringBuilder(); - StringBuilder insertsbdollar = new StringBuilder(); - StringBuilder insertsbnames = new StringBuilder(); - index = 0; - for (String col : insertcols) { - if (index > 0) insertsb.append(','); - insertsb.append(col); - if (index > 0) { - insertsbquestion.append(','); - insertsbdollar.append(','); - insertsbnames.append(','); - } - insertsbquestion.append('?'); - insertsbdollar.append("$").append(++index); - insertsbnames.append(":").append(col); - } - this.insertQuestionPrepareSQL = "INSERT INTO " + (this.tableStrategy == null ? table : "${newtable}") + "(" + insertsb + ") VALUES(" + insertsbquestion + ")"; - this.insertDollarPrepareSQL = "INSERT INTO " + (this.tableStrategy == null ? table : "${newtable}") + "(" + insertsb + ") VALUES(" + insertsbdollar + ")"; - this.insertNamesPrepareSQL = "INSERT INTO " + (this.tableStrategy == null ? table : "${newtable}") + "(" + insertsb + ") VALUES(" + insertsbnames + ")"; - StringBuilder updatesbquestion = new StringBuilder(); - StringBuilder updatesbdollar = new StringBuilder(); - StringBuilder updatesbnames = new StringBuilder(); - index = 0; - for (String col : updatecols) { - if (index > 0) { - updatesbquestion.append(", "); - updatesbdollar.append(", "); - updatesbnames.append(", "); - } - updatesbquestion.append(col).append(" = ?"); - updatesbdollar.append(col).append(" = ").append("$").append(++index); - updatesbnames.append(col).append(" = :").append(col); - } - this.updateQuestionPrepareSQL = "UPDATE " + (this.tableStrategy == null ? table : "${newtable}") + " SET " + updatesbquestion + " WHERE " + getPrimarySQLColumn(null) + " = ?"; - this.updateDollarPrepareSQL = "UPDATE " + (this.tableStrategy == null ? table : "${newtable}") + " SET " + updatesbdollar + " WHERE " + getPrimarySQLColumn(null) + " = $" + (++index); - this.updateNamesPrepareSQL = "UPDATE " + (this.tableStrategy == null ? table : "${newtable}") + " SET " + updatesbnames + " WHERE " + getPrimarySQLColumn(null) + " = :" + getPrimarySQLColumn(null); - this.deleteQuestionPrepareSQL = "DELETE FROM " + (this.tableStrategy == null ? table : "${newtable}") + " WHERE " + getPrimarySQLColumn(null) + " = ?"; - this.deleteDollarPrepareSQL = "DELETE FROM " + (this.tableStrategy == null ? table : "${newtable}") + " WHERE " + getPrimarySQLColumn(null) + " = $1"; - this.deleteNamesPrepareSQL = "DELETE FROM " + (this.tableStrategy == null ? table : "${newtable}") + " WHERE " + getPrimarySQLColumn(null) + " = :" + getPrimarySQLColumn(null); - this.allQueryPrepareSQL = "SELECT " + querydb + " FROM " + table; - this.findQuestionPrepareSQL = "SELECT " + querydb + " FROM " + table + " WHERE " + getPrimarySQLColumn(null) + " = ?"; - this.findDollarPrepareSQL = "SELECT " + querydb + " FROM " + table + " WHERE " + getPrimarySQLColumn(null) + " = $1"; - this.findNamesPrepareSQL = "SELECT " + querydb + " FROM " + table + " WHERE " + getPrimarySQLColumn(null) + " = :" + getPrimarySQLColumn(null); - } else { - this.allQueryPrepareSQL = null; - - this.insertQuestionPrepareSQL = null; - this.updateQuestionPrepareSQL = null; - this.deleteQuestionPrepareSQL = null; - this.findQuestionPrepareSQL = null; - - this.insertDollarPrepareSQL = null; - this.updateDollarPrepareSQL = null; - this.deleteDollarPrepareSQL = null; - this.findDollarPrepareSQL = null; - - this.insertNamesPrepareSQL = null; - this.updateNamesPrepareSQL = null; - this.deleteNamesPrepareSQL = null; - this.findNamesPrepareSQL = null; - } - //----------------cache-------------- - Cacheable c = type.getAnnotation(Cacheable.class); - if (this.table == null || (!cacheForbidden && c != null && c.value())) { - this.cache = new EntityCache<>(this, c); - } else { - this.cache = null; - } - } - - @SuppressWarnings("unchecked") - public V getSubobject(String name) { - return (V) this.subobjectMap.get(name); - } - - public void setSubobject(String name, Object value) { - this.subobjectMap.put(name, value); - } - - public void removeSubobject(String name) { - this.subobjectMap.remove(name); - } - - public void clearSubobjects() { - this.subobjectMap.clear(); - } - - /** - * 鑾峰彇JsonConvert - * - * @return JsonConvert - */ - public JsonConvert getJsonConvert() { - return jsonConvert; - } - - /** - * 鑾峰彇Entity缂撳瓨鍣 - * - * @return EntityCache - */ - public EntityCache getCache() { - return cache; - } - - /** - * 鍒ゆ柇缂撳瓨鍣ㄦ槸鍚﹀凡缁忓叏閲忓姞杞借繃 - * - * @return boolean - */ - public boolean isCacheFullLoaded() { - return cache != null && cache.isFullLoaded(); - } - - /** - * 鑾峰彇Entity鏋勫缓鍣 - * - * @return Creator - */ - public Creator getCreator() { - return creator; - } - - /** - * 鑾峰彇Entity鏁扮粍鏋勫缓鍣 - * - * @return Creator - */ - public IntFunction getArrayer() { - return arrayer; - } - - /** - * 鑾峰彇Entity绫诲悕 - * - * @return Class - */ - public Class getType() { - return type; - } - - /** - * 鍒ゆ柇Entity鏄惁涓鸿櫄鎷熺被 - * - * @return boolean - */ - public boolean isVirtualEntity() { - return table == null; - } - - public DistributeTableStrategy getTableStrategy() { - return tableStrategy; - } - - public Object disTableLock() { - return tables; - } - - public boolean containsDisTable(String tablekey) { - return tables.contains(tablekey); - } - - public void addDisTable(String tablekey) { - tables.add(tablekey); - } - - public boolean removeDisTable(String tablekey) { - return tables.remove(tablekey); - } - - public EntityColumn[] getDDLColumns() { - return ddlColumns; - } - - public Attribute[] getInsertAttributes() { - return insertAttributes; - } - - public Attribute[] getUpdateAttributes() { - return updateAttributes; - } - - public Attribute[] getQueryAttributes() { - return queryAttributes; - } - - /** - * 鑾峰彇Entity鐨凲UERY SQL - * - * @param pk 涓婚敭鍊 - * - * @return String - */ - public String getFindQuestionPrepareSQL(Serializable pk) { - if (this.tableStrategy == null) return findQuestionPrepareSQL; - return findQuestionPrepareSQL.replace("${newtable}", getTable(pk)); - } - - /** - * 鑾峰彇Entity鐨凲UERY SQL - * - * - * @return String - */ - public String getAllQueryPrepareSQL() { - return this.allQueryPrepareSQL; - } - - /** - * 鑾峰彇Entity鐨凲UERY SQL - * - * @param pk 涓婚敭鍊 - * - * @return String - */ - public String getFindDollarPrepareSQL(Serializable pk) { - if (this.tableStrategy == null) return findDollarPrepareSQL; - return findDollarPrepareSQL.replace("${newtable}", getTable(pk)); - } - - /** - * 鑾峰彇Entity鐨凲UERY SQL - * - * @param pk 涓婚敭鍊 - * - * @return String - */ - public String getFindNamesPrepareSQL(Serializable pk) { - if (this.tableStrategy == null) return findNamesPrepareSQL; - return findNamesPrepareSQL.replace("${newtable}", getTable(pk)); - } - - /** - * 鑾峰彇Entity鐨処NSERT SQL - * - * @param bean Entity瀵硅薄 - * - * @return String - */ - public String getInsertQuestionPrepareSQL(T bean) { - if (this.tableStrategy == null) return insertQuestionPrepareSQL; - return insertQuestionPrepareSQL.replace("${newtable}", getTable(bean)); - } - - /** - * 鑾峰彇Entity鐨処NSERT SQL - * - * @param bean Entity瀵硅薄 - * - * @return String - */ - public String getInsertDollarPrepareSQL(T bean) { - if (this.tableStrategy == null) return insertDollarPrepareSQL; - return insertDollarPrepareSQL.replace("${newtable}", getTable(bean)); - } - - /** - * 鑾峰彇Entity鐨処NSERT SQL - * - * @param bean Entity瀵硅薄 - * - * @return String - */ - public String getInsertNamesPrepareSQL(T bean) { - if (this.tableStrategy == null) return insertNamesPrepareSQL; - return insertNamesPrepareSQL.replace("${newtable}", getTable(bean)); - } - - /** - * 鑾峰彇Entity鐨刄PDATE SQL - * - * @param bean Entity瀵硅薄 - * - * @return String - */ - public String getUpdateQuestionPrepareSQL(T bean) { - if (this.tableStrategy == null) return updateQuestionPrepareSQL; - return updateQuestionPrepareSQL.replace("${newtable}", getTable(bean)); - } - - /** - * 鑾峰彇Entity鐨刄PDATE SQL - * - * @param bean Entity瀵硅薄 - * - * @return String - */ - public String getUpdateDollarPrepareSQL(T bean) { - if (this.tableStrategy == null) return updateDollarPrepareSQL; - return updateDollarPrepareSQL.replace("${newtable}", getTable(bean)); - } - - /** - * 鑾峰彇Entity鐨刄PDATE SQL - * - * @param bean Entity瀵硅薄 - * - * @return String - */ - public String getUpdateNamesPrepareSQL(T bean) { - if (this.tableStrategy == null) return updateNamesPrepareSQL; - return updateNamesPrepareSQL.replace("${newtable}", getTable(bean)); - } - - /** - * 鑾峰彇Entity鐨凞ELETE SQL - * - * @param bean Entity瀵硅薄 - * - * @return String - */ - public String getDeleteQuestionPrepareSQL(T bean) { - if (this.tableStrategy == null) return deleteQuestionPrepareSQL; - return deleteQuestionPrepareSQL.replace("${newtable}", getTable(bean)); - } - - /** - * 鑾峰彇Entity鐨凞ELETE SQL - * - * @param bean Entity瀵硅薄 - * - * @return String - */ - public String getDeleteDollarPrepareSQL(T bean) { - if (this.tableStrategy == null) return deleteDollarPrepareSQL; - return deleteDollarPrepareSQL.replace("${newtable}", getTable(bean)); - } - - /** - * 鑾峰彇Entity鐨凞ELETE SQL - * - * @param bean Entity瀵硅薄 - * - * @return String - */ - public String getDeleteNamesPrepareSQL(T bean) { - if (this.tableStrategy == null) return deleteNamesPrepareSQL; - return deleteNamesPrepareSQL.replace("${newtable}", getTable(bean)); - } - - /** - * 鑾峰彇鏌ヨ瀛楁鍒楄〃 - * - * @param tabalis 琛ㄥ埆鍚 - * @param selects 杩囨护瀛楁 - * - * @return String - */ - public CharSequence getQueryColumns(String tabalis, SelectColumn selects) { - if (selects == null) { - if (tabalis == null) return querySqlColumnSequence; - if ("a".equals(tabalis)) return querySqlColumnSequenceA; - return tabalis + "." + Utility.joining(querySqlColumns, "," + tabalis + "."); - } - StringBuilder sb = new StringBuilder(); - for (Attribute attr : this.attributes) { - if (!selects.test(attr.field())) continue; - if (sb.length() > 0) sb.append(','); - sb.append(getSQLColumn(tabalis, attr.field())); - } - if (sb.length() == 0) sb.append('*'); - return sb; - } - - public CharSequence getFullQueryColumns(String tabalis, SelectColumn selects) { - if (selects == null) { - if (tabalis == null) { - return querySqlColumnSequence; - } else { - StringBuilder sb = new StringBuilder(); - String s = tabalis + "."; - for (String col : querySqlColumns) { - if (sb.length() > 0) sb.append(','); - sb.append(s).append(col); - } - return sb; - } - } else { - StringBuilder sb = new StringBuilder(); - for (Attribute attr : this.attributes) { - if (!selects.test(attr.field())) continue; - if (sb.length() > 0) sb.append(','); - sb.append(getSQLColumn(tabalis, attr.field())); - } - if (sb.length() == 0) sb.append('*'); - return sb; - } - } - - public String getOriginTable() { - return table; - } - - /** - * 鏍规嵁涓婚敭鍊艰幏鍙朎ntity鐨勮〃鍚 - * - * @param primary Entity涓婚敭鍊 - * - * @return String - */ - public String getTable(Serializable primary) { - if (tableStrategy == null) return table; - String t = tableStrategy.getTable(table, primary); - return t == null || t.isEmpty() ? table : t; - } - - /** - * 鏍规嵁杩囨护鏉′欢鑾峰彇Entity鐨勮〃鍚 - * - * @param node 杩囨护鏉′欢 - * - * @return String - */ - public String getTable(FilterNode node) { - if (tableStrategy == null) return table; - String t = tableStrategy.getTable(table, node); - return t == null || t.isEmpty() ? table : t; - } - - /** - * 鏍规嵁Entity瀵硅薄鑾峰彇Entity鐨勮〃鍚 - * - * @param bean Entity瀵硅薄 - * - * @return String - */ - public String getTable(T bean) { - if (tableStrategy == null) return table; - String t = tableStrategy.getTable(table, bean); - return t == null || t.isEmpty() ? table : t; - } - - /** - * 鑾峰彇涓婚敭瀛楁鐨凙ttribute - * - * @return Attribute - */ - public Attribute getPrimary() { - return this.primary; - } - - /** - * 閬嶅巻鏁版嵁搴撹〃瀵瑰簲鐨勬墍鏈夊瓧娈, 涓嶅寘鍚@Transient瀛楁 - * - * @param action BiConsumer - */ - public void forEachAttribute(BiConsumer> action) { - this.attributeMap.forEach(action); - } - - /** - * 鏍规嵁Entity瀛楁鍚嶈幏鍙栧瓧娈电殑Attribute - * - * @param fieldname Class瀛楁鍚 - * - * @return Attribute - */ - public Attribute getAttribute(String fieldname) { - if (fieldname == null) return null; - return this.attributeMap.get(fieldname); - } - - /** - * 鏍规嵁Entity瀛楁鍚嶈幏鍙栧彲鏇存柊瀛楁鐨凙ttribute - * - * @param fieldname Class瀛楁鍚 - * - * @return Attribute - */ - public Attribute getUpdateAttribute(String fieldname) { - return this.updateAttributeMap.get(fieldname); - } - - /** - * 鍒ゆ柇Entity绫荤殑瀛楁鍚嶄笌琛ㄥ瓧娈靛悕s鏄惁瀛樺湪涓嶄竴鑷寸殑鍊 - * - * @return boolean - */ - public boolean isNoAlias() { - return this.aliasmap == null; - } - - /** - * 鏍规嵁Flipper鑾峰彇ORDER BY鐨凷QL璇彞锛屼笉瀛樺湪Flipper鎴杝ort瀛楁杩斿洖绌哄瓧绗︿覆 - * - * @param flipper 缈婚〉瀵硅薄 - * - * @return String - */ - protected String createSQLOrderby(Flipper flipper) { - if (flipper == null || flipper.getSort() == null) return ""; - final String sort = flipper.getSort(); - if (sort.isEmpty() || sort.indexOf(';') >= 0 || sort.indexOf('\n') >= 0) return ""; - String sql = this.sortOrderbySqls.get(sort); - if (sql != null) return sql; - final StringBuilder sb = new StringBuilder(); - sb.append(" ORDER BY "); - if (isNoAlias()) { - sb.append(sort); - } else { - boolean flag = false; - for (String item : sort.split(",")) { - if (item.isEmpty()) continue; - String[] sub = item.split("\\s+"); - if (flag) sb.append(','); - if (sub.length < 2 || sub[1].equalsIgnoreCase("ASC")) { - sb.append(getSQLColumn("a", sub[0])).append(" ASC"); - } else { - sb.append(getSQLColumn("a", sub[0])).append(" DESC"); - } - flag = true; - } - } - sql = sb.toString(); - this.sortOrderbySqls.put(sort, sql); - return sql; - } - - /** - * 鏍规嵁field瀛楁鍚嶈幏鍙栨暟鎹簱瀵瑰簲鐨勫瓧娈靛悕 - * - * @param tabalis 琛ㄥ埆鍚 - * @param fieldname 瀛楁鍚 - * - * @return String - */ - public String getSQLColumn(String tabalis, String fieldname) { - return this.aliasmap == null ? (tabalis == null ? fieldname : (tabalis + '.' + fieldname)) - : (tabalis == null ? aliasmap.getOrDefault(fieldname, fieldname) : (tabalis + '.' + aliasmap.getOrDefault(fieldname, fieldname))); - } - - /** - * 瀛楁鍊艰浆鎹㈡垚鏁版嵁搴撶殑鍊 - * - * @param fieldname 瀛楁鍚 - * @param fieldvalue 瀛楁鍊 - * - * @return Object - */ - public Object getSQLValue(String fieldname, Serializable fieldvalue) { - if (fieldvalue == null && fieldname != null && isNotNullable(fieldname)) { - if (isNotNullJson(getAttribute(fieldname))) return ""; - } - if (this.cryptmap == null) return fieldvalue; - CryptHandler handler = this.cryptmap.get(fieldname); - if (handler == null) return fieldvalue; - return handler.encrypt(fieldvalue); - } - - /** - * 瀛楁鍊艰浆鎹㈡垚甯﹁浆涔夌殑鏁版嵁搴撶殑鍊 - * - * @param fieldname 瀛楁鍚 - * @param fieldvalue 瀛楁鍊 - * @param sqlFormatter 杞箟鍣 - * - * @return CharSequence - */ - public CharSequence formatSQLValue(String fieldname, Serializable fieldvalue, BiFunction sqlFormatter) { - Object val = getSQLValue(fieldname, fieldvalue); - return sqlFormatter == null ? formatToString(val) : sqlFormatter.apply(this, val); - } - - /** - * 瀛楁鍊艰浆鎹㈡垚甯﹁浆涔夌殑鏁版嵁搴撶殑鍊 - * - * @param value 瀛楁鍊 - * @param sqlFormatter 杞箟鍣 - * - * @return CharSequence - */ - public CharSequence formatSQLValue(Object value, BiFunction sqlFormatter) { - return sqlFormatter == null ? formatToString(value) : sqlFormatter.apply(this, value); - } - - /** - * 瀛楁鍊艰浆鎹㈡垚鏁版嵁搴撶殑鍊 - * - * @param 娉涘瀷 - * @param attr Attribute - * @param entity 璁板綍瀵硅薄 - * - * @return Object - */ - public Object getSQLValue(Attribute attr, T entity) { - Object val = attr.get(entity); - CryptHandler cryptHandler = attr.attach(); - if (cryptHandler != null) val = cryptHandler.encrypt(val); - return val; - } - - /** - * 瀛楁鍊艰浆鎹㈡垚甯﹁浆涔夌殑鏁版嵁搴撶殑鍊 - * - * @param 娉涘瀷 - * @param attr Attribute - * @param entity 璁板綍瀵硅薄 - * @param sqlFormatter 杞箟鍣 - * - * @return CharSequence - */ - public CharSequence formatSQLValue(Attribute attr, T entity, BiFunction sqlFormatter) { - Object val = getSQLValue(attr, entity); - return sqlFormatter == null ? formatToString(val) : sqlFormatter.apply(this, val); - } - - /** - * 鏁版嵁搴撶殑鍊艰浆鎹㈡垚鏁板瓧娈靛 - * - * @param attr Attribute - * @param entity 璁板綍瀵硅薄 - * - * @return Object - */ - public Serializable getFieldValue(Attribute attr, T entity) { - Serializable val = attr.get(entity); - CryptHandler cryptHandler = attr.attach(); - if (cryptHandler != null) val = (Serializable) cryptHandler.decrypt(val); - return val; - } - - /** - * 鑾峰彇涓婚敭瀛楁鍚 - * - * @return String - */ - public String getPrimaryColumn() { - return this.primary.field(); - } - - /** - * 鑾峰彇涓婚敭瀛楁鐨勮〃瀛楁鍚 - * - * @return String - */ - public String getPrimarySQLColumn() { - return getSQLColumn(null, this.primary.field()); - } - - /** - * 鑾峰彇涓婚敭瀛楁鐨勫甫鏈夎〃鍒悕鐨勮〃瀛楁鍚 - * - * @param tabalis 琛ㄥ埆鍚 - * - * @return String - */ - public String getPrimarySQLColumn(String tabalis) { - return getSQLColumn(tabalis, this.primary.field()); - } - - /** - * 鎷兼帴UPDATE缁欏瓧娈佃祴鍊肩殑SQL鐗囨 - * - * @param sqlColumn 琛ㄥ瓧娈靛悕 - * @param attr Attribute - * @param cv ColumnValue - * @param formatter 杞箟鍣 - * - * @return CharSequence - */ - protected CharSequence formatSQLValue(String sqlColumn, Attribute attr, final ColumnValue cv, BiFunction formatter) { - if (cv == null) return null; - Object val = cv.getValue(); - //ColumnNodeValue鏃 cv.getExpress() == ColumnExpress.MOV 鍙敤浜巙pdateColumn - if (val instanceof ColumnNodeValue) return formatSQLValue(attr, null, (ColumnNodeValue) val, formatter); - if (val instanceof ColumnFuncNode) return formatSQLValue(attr, null, (ColumnFuncNode) val, formatter); - switch (cv.getExpress()) { - case INC: - return new StringBuilder().append(sqlColumn).append(" + ").append(val); - case DEC: - return new StringBuilder().append(sqlColumn).append(" - ").append(val); - case MUL: - return new StringBuilder().append(sqlColumn).append(" * ").append(val); - case DIV: - return new StringBuilder().append(sqlColumn).append(" / ").append(val); - case MOD: - return new StringBuilder().append(sqlColumn).append(" % ").append(val); - case AND: - return new StringBuilder().append(sqlColumn).append(" & ").append(val); - case ORR: - return new StringBuilder().append(sqlColumn).append(" | ").append(val); - case MOV: - CryptHandler handler = attr.attach(); - if (handler != null) val = handler.encrypt(val); - CharSequence rs = formatter == null ? formatToString(val) : formatter.apply(this, val); - if (rs == null && isNotNullJson(attr)) rs = ""; - return rs; - } - CryptHandler handler = attr.attach(); - if (handler != null) val = handler.encrypt(val); - return formatter == null ? formatToString(val) : formatter.apply(this, val); - } - - protected CharSequence formatSQLValue(Attribute attr, String tabalis, final ColumnFuncNode node, BiFunction formatter) { - if (node.getValue() instanceof ColumnNodeValue) { - return node.getFunc().getColumn(formatSQLValue(attr, tabalis, (ColumnNodeValue) node.getValue(), formatter).toString()); - } else { - return node.getFunc().getColumn(this.getSQLColumn(tabalis, String.valueOf(node.getValue()))); - } - } - - protected CharSequence formatSQLValue(Attribute attr, String tabalis, final ColumnNodeValue node, BiFunction formatter) { - Serializable left = node.getLeft(); - if (left instanceof CharSequence) { - left = this.getSQLColumn(tabalis, left.toString()); - if (node.getExpress() == ColumnExpress.MOV) return (String) left; - } else if (left instanceof ColumnNodeValue) { - left = "(" + formatSQLValue(attr, tabalis, (ColumnNodeValue) left, formatter) + ")"; - } else if (left instanceof ColumnFuncNode) { - left = "(" + formatSQLValue(attr, tabalis, (ColumnFuncNode) left, formatter) + ")"; - } - Serializable right = node.getRight(); - if (right instanceof CharSequence) { - right = this.getSQLColumn(null, right.toString()); - } else if (left instanceof ColumnNodeValue) { - right = "(" + formatSQLValue(attr, tabalis, (ColumnNodeValue) right, formatter) + ")"; - } else if (left instanceof ColumnFuncNode) { - right = "(" + formatSQLValue(attr, tabalis, (ColumnFuncNode) right, formatter) + ")"; - } - switch (node.getExpress()) { - case INC: - return new StringBuilder().append(left).append(" + ").append(right); - case DEC: - return new StringBuilder().append(left).append(" - ").append(right); - case MUL: - return new StringBuilder().append(left).append(" * ").append(right); - case DIV: - return new StringBuilder().append(left).append(" / ").append(right); - case MOD: - return new StringBuilder().append(left).append(" % ").append(right); - case AND: - return new StringBuilder().append(left).append(" & ").append(right); - case ORR: - return new StringBuilder().append(left).append(" | ").append(right); - } - throw new IllegalArgumentException(node + " express cannot be null or MOV"); - } - - /** - * 鑾峰彇鎵鏈夋暟鎹〃瀛楁鐨凙ttribute, 涓嶅寘鍚@Transient瀛楁 - * - * @return Map - */ - protected Map> getAttributes() { - return attributeMap; - } - - /** - * 鍒ゆ柇鏃ュ織绾у埆 - * - * @param logger Logger - * @param l Level - * - * @return boolean - */ - public boolean isLoggable(Logger logger, Level l) { - return logger.isLoggable(l) && l.intValue() >= this.logLevel; - } - - public boolean isNotNullable(String fieldname) { - return notNullColumns.contains(fieldname); - } - - public boolean isNotNullable(Attribute attr) { - return attr == null ? false : notNullColumns.contains(attr.field()); - } - - public boolean isNotNullJson(Attribute attr) { - if (attr == null) return false; - return notNullColumns.contains(attr.field()) - && !Number.class.isAssignableFrom(attr.type()) - && !CharSequence.class.isAssignableFrom(attr.type()) - && boolean.class != attr.type() && Boolean.class != attr.type() - && byte[].class != attr.type() - && java.util.Date.class != attr.type() - && !attr.type().getName().startsWith("java.sql.") //閬垮厤寮曠敤import java.sql.* 鍑忓皯妯″潡渚濊禆 - && !attr.type().getName().startsWith("java.time."); - } - - /** - * 鍒ゆ柇鏃ュ織绾у埆 - * - * @param logger Logger - * @param l Level - * @param str String - * - * @return boolean - */ - public boolean isLoggable(Logger logger, Level l, String str) { - boolean rs = logger.isLoggable(l) && l.intValue() >= this.logLevel; - if (this.excludeLogLevels == null || !rs || str == null) return rs; - String[] keys = this.excludeLogLevels.get(l.intValue()); - if (keys == null) return rs; - for (String key : keys) { - if (str.contains(key)) return false; - } - return rs; - } - - /** - * 灏嗗瓧娈靛煎簭鍒楀寲涓哄彲SQL鐨勫瓧绗︿覆 - * - * @param value 瀛楁鍊 - * - * @return String - */ - private String formatToString(Object value) { - if (value == null) return null; - if (value instanceof CharSequence) { - return new StringBuilder().append('\'').append(value.toString().replace("'", "\\'")).append('\'').toString(); - } else if (!(value instanceof Number) && !(value instanceof java.util.Date) - && !value.getClass().getName().startsWith("java.sql.") && !value.getClass().getName().startsWith("java.time.")) { - return new StringBuilder().append('\'').append(jsonConvert.convertTo(value).replace("'", "\\'")).append('\'').toString(); - } - return String.valueOf(value); - } - - /** - * 灏嗕竴琛岀殑ResultSet缁勮鎴愪竴涓狤ntity瀵硅薄 - * - * @param sels 鎸囧畾瀛楁 - * @param row ResultSet - * - * @return Entity瀵硅薄 - */ - protected T getEntityValue(final SelectColumn sels, final DataResultSetRow row) { - if (row.wasNull()) return null; - T obj; - Attribute[] attrs = this.queryAttributes; - if (this.constructorParameters == null) { - obj = creator.create(); - } else { - Object[] cps = new Object[this.constructorParameters.length]; - for (int i = 0; i < this.constructorAttributes.length; i++) { - Attribute attr = this.constructorAttributes[i]; - if (sels == null || sels.test(attr.field())) { - cps[i] = getFieldValue(attr, row, 0); - } - } - obj = creator.create(cps); - attrs = this.unconstructorAttributes; - } - for (Attribute attr : attrs) { - if (sels == null || sels.test(attr.field())) { - attr.set(obj, getFieldValue(attr, row, 0)); - } - } - return obj; - } - - protected T getFullEntityValue(final DataResultSetRow row) { - return getEntityValue(constructorAttributes, constructorAttributes == null ? queryAttributes : unconstructorAttributes, row); - } - - /** - * 灏嗕竴琛岀殑ResultSet缁勮鎴愪竴涓狤ntity瀵硅薄 - * - * @param constructorAttrs 鏋勫缓鍑芥暟鐨凙ttribute鏁扮粍, 澶у皬蹇呴』涓巘his.constructorAttributes鐩稿悓 - * @param unconstructorAttrs 闈炴瀯寤哄嚱鏁扮殑Attribute鏁扮粍 - * @param row ResultSet - * - * @return Entity瀵硅薄 - */ - protected T getEntityValue(final Attribute[] constructorAttrs, final Attribute[] unconstructorAttrs, final DataResultSetRow row) { - if (row.wasNull()) return null; - T obj; - int index = 0; - if (this.constructorParameters == null) { - obj = creator.create(); - } else { - Object[] cps = new Object[this.constructorParameters.length]; - for (int i = 0; i < constructorAttrs.length; i++) { - Attribute attr = constructorAttrs[i]; - if (attr == null) continue; - cps[i] = getFieldValue(attr, row, ++index); - } - obj = creator.create(cps); - } - if (unconstructorAttrs != null) { - for (Attribute attr : unconstructorAttrs) { - if (attr == null) continue; - attr.set(obj, getFieldValue(attr, row, ++index)); - } - } - return obj; - } - - protected Serializable getFieldValue(Attribute attr, final DataResultSetRow row, int index) { - return row.getObject(attr, index, index > 0 ? null : this.getSQLColumn(null, attr.field())); - } - - public static interface DataResultSetRow { - - //index浠1寮濮 - public Object getObject(int index); - - public Object getObject(String column); - - //index浠1寮濮 - default Serializable getObject(Attribute attr, int index, String column) { - return DataResultSet.getRowColumnValue(this, attr, index, column); - } - - //鍒ゆ柇褰撳墠琛屽兼槸鍚︿负null - public boolean wasNull(); - } - - public static class EntityColumn { - - public final boolean primary; //鏄惁涓婚敭 - - public final String field; - - public final String column; - - public final Class type; - - public final String comment; - - public final boolean nullable; - - public final boolean unique; - - public final int length; - - public final int precision; - - public final int scale; - - protected EntityColumn(boolean primary, Column col, String name, Class type, Comment comment) { - this.primary = primary; - this.field = name; - this.column = col == null || col.name().isEmpty() ? name : col.name(); - this.type = type; - this.comment = (col == null || col.comment().isEmpty()) && comment != null && !comment.value().isEmpty() ? comment.value() : (col == null ? "" : col.comment()); - this.nullable = col == null ? false : col.nullable(); - this.unique = col == null ? false : col.unique(); - this.length = col == null ? 255 : col.length(); - this.precision = col == null ? 0 : col.precision(); - this.scale = col == null ? 0 : col.scale(); - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - } -} +/* + * 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.source; + +import java.io.Serializable; +import java.lang.reflect.*; +import java.util.*; +import java.util.concurrent.*; +import java.util.function.*; +import java.util.logging.*; +import javax.persistence.*; +import org.redkale.convert.json.*; +import org.redkale.util.*; + +/** + * Entity鎿嶄綔绫 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Entity绫荤殑娉涘瀷 + */ +@SuppressWarnings("unchecked") +public final class EntityInfo { + + private static final JsonConvert DEFAULT_JSON_CONVERT = JsonFactory.create().skipAllIgnore(true).getConvert(); + + //鍏ㄥ眬闈欐佽祫婧 + private static final ConcurrentHashMap entityInfos = new ConcurrentHashMap<>(); + + //鏃ュ織 + private static final Logger logger = Logger.getLogger(EntityInfo.class.getSimpleName()); + + //Entity绫诲悕 + private final Class type; + + //绫诲搴旂殑鏁版嵁琛ㄥ悕, 濡傛灉鏄疺irtualEntity 绫伙紝 鍒欒瀛楁涓簄ull + final String table; + + //JsonConvert + final JsonConvert jsonConvert; + + //Entity鏋勫缓鍣 + private final Creator creator; + + //Entity鏁板兼瀯寤哄櫒 + private final IntFunction arrayer; + + //Entity鏋勫缓鍣ㄥ弬鏁 + private final String[] constructorParameters; + + //Entity鏋勫缓鍣ㄥ弬鏁癆ttribute锛 鏁扮粍涓暟涓巆onstructorParameters鐩稿悓 + final Attribute[] constructorAttributes; + + //Entity鏋勫缓鍣ㄥ弬鏁癆ttribute + final Attribute[] unconstructorAttributes; + + //涓婚敭 + final Attribute primary; + + //DDL瀛楁闆嗗悎 + final EntityColumn[] ddlColumns; + + //Entity缂撳瓨瀵硅薄 + private final EntityCache cache; + + //鐢ㄤ簬瀛樺偍缁戝畾鍦‥ntityInfo涓婄殑瀵硅薄 + private final ConcurrentHashMap subobjectMap = new ConcurrentHashMap<>(); + + //key鏄痜ield鐨刵ame锛 涓嶆槸sql瀛楁銆 + //瀛樻斁鎵鏈変笌鏁版嵁搴撳搴旂殑瀛楁锛 鍖呮嫭涓婚敭 + private final HashMap> attributeMap = new HashMap<>(); + + //瀛樻斁鎵鏈変笌鏁版嵁搴撳搴旂殑瀛楁锛 鍖呮嫭涓婚敭 + final Attribute[] attributes; + + //key鏄痜ield鐨刵ame锛 value鏄疌olumn鐨勫埆鍚嶏紝鍗虫暟鎹簱琛ㄧ殑瀛楁鍚 + //鍙湁field.name 涓 Column.name涓嶅悓鎵嶅瓨鏀惧湪aliasmap閲. + private final Map aliasmap; + + //key鏄痜ield鐨刵ame锛 value鏄疌ryptHandler + //瀛楁閮戒笉瀛樺湪CryptHandler鏃跺煎洜涓轰负null锛屽噺灏戝垽鏂 + private final Map cryptmap; + + //鎵鏈夊彲鏇存柊瀛楁锛屽嵆鎺掗櫎浜嗕富閿瓧娈靛拰鏍囪涓@Column(updatable=false)鐨勫瓧娈 + private final Map> updateAttributeMap = new HashMap<>(); + + //鐢ㄤ簬瀛樺湪database.table_20160202绫讳技杩欑鍒嗗竷寮忚〃 + private final Set tables = new CopyOnWriteArraySet<>(); + + //涓嶈兘涓簄ull鐨勫瓧娈靛悕 + private final Set notNullColumns = new CopyOnWriteArraySet<>(); + + //鍒嗚〃 绛栫暐 + private final DistributeTableStrategy tableStrategy; + + //鏍规嵁涓婚敭鏌ユ壘鎵鏈夊璞$殑SQL + private final String allQueryPrepareSQL; + + //鏍规嵁涓婚敭鏌ユ壘鍗曚釜瀵硅薄鐨凷QL锛 鍚 锛 + private final String findQuestionPrepareSQL; + + //鏍规嵁涓婚敭鏌ユ壘鍗曚釜瀵硅薄鐨凷QL锛 鍚 $ + private final String findDollarPrepareSQL; + + //鏍规嵁涓婚敭鏌ユ壘鍗曚釜瀵硅薄鐨凷QL锛 鍚 :name + private final String findNamesPrepareSQL; + + //鏁版嵁搴撲腑鎵鏈夊瓧娈 + private final String[] querySqlColumns; + + private final String querySqlColumnSequence; + + private final String querySqlColumnSequenceA; + + //鏁版嵁搴撲腑鎵鏈夊瓧娈, 椤哄簭蹇呴』涓巕uerySqlColumns銆乹uerySqlColumnSequence涓鑷 + private final Attribute[] queryAttributes; + + //鏂板SQL锛 鍚 锛燂紝鍗虫帓闄や簡鑷闀夸富閿拰鏍囪涓@Column(insertable=false)鐨勫瓧娈 + private final String insertQuestionPrepareSQL; + + //鏂板SQL锛 鍚 $锛屽嵆鎺掗櫎浜嗚嚜澧為暱涓婚敭鍜屾爣璁颁负@Column(insertable=false)鐨勫瓧娈 + private final String insertDollarPrepareSQL; + + //鏂板SQL锛 鍚 :name锛屽嵆鎺掗櫎浜嗚嚜澧為暱涓婚敭鍜屾爣璁颁负@Column(insertable=false)鐨勫瓧娈 + private final String insertNamesPrepareSQL; + + //鏁版嵁搴撲腑鎵鏈夊彲鏂板瀛楁 + final Attribute[] insertAttributes; + + //鏍规嵁涓婚敭鏇存柊鎵鏈夊彲鏇存柊瀛楁鐨凷QL锛屽惈 锛 + private final String updateQuestionPrepareSQL; + + //鏍规嵁涓婚敭鏇存柊鎵鏈夊彲鏇存柊瀛楁鐨凷QL锛屽惈 $ + private final String updateDollarPrepareSQL; + + //鏍规嵁涓婚敭鏇存柊鎵鏈夊彲鏇存柊瀛楁鐨凷QL锛屽惈 :name + private final String updateNamesPrepareSQL; + + //鏁版嵁搴撲腑鎵鏈夊彲鏇存柊瀛楁 + final Attribute[] updateAttributes; + + //鏍规嵁涓婚敭鍒犻櫎璁板綍鐨凷QL锛屽惈 锛 + private final String deleteQuestionPrepareSQL; + + //鏍规嵁涓婚敭鍒犻櫎璁板綍鐨凷QL锛屽惈 $ + private final String deleteDollarPrepareSQL; + + //鏍规嵁涓婚敭鍒犻櫎璁板綍鐨凷QL锛屽惈 :name + private final String deleteNamesPrepareSQL; + + //鏃ュ織绾у埆锛屼粠LogLevel鑾峰彇 + private final int logLevel; + + //鏃ュ織鎺у埗 + private final Map excludeLogLevels; + + //Flipper.sort杞崲鎴愪互ORDER BY寮澶碨QL鐨勭紦瀛 + private final Map sortOrderbySqls = new ConcurrentHashMap<>(); + + //鎵灞炵殑DataSource + final DataSource source; + + //鍏ㄩ噺鏁版嵁鐨勫姞杞藉櫒 + final BiFunction> fullloader; + //------------------------------------------------------------ + + /** + * 鍔犺浇EntityInfo + * + * @param clazz Entity绫 + * @param cacheForbidden 鏄惁绂佺敤EntityCache + * @param conf 閰嶇疆淇℃伅, persistence.xml涓殑property鑺傜偣鍊 + * @param source DataSource,鍙负null + * @param fullloader 鍏ㄩ噺鍔犺浇鍣,鍙负null + */ + static EntityInfo load(Class clazz, final boolean cacheForbidden, final Properties conf, + DataSource source, BiFunction> fullloader) { + EntityInfo rs = entityInfos.get(clazz); + if (rs != null && (rs.cache == null || rs.cache.isFullLoaded())) return rs; + synchronized (entityInfos) { + rs = entityInfos.get(clazz); + if (rs == null) { + rs = new EntityInfo(clazz, cacheForbidden, conf, source, fullloader); + entityInfos.put(clazz, rs); + } + if (rs.cache != null && !rs.isCacheFullLoaded()) { + if (fullloader == null) throw new IllegalArgumentException(clazz.getName() + " auto loader is illegal"); + rs.cache.fullLoadAsync(); + } + return rs; + } + } + + /** + * 鑾峰彇Entity绫诲搴旂殑EntityInfo瀵硅薄 + * + * @param 娉涘瀷 + * @param clazz Entity绫 + * + * @return EntityInfo + */ + static EntityInfo get(Class clazz) { + return entityInfos.get(clazz); + } + + /** + * 缁橮repareCompiler浣跨敤锛岀敤浜庨鍔ㄦ佺敓鎴怉ttribute + * + * @since 2.5.0 + * @param 娉涘瀷 + * @param clazz Entity瀹炰綋绫 + * @param source 鏁版嵁婧 + * + * @return EntityInfo + */ + public static EntityInfo compile(Class clazz, DataSource source) { + return new EntityInfo<>(clazz, false, null, source, (BiFunction) null); + } + + /** + * 鏋勯犲嚱鏁 + * + * @param type Entity绫 + * @param cacheForbidden 鏄惁绂佺敤EntityCache + * @param conf 閰嶇疆淇℃伅, persistence.xml涓殑property鑺傜偣鍊 + * @param source DataSource,鍙负null + * @param fullloader 鍏ㄩ噺鍔犺浇鍣,鍙负null + */ + private EntityInfo(Class type, final boolean cacheForbidden, + Properties conf, DataSource source, BiFunction> fullloader) { + this.type = type; + this.source = source; + //--------------------------------------------- + + LogLevel ll = type.getAnnotation(LogLevel.class); + this.logLevel = ll == null ? Integer.MIN_VALUE : Level.parse(ll.value()).intValue(); + Map> logmap = new HashMap<>(); + for (LogExcludeLevel lel : type.getAnnotationsByType(LogExcludeLevel.class)) { + for (String onelevel : lel.levels()) { + int level = Level.parse(onelevel).intValue(); + HashSet set = logmap.get(level); + if (set == null) { + set = new HashSet<>(); + logmap.put(level, set); + } + for (String key : lel.keys()) { + set.add(key); + } + } + } + if (logmap.isEmpty()) { + this.excludeLogLevels = null; + } else { + this.excludeLogLevels = new HashMap<>(); + logmap.forEach((l, set) -> excludeLogLevels.put(l, set.toArray(new String[set.size()]))); + } + //--------------------------------------------- + Table t = type.getAnnotation(Table.class); + if (type.getAnnotation(VirtualEntity.class) != null || (source == null || "memory".equalsIgnoreCase(source.getType()))) { + this.table = null; + BiFunction> loader = null; + try { + VirtualEntity ve = type.getAnnotation(VirtualEntity.class); + if (ve != null) { + loader = ve.loader().getDeclaredConstructor().newInstance(); + RedkaleClassLoader.putReflectionDeclaredConstructors(ve.loader(), ve.loader().getName()); + } + } catch (Exception e) { + logger.log(Level.SEVERE, type + " init @VirtualEntity.loader error", e); + } + this.fullloader = loader; + } else { + this.fullloader = fullloader; + if (t != null && !t.name().isEmpty() && t.name().indexOf('.') >= 0) throw new RuntimeException(type + " have illegal table.name on @Table"); + this.table = (t == null) ? type.getSimpleName().toLowerCase() : (t.catalog().isEmpty()) ? (t.name().isEmpty() ? type.getSimpleName().toLowerCase() : t.name()) : (t.catalog() + '.' + (t.name().isEmpty() ? type.getSimpleName().toLowerCase() : t.name())); + } + DistributeTable dt = type.getAnnotation(DistributeTable.class); + DistributeTableStrategy dts = null; + try { + dts = (dt == null) ? null : dt.strategy().getDeclaredConstructor().newInstance(); + if (dts != null) RedkaleClassLoader.putReflectionDeclaredConstructors(dt.strategy(), dt.strategy().getName()); + } catch (Exception e) { + logger.log(Level.SEVERE, type + " init DistributeTableStrategy error", e); + } + this.tableStrategy = dts; + + this.arrayer = Creator.arrayFunction(type); + this.creator = Creator.create(type); + ConstructorParameters cp = null; + try { + Method cm = this.creator.getClass().getMethod("create", Object[].class); + cp = cm.getAnnotation(ConstructorParameters.class); + RedkaleClassLoader.putReflectionPublicMethods(this.creator.getClass().getName()); + RedkaleClassLoader.putReflectionMethod(this.creator.getClass().getName(), cm); + } catch (Exception e) { + logger.log(Level.SEVERE, type + " cannot find ConstructorParameters Creator", e); + } + this.constructorParameters = (cp == null || cp.value().length < 1) ? null : cp.value(); + Attribute idAttr0 = null; + Map cryptmap0 = null; + Map aliasmap0 = null; + Class cltmp = type; + Set fields = new HashSet<>(); + List querycols = new ArrayList<>(); + List> queryattrs = new ArrayList<>(); + List insertcols = new ArrayList<>(); + List> insertattrs = new ArrayList<>(); + List updatecols = new ArrayList<>(); + List> updateattrs = new ArrayList<>(); + List> ddlList = new ArrayList<>(); + Map> cryptCreatorMap = new HashMap<>(); + do { + List ddl = new ArrayList<>(); + ddlList.add(ddl); + RedkaleClassLoader.putReflectionDeclaredFields(cltmp.getName()); + for (Field field : cltmp.getDeclaredFields()) { + if (Modifier.isStatic(field.getModifiers())) continue; + if (Modifier.isFinal(field.getModifiers())) continue; + if (field.getAnnotation(Transient.class) != null) continue; + if (fields.contains(field.getName())) continue; + final String fieldname = field.getName(); + final Column col = field.getAnnotation(Column.class); + final String sqlfield = col == null || col.name().isEmpty() ? fieldname : col.name(); + if (!fieldname.equals(sqlfield)) { + if (aliasmap0 == null) aliasmap0 = new HashMap<>(); + aliasmap0.put(fieldname, sqlfield); + } + final CryptColumn cpt = field.getAnnotation(CryptColumn.class); + CryptHandler cryptHandler = null; + if (cpt != null) { + if (cryptmap0 == null) cryptmap0 = new HashMap<>(); + cryptHandler = cryptCreatorMap.computeIfAbsent(cpt.handler(), c -> (Creator) Creator.create(cpt.handler())).create(); + cryptmap0.put(fieldname, cryptHandler); + } + Attribute attr; + try { + attr = Attribute.create(type, cltmp, field, cryptHandler); + } catch (RuntimeException e) { + continue; + } + if (field.getAnnotation(javax.persistence.Id.class) != null && idAttr0 == null) { + idAttr0 = attr; + insertcols.add(sqlfield); + insertattrs.add(attr); + RedkaleClassLoader.putReflectionField(cltmp.getName(), field); + } else { + if (col == null || col.insertable()) { + insertcols.add(sqlfield); + insertattrs.add(attr); + } + if (col == null || col.updatable()) { + updatecols.add(sqlfield); + updateattrs.add(attr); + updateAttributeMap.put(fieldname, attr); + } + if (col != null && !col.nullable()) { + notNullColumns.add(fieldname); + } + } + ddl.add(new EntityColumn(field.getAnnotation(javax.persistence.Id.class) != null, col, attr.field(), attr.type(), field.getAnnotation(Comment.class))); + querycols.add(sqlfield); + queryattrs.add(attr); + fields.add(fieldname); + attributeMap.put(fieldname, attr); + } + } while ((cltmp = cltmp.getSuperclass()) != Object.class); + if (idAttr0 == null) throw new RuntimeException(type.getName() + " have no primary column by @javax.persistence.Id"); + cltmp = type; + JsonConvert convert = DEFAULT_JSON_CONVERT; + do { + for (Method method : cltmp.getDeclaredMethods()) { + if (method.getAnnotation(SourceConvert.class) == null) continue; + if (!Modifier.isStatic(method.getModifiers())) throw new RuntimeException("@SourceConvert method(" + method + ") must be static"); + if (method.getReturnType() != JsonConvert.class) throw new RuntimeException("@SourceConvert method(" + method + ") must be return JsonConvert.class"); + if (method.getParameterCount() > 0) throw new RuntimeException("@SourceConvert method(" + method + ") must be 0 parameter"); + try { + method.setAccessible(true); + convert = (JsonConvert) method.invoke(null); + } catch (Exception e) { + throw new RuntimeException(method + " invoke error", e); + } + if (convert != null) break; + } + } while ((cltmp = cltmp.getSuperclass()) != Object.class); + this.jsonConvert = convert == null ? DEFAULT_JSON_CONVERT : convert; + + this.primary = idAttr0; + this.aliasmap = aliasmap0; + this.cryptmap = cryptmap0; + List ddls = new ArrayList<>(); + Collections.reverse(ddlList); //鐖剁被鐨勫瓧娈垫帓鍦ㄥ墠闈 + for (List ls : ddlList) { + ddls.addAll(ls); + } + this.ddlColumns = ddls.toArray(new EntityColumn[ddls.size()]); + this.attributes = attributeMap.values().toArray(new Attribute[attributeMap.size()]); + this.insertAttributes = insertattrs.toArray(new Attribute[insertattrs.size()]); + this.updateAttributes = updateattrs.toArray(new Attribute[updateattrs.size()]); + if (this.constructorParameters == null) { + this.constructorAttributes = null; + this.unconstructorAttributes = null; + } else { + this.constructorAttributes = new Attribute[this.constructorParameters.length]; + List> unconstructorAttrs = new ArrayList<>(); + List newquerycols1 = new ArrayList<>(); + List newquerycols2 = new ArrayList<>(); + for (Attribute attr : new ArrayList<>(queryattrs)) { + int pos = -1; + for (int i = 0; i < this.constructorParameters.length; i++) { + if (attr.field().equals(this.constructorParameters[i])) { + pos = i; + break; + } + } + if (pos >= 0) { + this.constructorAttributes[pos] = attr; + newquerycols1.add(querycols.get(queryattrs.indexOf(attr))); + } else { + unconstructorAttrs.add(attr); + newquerycols2.add(querycols.get(queryattrs.indexOf(attr))); + } + } + this.unconstructorAttributes = unconstructorAttrs.toArray(new Attribute[unconstructorAttrs.size()]); + newquerycols1.addAll(newquerycols2); + querycols = newquerycols1; + List> newqueryattrs = new ArrayList<>(); + newqueryattrs.addAll(List.of(constructorAttributes)); + newqueryattrs.addAll(unconstructorAttrs); + queryattrs = newqueryattrs; + } + this.querySqlColumns = querycols.toArray(new String[querycols.size()]); + this.querySqlColumnSequence = Utility.joining(querySqlColumns, ','); + this.querySqlColumnSequenceA = "a." + Utility.joining(querySqlColumns, ",a."); + this.queryAttributes = queryattrs.toArray(new Attribute[queryattrs.size()]); + if (table != null) { + StringBuilder querydb = new StringBuilder(); + int index = 0; + for (String col : querycols) { + if (index > 0) querydb.append(','); + querydb.append(col); + index++; + } + StringBuilder insertsb = new StringBuilder(); + StringBuilder insertsbquestion = new StringBuilder(); + StringBuilder insertsbdollar = new StringBuilder(); + StringBuilder insertsbnames = new StringBuilder(); + index = 0; + for (String col : insertcols) { + if (index > 0) insertsb.append(','); + insertsb.append(col); + if (index > 0) { + insertsbquestion.append(','); + insertsbdollar.append(','); + insertsbnames.append(','); + } + insertsbquestion.append('?'); + insertsbdollar.append("$").append(++index); + insertsbnames.append(":").append(col); + } + this.insertQuestionPrepareSQL = "INSERT INTO " + (this.tableStrategy == null ? table : "${newtable}") + "(" + insertsb + ") VALUES(" + insertsbquestion + ")"; + this.insertDollarPrepareSQL = "INSERT INTO " + (this.tableStrategy == null ? table : "${newtable}") + "(" + insertsb + ") VALUES(" + insertsbdollar + ")"; + this.insertNamesPrepareSQL = "INSERT INTO " + (this.tableStrategy == null ? table : "${newtable}") + "(" + insertsb + ") VALUES(" + insertsbnames + ")"; + StringBuilder updatesbquestion = new StringBuilder(); + StringBuilder updatesbdollar = new StringBuilder(); + StringBuilder updatesbnames = new StringBuilder(); + index = 0; + for (String col : updatecols) { + if (index > 0) { + updatesbquestion.append(", "); + updatesbdollar.append(", "); + updatesbnames.append(", "); + } + updatesbquestion.append(col).append(" = ?"); + updatesbdollar.append(col).append(" = ").append("$").append(++index); + updatesbnames.append(col).append(" = :").append(col); + } + this.updateQuestionPrepareSQL = "UPDATE " + (this.tableStrategy == null ? table : "${newtable}") + " SET " + updatesbquestion + " WHERE " + getPrimarySQLColumn(null) + " = ?"; + this.updateDollarPrepareSQL = "UPDATE " + (this.tableStrategy == null ? table : "${newtable}") + " SET " + updatesbdollar + " WHERE " + getPrimarySQLColumn(null) + " = $" + (++index); + this.updateNamesPrepareSQL = "UPDATE " + (this.tableStrategy == null ? table : "${newtable}") + " SET " + updatesbnames + " WHERE " + getPrimarySQLColumn(null) + " = :" + getPrimarySQLColumn(null); + this.deleteQuestionPrepareSQL = "DELETE FROM " + (this.tableStrategy == null ? table : "${newtable}") + " WHERE " + getPrimarySQLColumn(null) + " = ?"; + this.deleteDollarPrepareSQL = "DELETE FROM " + (this.tableStrategy == null ? table : "${newtable}") + " WHERE " + getPrimarySQLColumn(null) + " = $1"; + this.deleteNamesPrepareSQL = "DELETE FROM " + (this.tableStrategy == null ? table : "${newtable}") + " WHERE " + getPrimarySQLColumn(null) + " = :" + getPrimarySQLColumn(null); + this.allQueryPrepareSQL = "SELECT " + querydb + " FROM " + table; + this.findQuestionPrepareSQL = "SELECT " + querydb + " FROM " + table + " WHERE " + getPrimarySQLColumn(null) + " = ?"; + this.findDollarPrepareSQL = "SELECT " + querydb + " FROM " + table + " WHERE " + getPrimarySQLColumn(null) + " = $1"; + this.findNamesPrepareSQL = "SELECT " + querydb + " FROM " + table + " WHERE " + getPrimarySQLColumn(null) + " = :" + getPrimarySQLColumn(null); + } else { + this.allQueryPrepareSQL = null; + + this.insertQuestionPrepareSQL = null; + this.updateQuestionPrepareSQL = null; + this.deleteQuestionPrepareSQL = null; + this.findQuestionPrepareSQL = null; + + this.insertDollarPrepareSQL = null; + this.updateDollarPrepareSQL = null; + this.deleteDollarPrepareSQL = null; + this.findDollarPrepareSQL = null; + + this.insertNamesPrepareSQL = null; + this.updateNamesPrepareSQL = null; + this.deleteNamesPrepareSQL = null; + this.findNamesPrepareSQL = null; + } + //----------------cache-------------- + Cacheable c = type.getAnnotation(Cacheable.class); + if (this.table == null || (!cacheForbidden && c != null && c.value())) { + this.cache = new EntityCache<>(this, c); + } else { + this.cache = null; + } + } + + @SuppressWarnings("unchecked") + public V getSubobject(String name) { + return (V) this.subobjectMap.get(name); + } + + public void setSubobject(String name, Object value) { + this.subobjectMap.put(name, value); + } + + public void removeSubobject(String name) { + this.subobjectMap.remove(name); + } + + public void clearSubobjects() { + this.subobjectMap.clear(); + } + + /** + * 鑾峰彇JsonConvert + * + * @return JsonConvert + */ + public JsonConvert getJsonConvert() { + return jsonConvert; + } + + /** + * 鑾峰彇Entity缂撳瓨鍣 + * + * @return EntityCache + */ + public EntityCache getCache() { + return cache; + } + + /** + * 鍒ゆ柇缂撳瓨鍣ㄦ槸鍚﹀凡缁忓叏閲忓姞杞借繃 + * + * @return boolean + */ + public boolean isCacheFullLoaded() { + return cache != null && cache.isFullLoaded(); + } + + /** + * 鑾峰彇Entity鏋勫缓鍣 + * + * @return Creator + */ + public Creator getCreator() { + return creator; + } + + /** + * 鑾峰彇Entity鏁扮粍鏋勫缓鍣 + * + * @return Creator + */ + public IntFunction getArrayer() { + return arrayer; + } + + /** + * 鑾峰彇Entity绫诲悕 + * + * @return Class + */ + public Class getType() { + return type; + } + + /** + * 鍒ゆ柇Entity鏄惁涓鸿櫄鎷熺被 + * + * @return boolean + */ + public boolean isVirtualEntity() { + return table == null; + } + + public DistributeTableStrategy getTableStrategy() { + return tableStrategy; + } + + public Object disTableLock() { + return tables; + } + + public boolean containsDisTable(String tablekey) { + return tables.contains(tablekey); + } + + public void addDisTable(String tablekey) { + tables.add(tablekey); + } + + public boolean removeDisTable(String tablekey) { + return tables.remove(tablekey); + } + + public EntityColumn[] getDDLColumns() { + return ddlColumns; + } + + public Attribute[] getInsertAttributes() { + return insertAttributes; + } + + public Attribute[] getUpdateAttributes() { + return updateAttributes; + } + + public Attribute[] getQueryAttributes() { + return queryAttributes; + } + + /** + * 鑾峰彇Entity鐨凲UERY SQL + * + * @param pk 涓婚敭鍊 + * + * @return String + */ + public String getFindQuestionPrepareSQL(Serializable pk) { + if (this.tableStrategy == null) return findQuestionPrepareSQL; + return findQuestionPrepareSQL.replace("${newtable}", getTable(pk)); + } + + /** + * 鑾峰彇Entity鐨凲UERY SQL + * + * + * @return String + */ + public String getAllQueryPrepareSQL() { + return this.allQueryPrepareSQL; + } + + /** + * 鑾峰彇Entity鐨凲UERY SQL + * + * @param pk 涓婚敭鍊 + * + * @return String + */ + public String getFindDollarPrepareSQL(Serializable pk) { + if (this.tableStrategy == null) return findDollarPrepareSQL; + return findDollarPrepareSQL.replace("${newtable}", getTable(pk)); + } + + /** + * 鑾峰彇Entity鐨凲UERY SQL + * + * @param pk 涓婚敭鍊 + * + * @return String + */ + public String getFindNamesPrepareSQL(Serializable pk) { + if (this.tableStrategy == null) return findNamesPrepareSQL; + return findNamesPrepareSQL.replace("${newtable}", getTable(pk)); + } + + /** + * 鑾峰彇Entity鐨処NSERT SQL + * + * @param bean Entity瀵硅薄 + * + * @return String + */ + public String getInsertQuestionPrepareSQL(T bean) { + if (this.tableStrategy == null) return insertQuestionPrepareSQL; + return insertQuestionPrepareSQL.replace("${newtable}", getTable(bean)); + } + + /** + * 鑾峰彇Entity鐨処NSERT SQL + * + * @param bean Entity瀵硅薄 + * + * @return String + */ + public String getInsertDollarPrepareSQL(T bean) { + if (this.tableStrategy == null) return insertDollarPrepareSQL; + return insertDollarPrepareSQL.replace("${newtable}", getTable(bean)); + } + + /** + * 鑾峰彇Entity鐨処NSERT SQL + * + * @param bean Entity瀵硅薄 + * + * @return String + */ + public String getInsertNamesPrepareSQL(T bean) { + if (this.tableStrategy == null) return insertNamesPrepareSQL; + return insertNamesPrepareSQL.replace("${newtable}", getTable(bean)); + } + + /** + * 鑾峰彇Entity鐨刄PDATE SQL + * + * @param bean Entity瀵硅薄 + * + * @return String + */ + public String getUpdateQuestionPrepareSQL(T bean) { + if (this.tableStrategy == null) return updateQuestionPrepareSQL; + return updateQuestionPrepareSQL.replace("${newtable}", getTable(bean)); + } + + /** + * 鑾峰彇Entity鐨刄PDATE SQL + * + * @param bean Entity瀵硅薄 + * + * @return String + */ + public String getUpdateDollarPrepareSQL(T bean) { + if (this.tableStrategy == null) return updateDollarPrepareSQL; + return updateDollarPrepareSQL.replace("${newtable}", getTable(bean)); + } + + /** + * 鑾峰彇Entity鐨刄PDATE SQL + * + * @param bean Entity瀵硅薄 + * + * @return String + */ + public String getUpdateNamesPrepareSQL(T bean) { + if (this.tableStrategy == null) return updateNamesPrepareSQL; + return updateNamesPrepareSQL.replace("${newtable}", getTable(bean)); + } + + /** + * 鑾峰彇Entity鐨凞ELETE SQL + * + * @param bean Entity瀵硅薄 + * + * @return String + */ + public String getDeleteQuestionPrepareSQL(T bean) { + if (this.tableStrategy == null) return deleteQuestionPrepareSQL; + return deleteQuestionPrepareSQL.replace("${newtable}", getTable(bean)); + } + + /** + * 鑾峰彇Entity鐨凞ELETE SQL + * + * @param bean Entity瀵硅薄 + * + * @return String + */ + public String getDeleteDollarPrepareSQL(T bean) { + if (this.tableStrategy == null) return deleteDollarPrepareSQL; + return deleteDollarPrepareSQL.replace("${newtable}", getTable(bean)); + } + + /** + * 鑾峰彇Entity鐨凞ELETE SQL + * + * @param bean Entity瀵硅薄 + * + * @return String + */ + public String getDeleteNamesPrepareSQL(T bean) { + if (this.tableStrategy == null) return deleteNamesPrepareSQL; + return deleteNamesPrepareSQL.replace("${newtable}", getTable(bean)); + } + + /** + * 鑾峰彇鏌ヨ瀛楁鍒楄〃 + * + * @param tabalis 琛ㄥ埆鍚 + * @param selects 杩囨护瀛楁 + * + * @return String + */ + public CharSequence getQueryColumns(String tabalis, SelectColumn selects) { + if (selects == null) { + if (tabalis == null) return querySqlColumnSequence; + if ("a".equals(tabalis)) return querySqlColumnSequenceA; + return tabalis + "." + Utility.joining(querySqlColumns, "," + tabalis + "."); + } + StringBuilder sb = new StringBuilder(); + for (Attribute attr : this.attributes) { + if (!selects.test(attr.field())) continue; + if (sb.length() > 0) sb.append(','); + sb.append(getSQLColumn(tabalis, attr.field())); + } + if (sb.length() == 0) sb.append('*'); + return sb; + } + + public CharSequence getFullQueryColumns(String tabalis, SelectColumn selects) { + if (selects == null) { + if (tabalis == null) { + return querySqlColumnSequence; + } else { + StringBuilder sb = new StringBuilder(); + String s = tabalis + "."; + for (String col : querySqlColumns) { + if (sb.length() > 0) sb.append(','); + sb.append(s).append(col); + } + return sb; + } + } else { + StringBuilder sb = new StringBuilder(); + for (Attribute attr : this.attributes) { + if (!selects.test(attr.field())) continue; + if (sb.length() > 0) sb.append(','); + sb.append(getSQLColumn(tabalis, attr.field())); + } + if (sb.length() == 0) sb.append('*'); + return sb; + } + } + + public String getOriginTable() { + return table; + } + + /** + * 鏍规嵁涓婚敭鍊艰幏鍙朎ntity鐨勮〃鍚 + * + * @param primary Entity涓婚敭鍊 + * + * @return String + */ + public String getTable(Serializable primary) { + if (tableStrategy == null) return table; + String t = tableStrategy.getTable(table, primary); + return t == null || t.isEmpty() ? table : t; + } + + /** + * 鏍规嵁杩囨护鏉′欢鑾峰彇Entity鐨勮〃鍚 + * + * @param node 杩囨护鏉′欢 + * + * @return String + */ + public String getTable(FilterNode node) { + if (tableStrategy == null) return table; + String t = tableStrategy.getTable(table, node); + return t == null || t.isEmpty() ? table : t; + } + + /** + * 鏍规嵁Entity瀵硅薄鑾峰彇Entity鐨勮〃鍚 + * + * @param bean Entity瀵硅薄 + * + * @return String + */ + public String getTable(T bean) { + if (tableStrategy == null) return table; + String t = tableStrategy.getTable(table, bean); + return t == null || t.isEmpty() ? table : t; + } + + /** + * 鑾峰彇涓婚敭瀛楁鐨凙ttribute + * + * @return Attribute + */ + public Attribute getPrimary() { + return this.primary; + } + + /** + * 閬嶅巻鏁版嵁搴撹〃瀵瑰簲鐨勬墍鏈夊瓧娈, 涓嶅寘鍚@Transient瀛楁 + * + * @param action BiConsumer + */ + public void forEachAttribute(BiConsumer> action) { + this.attributeMap.forEach(action); + } + + /** + * 鏍规嵁Entity瀛楁鍚嶈幏鍙栧瓧娈电殑Attribute + * + * @param fieldname Class瀛楁鍚 + * + * @return Attribute + */ + public Attribute getAttribute(String fieldname) { + if (fieldname == null) return null; + return this.attributeMap.get(fieldname); + } + + /** + * 鏍规嵁Entity瀛楁鍚嶈幏鍙栧彲鏇存柊瀛楁鐨凙ttribute + * + * @param fieldname Class瀛楁鍚 + * + * @return Attribute + */ + public Attribute getUpdateAttribute(String fieldname) { + return this.updateAttributeMap.get(fieldname); + } + + /** + * 鍒ゆ柇Entity绫荤殑瀛楁鍚嶄笌琛ㄥ瓧娈靛悕s鏄惁瀛樺湪涓嶄竴鑷寸殑鍊 + * + * @return boolean + */ + public boolean isNoAlias() { + return this.aliasmap == null; + } + + /** + * 鏍规嵁Flipper鑾峰彇ORDER BY鐨凷QL璇彞锛屼笉瀛樺湪Flipper鎴杝ort瀛楁杩斿洖绌哄瓧绗︿覆 + * + * @param flipper 缈婚〉瀵硅薄 + * + * @return String + */ + protected String createSQLOrderby(Flipper flipper) { + if (flipper == null || flipper.getSort() == null) return ""; + final String sort = flipper.getSort(); + if (sort.isEmpty() || sort.indexOf(';') >= 0 || sort.indexOf('\n') >= 0) return ""; + String sql = this.sortOrderbySqls.get(sort); + if (sql != null) return sql; + final StringBuilder sb = new StringBuilder(); + sb.append(" ORDER BY "); + if (isNoAlias()) { + sb.append(sort); + } else { + boolean flag = false; + for (String item : sort.split(",")) { + if (item.isEmpty()) continue; + String[] sub = item.split("\\s+"); + if (flag) sb.append(','); + if (sub.length < 2 || sub[1].equalsIgnoreCase("ASC")) { + sb.append(getSQLColumn("a", sub[0])).append(" ASC"); + } else { + sb.append(getSQLColumn("a", sub[0])).append(" DESC"); + } + flag = true; + } + } + sql = sb.toString(); + this.sortOrderbySqls.put(sort, sql); + return sql; + } + + /** + * 鏍规嵁field瀛楁鍚嶈幏鍙栨暟鎹簱瀵瑰簲鐨勫瓧娈靛悕 + * + * @param tabalis 琛ㄥ埆鍚 + * @param fieldname 瀛楁鍚 + * + * @return String + */ + public String getSQLColumn(String tabalis, String fieldname) { + return this.aliasmap == null ? (tabalis == null ? fieldname : (tabalis + '.' + fieldname)) + : (tabalis == null ? aliasmap.getOrDefault(fieldname, fieldname) : (tabalis + '.' + aliasmap.getOrDefault(fieldname, fieldname))); + } + + /** + * 瀛楁鍊艰浆鎹㈡垚鏁版嵁搴撶殑鍊 + * + * @param fieldname 瀛楁鍚 + * @param fieldvalue 瀛楁鍊 + * + * @return Object + */ + public Object getSQLValue(String fieldname, Serializable fieldvalue) { + if (fieldvalue == null && fieldname != null && isNotNullable(fieldname)) { + if (isNotNullJson(getAttribute(fieldname))) return ""; + } + if (this.cryptmap == null) return fieldvalue; + CryptHandler handler = this.cryptmap.get(fieldname); + if (handler == null) return fieldvalue; + return handler.encrypt(fieldvalue); + } + + /** + * 瀛楁鍊艰浆鎹㈡垚甯﹁浆涔夌殑鏁版嵁搴撶殑鍊 + * + * @param fieldname 瀛楁鍚 + * @param fieldvalue 瀛楁鍊 + * @param sqlFormatter 杞箟鍣 + * + * @return CharSequence + */ + public CharSequence formatSQLValue(String fieldname, Serializable fieldvalue, BiFunction sqlFormatter) { + Object val = getSQLValue(fieldname, fieldvalue); + return sqlFormatter == null ? formatToString(val) : sqlFormatter.apply(this, val); + } + + /** + * 瀛楁鍊艰浆鎹㈡垚甯﹁浆涔夌殑鏁版嵁搴撶殑鍊 + * + * @param value 瀛楁鍊 + * @param sqlFormatter 杞箟鍣 + * + * @return CharSequence + */ + public CharSequence formatSQLValue(Object value, BiFunction sqlFormatter) { + return sqlFormatter == null ? formatToString(value) : sqlFormatter.apply(this, value); + } + + /** + * 瀛楁鍊艰浆鎹㈡垚鏁版嵁搴撶殑鍊 + * + * @param 娉涘瀷 + * @param attr Attribute + * @param entity 璁板綍瀵硅薄 + * + * @return Object + */ + public Object getSQLValue(Attribute attr, T entity) { + Object val = attr.get(entity); + CryptHandler cryptHandler = attr.attach(); + if (cryptHandler != null) val = cryptHandler.encrypt(val); + return val; + } + + /** + * 瀛楁鍊艰浆鎹㈡垚甯﹁浆涔夌殑鏁版嵁搴撶殑鍊 + * + * @param 娉涘瀷 + * @param attr Attribute + * @param entity 璁板綍瀵硅薄 + * @param sqlFormatter 杞箟鍣 + * + * @return CharSequence + */ + public CharSequence formatSQLValue(Attribute attr, T entity, BiFunction sqlFormatter) { + Object val = getSQLValue(attr, entity); + return sqlFormatter == null ? formatToString(val) : sqlFormatter.apply(this, val); + } + + /** + * 鏁版嵁搴撶殑鍊艰浆鎹㈡垚鏁板瓧娈靛 + * + * @param attr Attribute + * @param entity 璁板綍瀵硅薄 + * + * @return Object + */ + public Serializable getFieldValue(Attribute attr, T entity) { + Serializable val = attr.get(entity); + CryptHandler cryptHandler = attr.attach(); + if (cryptHandler != null) val = (Serializable) cryptHandler.decrypt(val); + return val; + } + + /** + * 鑾峰彇涓婚敭瀛楁鍚 + * + * @return String + */ + public String getPrimaryColumn() { + return this.primary.field(); + } + + /** + * 鑾峰彇涓婚敭瀛楁鐨勮〃瀛楁鍚 + * + * @return String + */ + public String getPrimarySQLColumn() { + return getSQLColumn(null, this.primary.field()); + } + + /** + * 鑾峰彇涓婚敭瀛楁鐨勫甫鏈夎〃鍒悕鐨勮〃瀛楁鍚 + * + * @param tabalis 琛ㄥ埆鍚 + * + * @return String + */ + public String getPrimarySQLColumn(String tabalis) { + return getSQLColumn(tabalis, this.primary.field()); + } + + /** + * 鎷兼帴UPDATE缁欏瓧娈佃祴鍊肩殑SQL鐗囨 + * + * @param sqlColumn 琛ㄥ瓧娈靛悕 + * @param attr Attribute + * @param cv ColumnValue + * @param formatter 杞箟鍣 + * + * @return CharSequence + */ + protected CharSequence formatSQLValue(String sqlColumn, Attribute attr, final ColumnValue cv, BiFunction formatter) { + if (cv == null) return null; + Object val = cv.getValue(); + //ColumnNodeValue鏃 cv.getExpress() == ColumnExpress.MOV 鍙敤浜巙pdateColumn + if (val instanceof ColumnNodeValue) return formatSQLValue(attr, null, (ColumnNodeValue) val, formatter); + if (val instanceof ColumnFuncNode) return formatSQLValue(attr, null, (ColumnFuncNode) val, formatter); + switch (cv.getExpress()) { + case INC: + return new StringBuilder().append(sqlColumn).append(" + ").append(val); + case DEC: + return new StringBuilder().append(sqlColumn).append(" - ").append(val); + case MUL: + return new StringBuilder().append(sqlColumn).append(" * ").append(val); + case DIV: + return new StringBuilder().append(sqlColumn).append(" / ").append(val); + case MOD: + return new StringBuilder().append(sqlColumn).append(" % ").append(val); + case AND: + return new StringBuilder().append(sqlColumn).append(" & ").append(val); + case ORR: + return new StringBuilder().append(sqlColumn).append(" | ").append(val); + case MOV: + CryptHandler handler = attr.attach(); + if (handler != null) val = handler.encrypt(val); + CharSequence rs = formatter == null ? formatToString(val) : formatter.apply(this, val); + if (rs == null && isNotNullJson(attr)) rs = ""; + return rs; + } + CryptHandler handler = attr.attach(); + if (handler != null) val = handler.encrypt(val); + return formatter == null ? formatToString(val) : formatter.apply(this, val); + } + + protected CharSequence formatSQLValue(Attribute attr, String tabalis, final ColumnFuncNode node, BiFunction formatter) { + if (node.getValue() instanceof ColumnNodeValue) { + return node.getFunc().getColumn(formatSQLValue(attr, tabalis, (ColumnNodeValue) node.getValue(), formatter).toString()); + } else { + return node.getFunc().getColumn(this.getSQLColumn(tabalis, String.valueOf(node.getValue()))); + } + } + + protected CharSequence formatSQLValue(Attribute attr, String tabalis, final ColumnNodeValue node, BiFunction formatter) { + Serializable left = node.getLeft(); + if (left instanceof CharSequence) { + left = this.getSQLColumn(tabalis, left.toString()); + if (node.getExpress() == ColumnExpress.MOV) return (String) left; + } else if (left instanceof ColumnNodeValue) { + left = "(" + formatSQLValue(attr, tabalis, (ColumnNodeValue) left, formatter) + ")"; + } else if (left instanceof ColumnFuncNode) { + left = "(" + formatSQLValue(attr, tabalis, (ColumnFuncNode) left, formatter) + ")"; + } + Serializable right = node.getRight(); + if (right instanceof CharSequence) { + right = this.getSQLColumn(null, right.toString()); + } else if (left instanceof ColumnNodeValue) { + right = "(" + formatSQLValue(attr, tabalis, (ColumnNodeValue) right, formatter) + ")"; + } else if (left instanceof ColumnFuncNode) { + right = "(" + formatSQLValue(attr, tabalis, (ColumnFuncNode) right, formatter) + ")"; + } + switch (node.getExpress()) { + case INC: + return new StringBuilder().append(left).append(" + ").append(right); + case DEC: + return new StringBuilder().append(left).append(" - ").append(right); + case MUL: + return new StringBuilder().append(left).append(" * ").append(right); + case DIV: + return new StringBuilder().append(left).append(" / ").append(right); + case MOD: + return new StringBuilder().append(left).append(" % ").append(right); + case AND: + return new StringBuilder().append(left).append(" & ").append(right); + case ORR: + return new StringBuilder().append(left).append(" | ").append(right); + } + throw new IllegalArgumentException(node + " express cannot be null or MOV"); + } + + /** + * 鑾峰彇鎵鏈夋暟鎹〃瀛楁鐨凙ttribute, 涓嶅寘鍚@Transient瀛楁 + * + * @return Map + */ + protected Map> getAttributes() { + return attributeMap; + } + + /** + * 鍒ゆ柇鏃ュ織绾у埆 + * + * @param logger Logger + * @param l Level + * + * @return boolean + */ + public boolean isLoggable(Logger logger, Level l) { + return logger.isLoggable(l) && l.intValue() >= this.logLevel; + } + + public boolean isNotNullable(String fieldname) { + return notNullColumns.contains(fieldname); + } + + public boolean isNotNullable(Attribute attr) { + return attr == null ? false : notNullColumns.contains(attr.field()); + } + + public boolean isNotNullJson(Attribute attr) { + if (attr == null) return false; + return notNullColumns.contains(attr.field()) + && !Number.class.isAssignableFrom(attr.type()) + && !CharSequence.class.isAssignableFrom(attr.type()) + && boolean.class != attr.type() && Boolean.class != attr.type() + && byte[].class != attr.type() + && java.util.Date.class != attr.type() + && !attr.type().getName().startsWith("java.sql.") //閬垮厤寮曠敤import java.sql.* 鍑忓皯妯″潡渚濊禆 + && !attr.type().getName().startsWith("java.time."); + } + + /** + * 鍒ゆ柇鏃ュ織绾у埆 + * + * @param logger Logger + * @param l Level + * @param str String + * + * @return boolean + */ + public boolean isLoggable(Logger logger, Level l, String str) { + boolean rs = logger.isLoggable(l) && l.intValue() >= this.logLevel; + if (this.excludeLogLevels == null || !rs || str == null) return rs; + String[] keys = this.excludeLogLevels.get(l.intValue()); + if (keys == null) return rs; + for (String key : keys) { + if (str.contains(key)) return false; + } + return rs; + } + + /** + * 灏嗗瓧娈靛煎簭鍒楀寲涓哄彲SQL鐨勫瓧绗︿覆 + * + * @param value 瀛楁鍊 + * + * @return String + */ + private String formatToString(Object value) { + if (value == null) return null; + if (value instanceof CharSequence) { + return new StringBuilder().append('\'').append(value.toString().replace("'", "\\'")).append('\'').toString(); + } else if (!(value instanceof Number) && !(value instanceof java.util.Date) + && !value.getClass().getName().startsWith("java.sql.") && !value.getClass().getName().startsWith("java.time.")) { + return new StringBuilder().append('\'').append(jsonConvert.convertTo(value).replace("'", "\\'")).append('\'').toString(); + } + return String.valueOf(value); + } + + /** + * 灏嗕竴琛岀殑ResultSet缁勮鎴愪竴涓狤ntity瀵硅薄 + * + * @param sels 鎸囧畾瀛楁 + * @param row ResultSet + * + * @return Entity瀵硅薄 + */ + protected T getEntityValue(final SelectColumn sels, final DataResultSetRow row) { + if (row.wasNull()) return null; + T obj; + Attribute[] attrs = this.queryAttributes; + if (this.constructorParameters == null) { + obj = creator.create(); + } else { + Object[] cps = new Object[this.constructorParameters.length]; + for (int i = 0; i < this.constructorAttributes.length; i++) { + Attribute attr = this.constructorAttributes[i]; + if (sels == null || sels.test(attr.field())) { + cps[i] = getFieldValue(attr, row, 0); + } + } + obj = creator.create(cps); + attrs = this.unconstructorAttributes; + } + for (Attribute attr : attrs) { + if (sels == null || sels.test(attr.field())) { + attr.set(obj, getFieldValue(attr, row, 0)); + } + } + return obj; + } + + protected T getFullEntityValue(final DataResultSetRow row) { + return getEntityValue(constructorAttributes, constructorAttributes == null ? queryAttributes : unconstructorAttributes, row); + } + + /** + * 灏嗕竴琛岀殑ResultSet缁勮鎴愪竴涓狤ntity瀵硅薄 + * + * @param constructorAttrs 鏋勫缓鍑芥暟鐨凙ttribute鏁扮粍, 澶у皬蹇呴』涓巘his.constructorAttributes鐩稿悓 + * @param unconstructorAttrs 闈炴瀯寤哄嚱鏁扮殑Attribute鏁扮粍 + * @param row ResultSet + * + * @return Entity瀵硅薄 + */ + protected T getEntityValue(final Attribute[] constructorAttrs, final Attribute[] unconstructorAttrs, final DataResultSetRow row) { + if (row.wasNull()) return null; + T obj; + int index = 0; + if (this.constructorParameters == null) { + obj = creator.create(); + } else { + Object[] cps = new Object[this.constructorParameters.length]; + for (int i = 0; i < constructorAttrs.length; i++) { + Attribute attr = constructorAttrs[i]; + if (attr == null) continue; + cps[i] = getFieldValue(attr, row, ++index); + } + obj = creator.create(cps); + } + if (unconstructorAttrs != null) { + for (Attribute attr : unconstructorAttrs) { + if (attr == null) continue; + attr.set(obj, getFieldValue(attr, row, ++index)); + } + } + return obj; + } + + protected Serializable getFieldValue(Attribute attr, final DataResultSetRow row, int index) { + return row.getObject(attr, index, index > 0 ? null : this.getSQLColumn(null, attr.field())); + } + + public static interface DataResultSetRow { + + //index浠1寮濮 + public Object getObject(int index); + + public Object getObject(String column); + + //index浠1寮濮 + default Serializable getObject(Attribute attr, int index, String column) { + return DataResultSet.getRowColumnValue(this, attr, index, column); + } + + //鍒ゆ柇褰撳墠琛屽兼槸鍚︿负null + public boolean wasNull(); + } + + public static class EntityColumn { + + public final boolean primary; //鏄惁涓婚敭 + + public final String field; + + public final String column; + + public final Class type; + + public final String comment; + + public final boolean nullable; + + public final boolean unique; + + public final int length; + + public final int precision; + + public final int scale; + + protected EntityColumn(boolean primary, Column col, String name, Class type, Comment comment) { + this.primary = primary; + this.field = name; + this.column = col == null || col.name().isEmpty() ? name : col.name(); + this.type = type; + this.comment = (col == null || col.comment().isEmpty()) && comment != null && !comment.value().isEmpty() ? comment.value() : (col == null ? "" : col.comment()); + this.nullable = col == null ? false : col.nullable(); + this.unique = col == null ? false : col.unique(); + this.length = col == null ? 255 : col.length(); + this.precision = col == null ? 0 : col.precision(); + this.scale = col == null ? 0 : col.scale(); + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + } +} diff --git a/src/main/java/org/redkale/source/FilterBean.java b/src/main/java/org/redkale/source/FilterBean.java index fdf03fc7c..46caaf9f3 100644 --- a/src/main/java/org/redkale/source/FilterBean.java +++ b/src/main/java/org/redkale/source/FilterBean.java @@ -1,23 +1,23 @@ -/* - * 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.source; - -import org.redkale.util.Bean; - -/** - * FilterBean鐢ㄤ簬杩囨护鏉′欢锛 鎵鏈夌殑FilterBean閮藉繀椤诲彲浠ヨ浆鎹㈡垚FilterNode
- * - * 鏍囪涓@FilterColumn.ignore=true 鐨勫瓧娈典細琚拷鐣ワ紝 涓嶅弬涓庣敓鎴愯繃婊ゆ潯浠
- * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@Bean -public interface FilterBean { - -} +/* + * 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.source; + +import org.redkale.util.Bean; + +/** + * FilterBean鐢ㄤ簬杩囨护鏉′欢锛 鎵鏈夌殑FilterBean閮藉繀椤诲彲浠ヨ浆鎹㈡垚FilterNode
+ * + * 鏍囪涓@FilterColumn.ignore=true 鐨勫瓧娈典細琚拷鐣ワ紝 涓嶅弬涓庣敓鎴愯繃婊ゆ潯浠
+ * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@Bean +public interface FilterBean { + +} diff --git a/src/main/java/org/redkale/source/FilterColumn.java b/src/main/java/org/redkale/source/FilterColumn.java index a8f48f4bc..69998ef64 100644 --- a/src/main/java/org/redkale/source/FilterColumn.java +++ b/src/main/java/org/redkale/source/FilterColumn.java @@ -1,86 +1,86 @@ -/* - * 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.source; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.RetentionPolicy.RUNTIME; -import java.lang.annotation.*; - -/** - * 杩囨护瀛楁鏍囪 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@Inherited -@Documented -@Target({FIELD}) -@Retention(RUNTIME) -public @interface FilterColumn { - - /** - * 瀵瑰簲Entity Class涓瓧娈电殑鍚嶇О锛 鑰屼笉鏄疭QL瀛楁鍚嶇О - * - * @return 瀛楁鍚 - */ - String name() default ""; - - /** - * 褰撳瓧娈电被鍨嬫槸Number鏃讹紝 濡傛灉鍊>=least() 鍒欓渶瑕佽繃婊わ紝 鍚﹀垯璺宠繃璇ュ瓧娈 - * - * @return 鏈灏忓彲杩囨护鍊 - */ - long least() default 1; - - /** - * 鐢熸垚杩囨护鏉′欢鏃舵槸鍚﹀睆钄借瀛楁 - * - * @return 鏄惁灞忚斀璇ュ瓧娈 - * @since 2.4.0 - */ - boolean ignore() default false; - - /** - * express鐨勯粯璁ゅ兼牴鎹瓧娈电被鍨嬬殑涓嶅悓鑰屼笉鍚:
- * 鏁扮粍 --> IN
- * Range --> Between
- * 鍏朵粬 --> =
- * - * @return 瀛楁琛ㄨ揪寮 - */ - FilterExpress express() default FilterExpress.EQUAL; - - /** - * 褰撴爣璁扮殑瀛楁绫诲瀷鏄暟缁/Collection绫诲瀷涓攅xpress涓嶆槸IN/NOTIN鏃讹紝鍒欐瀯寤鸿繃婊ゆ潯浠舵椂浼氶亶鍘嗗瓧娈靛肩殑鍏冪礌鏉ュ惊鐜瀯寤鸿〃杈惧紡锛屽厓绱犱箣闂寸殑鍏崇郴鏄疉ND鎴朞R鐢辫鍊兼潵纭畾 - * - * @return 鏁扮粍鍏冪礌闂寸殑琛ㄨ揪寮忔槸鍚ND鍏崇郴 - */ - boolean itemand() default true; - - /** - * 鍒ゆ柇瀛楁鏄惁蹇呴渶锛宖or OpenAPI Specification 3.1.0 - * - * @return 鏄惁蹇呴渶 - */ - boolean required() default false; - - /** - * for OpenAPI Specification 3.1.0 - * - * @return String - */ - String example() default ""; - - /** - * 澶囨敞鎻忚堪 - * - * @return 澶囨敞鎻忚堪 - */ - String comment() default ""; - -} +/* + * 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.source; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import java.lang.annotation.*; + +/** + * 杩囨护瀛楁鏍囪 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@Inherited +@Documented +@Target({FIELD}) +@Retention(RUNTIME) +public @interface FilterColumn { + + /** + * 瀵瑰簲Entity Class涓瓧娈电殑鍚嶇О锛 鑰屼笉鏄疭QL瀛楁鍚嶇О + * + * @return 瀛楁鍚 + */ + String name() default ""; + + /** + * 褰撳瓧娈电被鍨嬫槸Number鏃讹紝 濡傛灉鍊>=least() 鍒欓渶瑕佽繃婊わ紝 鍚﹀垯璺宠繃璇ュ瓧娈 + * + * @return 鏈灏忓彲杩囨护鍊 + */ + long least() default 1; + + /** + * 鐢熸垚杩囨护鏉′欢鏃舵槸鍚﹀睆钄借瀛楁 + * + * @return 鏄惁灞忚斀璇ュ瓧娈 + * @since 2.4.0 + */ + boolean ignore() default false; + + /** + * express鐨勯粯璁ゅ兼牴鎹瓧娈电被鍨嬬殑涓嶅悓鑰屼笉鍚:
+ * 鏁扮粍 --> IN
+ * Range --> Between
+ * 鍏朵粬 --> =
+ * + * @return 瀛楁琛ㄨ揪寮 + */ + FilterExpress express() default FilterExpress.EQUAL; + + /** + * 褰撴爣璁扮殑瀛楁绫诲瀷鏄暟缁/Collection绫诲瀷涓攅xpress涓嶆槸IN/NOTIN鏃讹紝鍒欐瀯寤鸿繃婊ゆ潯浠舵椂浼氶亶鍘嗗瓧娈靛肩殑鍏冪礌鏉ュ惊鐜瀯寤鸿〃杈惧紡锛屽厓绱犱箣闂寸殑鍏崇郴鏄疉ND鎴朞R鐢辫鍊兼潵纭畾 + * + * @return 鏁扮粍鍏冪礌闂寸殑琛ㄨ揪寮忔槸鍚ND鍏崇郴 + */ + boolean itemand() default true; + + /** + * 鍒ゆ柇瀛楁鏄惁蹇呴渶锛宖or OpenAPI Specification 3.1.0 + * + * @return 鏄惁蹇呴渶 + */ + boolean required() default false; + + /** + * for OpenAPI Specification 3.1.0 + * + * @return String + */ + String example() default ""; + + /** + * 澶囨敞鎻忚堪 + * + * @return 澶囨敞鎻忚堪 + */ + String comment() default ""; + +} diff --git a/src/main/java/org/redkale/source/FilterExpress.java b/src/main/java/org/redkale/source/FilterExpress.java index a6e7fac8a..290ade443 100644 --- a/src/main/java/org/redkale/source/FilterExpress.java +++ b/src/main/java/org/redkale/source/FilterExpress.java @@ -1,71 +1,71 @@ -/* - * 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.source; - -/** - * 鍑芥暟琛ㄨ揪寮忥紝 鍧囦笌SQL瀹氫箟涓殑琛ㄨ揪寮忕浉鍚 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public enum FilterExpress { - - EQUAL("="), - IGNORECASEEQUAL("="),//涓嶅尯鍒嗗ぇ灏忓啓鐨 = - NOTEQUAL("<>"), - IGNORECASENOTEQUAL("="),//涓嶅尯鍒嗗ぇ灏忓啓鐨 <> - GREATERTHAN(">"), - LESSTHAN("<"), - GREATERTHANOREQUALTO(">="), - LESSTHANOREQUALTO("<="), - STARTSWITH("LIKE"), - NOTSTARTSWITH("NOT LIKE"), - ENDSWITH("LIKE"), - NOTENDSWITH("NOT LIKE"), - LIKE("LIKE"), - NOTLIKE("NOT LIKE"), - IGNORECASELIKE("LIKE"), //涓嶅尯鍒嗗ぇ灏忓啓鐨 LIKE - IGNORECASENOTLIKE("NOT LIKE"), //涓嶅尯鍒嗗ぇ灏忓啓鐨 NOT LIKE - LENGTH_EQUAL("="), //瀛楃涓插肩殑闀垮害 - LENGTH_LESSTHAN("<"), //瀛楃涓插肩殑闀垮害 < - LENGTH_LESSTHANOREQUALTO("<="), //瀛楃涓插肩殑闀垮害 <= - LENGTH_GREATERTHAN(">"), //瀛楃涓插肩殑闀垮害 > - LENGTH_GREATERTHANOREQUALTO(">="), //瀛楃涓插肩殑闀垮害 >= - - CONTAIN("CONTAIN"), //鍖呭惈锛 鐩稿綋浜庡弽鍚慙IKE - NOTCONTAIN("NOT CONTAIN"), //涓嶅寘鍚紝 鐩稿綋浜庡弽鍚慙IKE - IGNORECASECONTAIN("CONTAIN"), //涓嶅尯鍒嗗ぇ灏忓啓鐨 CONTAIN - IGNORECASENOTCONTAIN("NOT CONTAIN"), //涓嶅尯鍒嗗ぇ灏忓啓鐨 NOT CONTAIN - - BETWEEN("BETWEEN"), - NOTBETWEEN("NOT BETWEEN"), - IN("IN"), - NOTIN("NOT IN"), - ISNULL("IS NULL"), - ISNOTNULL("IS NOT NULL"), - ISEMPTY("="),//鍊间负绌 - ISNOTEMPTY("<>"), //鍊间笉涓虹┖ - OPAND("&"), //涓庤繍绠 > 0 - OPOR("|"), //鎴栬繍绠 > 0 - OPANDNO("&"), //涓庤繍绠 == 0 - FV_MOD("%"), //鍙栨ā杩愮畻锛岄渶瑕佷笌FilterValue閰嶅悎浣跨敤 - FV_DIV("DIV"), //鏁撮櫎杩愮畻锛岄渶瑕佷笌FilterValue閰嶅悎浣跨敤 - AND("AND"), - OR("OR"); - - private final String value; - - private FilterExpress(String v) { - this.value = v; - } - - public String value() { - return value; - } - -} +/* + * 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.source; + +/** + * 鍑芥暟琛ㄨ揪寮忥紝 鍧囦笌SQL瀹氫箟涓殑琛ㄨ揪寮忕浉鍚 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public enum FilterExpress { + + EQUAL("="), + IGNORECASEEQUAL("="),//涓嶅尯鍒嗗ぇ灏忓啓鐨 = + NOTEQUAL("<>"), + IGNORECASENOTEQUAL("="),//涓嶅尯鍒嗗ぇ灏忓啓鐨 <> + GREATERTHAN(">"), + LESSTHAN("<"), + GREATERTHANOREQUALTO(">="), + LESSTHANOREQUALTO("<="), + STARTSWITH("LIKE"), + NOTSTARTSWITH("NOT LIKE"), + ENDSWITH("LIKE"), + NOTENDSWITH("NOT LIKE"), + LIKE("LIKE"), + NOTLIKE("NOT LIKE"), + IGNORECASELIKE("LIKE"), //涓嶅尯鍒嗗ぇ灏忓啓鐨 LIKE + IGNORECASENOTLIKE("NOT LIKE"), //涓嶅尯鍒嗗ぇ灏忓啓鐨 NOT LIKE + LENGTH_EQUAL("="), //瀛楃涓插肩殑闀垮害 + LENGTH_LESSTHAN("<"), //瀛楃涓插肩殑闀垮害 < + LENGTH_LESSTHANOREQUALTO("<="), //瀛楃涓插肩殑闀垮害 <= + LENGTH_GREATERTHAN(">"), //瀛楃涓插肩殑闀垮害 > + LENGTH_GREATERTHANOREQUALTO(">="), //瀛楃涓插肩殑闀垮害 >= + + CONTAIN("CONTAIN"), //鍖呭惈锛 鐩稿綋浜庡弽鍚慙IKE + NOTCONTAIN("NOT CONTAIN"), //涓嶅寘鍚紝 鐩稿綋浜庡弽鍚慙IKE + IGNORECASECONTAIN("CONTAIN"), //涓嶅尯鍒嗗ぇ灏忓啓鐨 CONTAIN + IGNORECASENOTCONTAIN("NOT CONTAIN"), //涓嶅尯鍒嗗ぇ灏忓啓鐨 NOT CONTAIN + + BETWEEN("BETWEEN"), + NOTBETWEEN("NOT BETWEEN"), + IN("IN"), + NOTIN("NOT IN"), + ISNULL("IS NULL"), + ISNOTNULL("IS NOT NULL"), + ISEMPTY("="),//鍊间负绌 + ISNOTEMPTY("<>"), //鍊间笉涓虹┖ + OPAND("&"), //涓庤繍绠 > 0 + OPOR("|"), //鎴栬繍绠 > 0 + OPANDNO("&"), //涓庤繍绠 == 0 + FV_MOD("%"), //鍙栨ā杩愮畻锛岄渶瑕佷笌FilterValue閰嶅悎浣跨敤 + FV_DIV("DIV"), //鏁撮櫎杩愮畻锛岄渶瑕佷笌FilterValue閰嶅悎浣跨敤 + AND("AND"), + OR("OR"); + + private final String value; + + private FilterExpress(String v) { + this.value = v; + } + + public String value() { + return value; + } + +} diff --git a/src/main/java/org/redkale/source/FilterFunc.java b/src/main/java/org/redkale/source/FilterFunc.java index 919a01909..756906cee 100644 --- a/src/main/java/org/redkale/source/FilterFunc.java +++ b/src/main/java/org/redkale/source/FilterFunc.java @@ -1,28 +1,28 @@ -/* - * 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.source; - -/** - * 甯歌鐨凷QL鑱氬悎鍑芥暟 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public enum FilterFunc { - AVG, //骞冲潎鍊 - COUNT, //鎬绘暟 - DISTINCTCOUNT, //鍘婚噸鎬绘暟 - MAX, //鏈澶у - MIN, //鏈灏忓 - SUM; //姹傚拰 - - public String getColumn(String col) { - if (this == DISTINCTCOUNT) return "COUNT(DISTINCT " + col + ")"; - return this.name() + "(" + col + ")"; - } -} +/* + * 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.source; + +/** + * 甯歌鐨凷QL鑱氬悎鍑芥暟 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public enum FilterFunc { + AVG, //骞冲潎鍊 + COUNT, //鎬绘暟 + DISTINCTCOUNT, //鍘婚噸鎬绘暟 + MAX, //鏈澶у + MIN, //鏈灏忓 + SUM; //姹傚拰 + + public String getColumn(String col) { + if (this == DISTINCTCOUNT) return "COUNT(DISTINCT " + col + ")"; + return this.name() + "(" + col + ")"; + } +} diff --git a/src/main/java/org/redkale/source/FilterFuncColumn.java b/src/main/java/org/redkale/source/FilterFuncColumn.java index 85daac7eb..d12032dd0 100644 --- a/src/main/java/org/redkale/source/FilterFuncColumn.java +++ b/src/main/java/org/redkale/source/FilterFuncColumn.java @@ -1,93 +1,93 @@ -/* - * 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.source; - -import java.util.Arrays; - -/** - * FilterFuncColumn鐢ㄤ簬getNumberMap鑾峰彇鍒楄〃浼兼暟鎹, getNumberResult鑾峰彇鍗曞瓧娈靛硷紝 getNumberMap鑾峰彇澶氬瓧娈靛 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public class FilterFuncColumn implements java.io.Serializable { - - public static final String COLUMN_NULL = "*"; - - FilterFunc func; - - String[] columns; //涓簄ull锛屽皢浣跨敤*浠f浛 - - Number defvalue; - - public FilterFuncColumn() { - } - - public static FilterFuncColumn create(final FilterFunc func) { - return new FilterFuncColumn(func); - } - - public static FilterFuncColumn create(final FilterFunc func, final String... columns) { - return new FilterFuncColumn(func, columns); - } - - public static FilterFuncColumn create(final FilterFunc func, final Number defvalue, final String... columns) { - return new FilterFuncColumn(func, defvalue, columns); - } - - public String[] cols() { - return columns == null || columns.length == 0 ? new String[]{COLUMN_NULL} : columns; - } - - public String col(String column) { - return column == null || column.isEmpty() ? COLUMN_NULL : column; - } - - public FilterFuncColumn(final FilterFunc func) { - this(func, (Number) null); - } - - public FilterFuncColumn(final FilterFunc func, final String... columns) { - this(func, null, columns); - } - - public FilterFuncColumn(final FilterFunc func, final Number defvalue, final String... columns) { - this.func = func; - this.defvalue = defvalue; - this.columns = columns; - } - - public FilterFunc getFunc() { - return func; - } - - public void setFunc(FilterFunc func) { - this.func = func; - } - - public String[] getColumns() { - return columns; - } - - public void setColumns(String[] columns) { - this.columns = columns; - } - - public Number getDefvalue() { - return defvalue; - } - - public void setDefvalue(Number defvalue) { - this.defvalue = defvalue; - } - - @Override - public String toString() { - return this.getClass().getSimpleName() + "{func:" + this.func + ", columns:" + Arrays.toString(this.columns) + ", defvalue:" + this.defvalue + "}"; - } -} +/* + * 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.source; + +import java.util.Arrays; + +/** + * FilterFuncColumn鐢ㄤ簬getNumberMap鑾峰彇鍒楄〃浼兼暟鎹, getNumberResult鑾峰彇鍗曞瓧娈靛硷紝 getNumberMap鑾峰彇澶氬瓧娈靛 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public class FilterFuncColumn implements java.io.Serializable { + + public static final String COLUMN_NULL = "*"; + + FilterFunc func; + + String[] columns; //涓簄ull锛屽皢浣跨敤*浠f浛 + + Number defvalue; + + public FilterFuncColumn() { + } + + public static FilterFuncColumn create(final FilterFunc func) { + return new FilterFuncColumn(func); + } + + public static FilterFuncColumn create(final FilterFunc func, final String... columns) { + return new FilterFuncColumn(func, columns); + } + + public static FilterFuncColumn create(final FilterFunc func, final Number defvalue, final String... columns) { + return new FilterFuncColumn(func, defvalue, columns); + } + + public String[] cols() { + return columns == null || columns.length == 0 ? new String[]{COLUMN_NULL} : columns; + } + + public String col(String column) { + return column == null || column.isEmpty() ? COLUMN_NULL : column; + } + + public FilterFuncColumn(final FilterFunc func) { + this(func, (Number) null); + } + + public FilterFuncColumn(final FilterFunc func, final String... columns) { + this(func, null, columns); + } + + public FilterFuncColumn(final FilterFunc func, final Number defvalue, final String... columns) { + this.func = func; + this.defvalue = defvalue; + this.columns = columns; + } + + public FilterFunc getFunc() { + return func; + } + + public void setFunc(FilterFunc func) { + this.func = func; + } + + public String[] getColumns() { + return columns; + } + + public void setColumns(String[] columns) { + this.columns = columns; + } + + public Number getDefvalue() { + return defvalue; + } + + public void setDefvalue(Number defvalue) { + this.defvalue = defvalue; + } + + @Override + public String toString() { + return this.getClass().getSimpleName() + "{func:" + this.func + ", columns:" + Arrays.toString(this.columns) + ", defvalue:" + this.defvalue + "}"; + } +} diff --git a/src/main/java/org/redkale/source/FilterGroup.java b/src/main/java/org/redkale/source/FilterGroup.java index 82b21b4da..124379885 100644 --- a/src/main/java/org/redkale/source/FilterGroup.java +++ b/src/main/java/org/redkale/source/FilterGroup.java @@ -1,69 +1,69 @@ -/* - * 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.source; - -import static java.lang.annotation.RetentionPolicy.RUNTIME; -import static java.lang.annotation.ElementType.FIELD; -import java.lang.annotation.*; - -/** - * 榛樿鎯呭喌涓婩ilterBean涓嬬殑杩囨护瀛楁涔嬮棿鏄疉ND鍏崇郴銆
- * 褰撻渶瑕佷娇鐢∣R鎴朅ND OR缁勫悎杩囨护鏌ヨ鏃堕渶瑕佷娇鐢 FilterGroup銆
- * FilterGroup 鐨剉alue 蹇呴』鏄痆OR]鎴栬匸AND]寮澶达紝 澶氱骇闇瑕佺敤鐐.鍒嗛殧銆 (娉: 鏆傛椂涓嶆敮鎸佸绾)
- * 绀轰緥涓: - *

- * public class TestFilterBean implements FilterBean {
- *
- *      private int id;
- *
- *      @FilterGroup("[OR]g1")
- *      private String desc;
- *
- *      @FilterGroup("[OR]g1")
- *      private String name;
- * }
- * 
- * 杞崲鐨凷QL璇彞涓: WHERE id = ? AND (desc = ? OR name = ?) - * - * 绀轰緥浜: - *
- * public class TestFilterBean implements FilterBean {
- *
- *      private int id;
- *
- *      @FilterGroup("[OR]g1.[AND]subg1")
- *      @FilterColumn(express = LIKE)
- *      private String desc;
- *
- *      @FilterGroup("[OR]g1.[AND]subg1")
- *      @FilterColumn(express = LIKE)
- *      private String name;
- *
- *      @FilterGroup("[OR]g1.[OR]subg2")
- *      private int age;
- *
- *      @FilterGroup("[OR]g1.[OR]subg2")
- *      private int birthday;
- * }
- * 
- * 杞崲鐨凷QL璇彞涓: WHERE id = ? AND ((desc LIKE ? AND name LIKE ?) OR (age = ? OR birthday = ?))
- * 鍥犱负榛樿鏄疉ND鍏崇郴锛 @FilterGroup("") 绛変环浜 @FilterGroup("[AND]")
- * 鎵浠ョず渚嬩簩鐨@FilterGroup("[OR]g1.[AND]subg1") 鍙互绠鍖栦负 @FilterGroup("[OR]g1.subg1")
- */ -/** - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@Inherited -@Documented -@Target({FIELD}) -@Retention(RUNTIME) -public @interface FilterGroup { - - String value() default "[AND]"; -} +/* + * 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.source; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import static java.lang.annotation.ElementType.FIELD; +import java.lang.annotation.*; + +/** + * 榛樿鎯呭喌涓婩ilterBean涓嬬殑杩囨护瀛楁涔嬮棿鏄疉ND鍏崇郴銆
+ * 褰撻渶瑕佷娇鐢∣R鎴朅ND OR缁勫悎杩囨护鏌ヨ鏃堕渶瑕佷娇鐢 FilterGroup銆
+ * FilterGroup 鐨剉alue 蹇呴』鏄痆OR]鎴栬匸AND]寮澶达紝 澶氱骇闇瑕佺敤鐐.鍒嗛殧銆 (娉: 鏆傛椂涓嶆敮鎸佸绾)
+ * 绀轰緥涓: + *

+ * public class TestFilterBean implements FilterBean {
+ *
+ *      private int id;
+ *
+ *      @FilterGroup("[OR]g1")
+ *      private String desc;
+ *
+ *      @FilterGroup("[OR]g1")
+ *      private String name;
+ * }
+ * 
+ * 杞崲鐨凷QL璇彞涓: WHERE id = ? AND (desc = ? OR name = ?) + * + * 绀轰緥浜: + *
+ * public class TestFilterBean implements FilterBean {
+ *
+ *      private int id;
+ *
+ *      @FilterGroup("[OR]g1.[AND]subg1")
+ *      @FilterColumn(express = LIKE)
+ *      private String desc;
+ *
+ *      @FilterGroup("[OR]g1.[AND]subg1")
+ *      @FilterColumn(express = LIKE)
+ *      private String name;
+ *
+ *      @FilterGroup("[OR]g1.[OR]subg2")
+ *      private int age;
+ *
+ *      @FilterGroup("[OR]g1.[OR]subg2")
+ *      private int birthday;
+ * }
+ * 
+ * 杞崲鐨凷QL璇彞涓: WHERE id = ? AND ((desc LIKE ? AND name LIKE ?) OR (age = ? OR birthday = ?))
+ * 鍥犱负榛樿鏄疉ND鍏崇郴锛 @FilterGroup("") 绛変环浜 @FilterGroup("[AND]")
+ * 鎵浠ョず渚嬩簩鐨@FilterGroup("[OR]g1.[AND]subg1") 鍙互绠鍖栦负 @FilterGroup("[OR]g1.subg1")
+ */ +/** + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@Inherited +@Documented +@Target({FIELD}) +@Retention(RUNTIME) +public @interface FilterGroup { + + String value() default "[AND]"; +} diff --git a/src/main/java/org/redkale/source/FilterJoinColumn.java b/src/main/java/org/redkale/source/FilterJoinColumn.java index fe03ee3cb..528deb081 100644 --- a/src/main/java/org/redkale/source/FilterJoinColumn.java +++ b/src/main/java/org/redkale/source/FilterJoinColumn.java @@ -1,54 +1,54 @@ -/* - * 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.source; - -import java.lang.annotation.*; -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * 鍏宠仈琛ㄨ繃婊ゆ潯浠
- * 鍏宠仈鍏崇郴琛ㄥ繀椤诲惈涓昏〃锛 涓嶈兘鏄富琛ˋ鍏宠仈琛˙锛岃〃B鍐嶅叧鑱旇〃C锛屽彧鑳芥槸涓昏〃A鍏宠仈琛˙锛屼富琛ˋ鍏宠仈琛–
- * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@Inherited -@Documented -@Target({FIELD}) -@Retention(RUNTIME) -public @interface FilterJoinColumn { - - /** - * 鍏宠仈琛 閫氬父join琛ㄩ粯璁ゅ埆鍚嶄负b/c/d/...鑷锛 琚玧oin琛ㄩ粯璁ゅ埆鍚嶄负a - * - * @return 鍏宠仈琛 - */ - Class table(); - - /** - * - * 澶氫釜鍏宠仈瀛楁, 榛樿浣跨敤join琛(b)鐨勪富閿, join琛ㄤ笌琚玧oin琛(a)鐨勫瓧娈靛繀椤讳竴鏍
- * 渚嬪: SELECT a.* FROM user a INNER JOIN orderinfo b ON a.userid = b.userid AND a.usertype = b.usertype
- * 閭d箞娉ㄨВ涓: @FilterJoinColumn(table = OrderInfo.class, columns = {"userid", "usertype"})
- *

- * columns涓殑瀛楁鍚嶅鏋滀笉涓鑷达紝鍙互灏嗕袱涓瓧娈靛悕鐢=杩炴帴鎴愪竴涓瓧娈靛悕
- * 渚嬪: SELECT a.* FROM user a INNER JOIN orderinfo b ON a.userid = b.buyerid AND a.usertype = b.usertype
- * 閭d箞娉ㄨВ涓: @FilterJoinColumn(table = OrderInfo.class, columns = {"userid=buyerid", "usertype"})
- * - * @return 鍏宠仈瀛楁 - */ - String[] columns(); - - /** - * 澶囨敞鎻忚堪 - * - * @return 澶囨敞鎻忚堪 - */ - String comment() default ""; -} +/* + * 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.source; + +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * 鍏宠仈琛ㄨ繃婊ゆ潯浠
+ * 鍏宠仈鍏崇郴琛ㄥ繀椤诲惈涓昏〃锛 涓嶈兘鏄富琛ˋ鍏宠仈琛˙锛岃〃B鍐嶅叧鑱旇〃C锛屽彧鑳芥槸涓昏〃A鍏宠仈琛˙锛屼富琛ˋ鍏宠仈琛–
+ * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@Inherited +@Documented +@Target({FIELD}) +@Retention(RUNTIME) +public @interface FilterJoinColumn { + + /** + * 鍏宠仈琛 閫氬父join琛ㄩ粯璁ゅ埆鍚嶄负b/c/d/...鑷锛 琚玧oin琛ㄩ粯璁ゅ埆鍚嶄负a + * + * @return 鍏宠仈琛 + */ + Class table(); + + /** + * + * 澶氫釜鍏宠仈瀛楁, 榛樿浣跨敤join琛(b)鐨勪富閿, join琛ㄤ笌琚玧oin琛(a)鐨勫瓧娈靛繀椤讳竴鏍
+ * 渚嬪: SELECT a.* FROM user a INNER JOIN orderinfo b ON a.userid = b.userid AND a.usertype = b.usertype
+ * 閭d箞娉ㄨВ涓: @FilterJoinColumn(table = OrderInfo.class, columns = {"userid", "usertype"})
+ *

+ * columns涓殑瀛楁鍚嶅鏋滀笉涓鑷达紝鍙互灏嗕袱涓瓧娈靛悕鐢=杩炴帴鎴愪竴涓瓧娈靛悕
+ * 渚嬪: SELECT a.* FROM user a INNER JOIN orderinfo b ON a.userid = b.buyerid AND a.usertype = b.usertype
+ * 閭d箞娉ㄨВ涓: @FilterJoinColumn(table = OrderInfo.class, columns = {"userid=buyerid", "usertype"})
+ * + * @return 鍏宠仈瀛楁 + */ + String[] columns(); + + /** + * 澶囨敞鎻忚堪 + * + * @return 澶囨敞鎻忚堪 + */ + String comment() default ""; +} diff --git a/src/main/java/org/redkale/source/FilterJoinNode.java b/src/main/java/org/redkale/source/FilterJoinNode.java index 8cd35934a..37a60b39d 100644 --- a/src/main/java/org/redkale/source/FilterJoinNode.java +++ b/src/main/java/org/redkale/source/FilterJoinNode.java @@ -1,367 +1,367 @@ -/* - * 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.source; - -import java.io.Serializable; -import java.util.*; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.*; -import static org.redkale.source.FilterExpress.EQUAL; -import org.redkale.util.*; - -/** - * @FilterJoinColumn瀵瑰簲鐨凢ilterNode瀵硅薄 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public class FilterJoinNode extends FilterNode { - - private Class joinClass; - - private EntityInfo joinEntity; //鍦ㄨ皟鐢 createSQLJoin 鍜 isCacheUseable 鏃朵細娉ㄥ叆 - - private String[] joinColumns; - - public FilterJoinNode() { - } - - protected FilterJoinNode(Class joinClass, String[] joinColumns, String column, FilterExpress express, boolean itemand, Serializable value) { - Objects.requireNonNull(joinClass); - Objects.requireNonNull(joinColumns); - if (express == null && value != null) { - if (value instanceof Range) { - express = FilterExpress.BETWEEN; - } else if (value instanceof Collection) { - express = FilterExpress.IN; - } else if (value.getClass().isArray()) { - express = FilterExpress.IN; - } - } - this.joinClass = joinClass; - this.joinColumns = joinColumns; - this.column = column; - this.express = express == null ? EQUAL : express; - this.itemand = itemand; - this.value = value; - } - - protected FilterJoinNode(FilterJoinNode node) { - this(node.joinClass, node.joinColumns, node.column, node.express, node.itemand, node.value); - this.joinEntity = node.joinEntity; - this.or = node.or; - this.nodes = node.nodes; - } - - public static FilterJoinNode create(Class joinClass, String joinColumn, String column, Serializable value) { - return create(joinClass, new String[]{joinColumn}, column, value); - } - - public static FilterJoinNode create(Class joinClass, String joinColumn, String column, FilterExpress express, Serializable value) { - return create(joinClass, new String[]{joinColumn}, column, express, value); - } - - public static FilterJoinNode create(Class joinClass, String joinColumn, String column, FilterExpress express, boolean itemand, Serializable value) { - return create(joinClass, new String[]{joinColumn}, column, express, itemand, value); - } - - public static FilterJoinNode create(Class joinClass, String[] joinColumns, String column, Serializable value) { - return create(joinClass, joinColumns, column, null, value); - } - - public static FilterJoinNode create(Class joinClass, String[] joinColumns, String column, FilterExpress express, Serializable value) { - return create(joinClass, joinColumns, column, express, true, value); - } - - public static FilterJoinNode create(Class joinClass, String[] joinColumns, String column, FilterExpress express, boolean itemand, Serializable value) { - return new FilterJoinNode(joinClass, joinColumns, column, express, itemand, value); - } - - @Override - public FilterJoinNode copy() { - FilterJoinNode node = (FilterJoinNode) copy(new FilterJoinNode()); - node.joinClass = this.joinClass; - node.joinEntity = this.joinEntity; - if (this.joinColumns != null) { - node.joinColumns = new String[this.joinColumns.length]; - System.arraycopy(this.joinColumns, 0, node.joinColumns, 0, this.joinColumns.length); - } - return node; - } - - @Override - protected FilterNode any(final FilterNode node0, boolean signor) { - Objects.requireNonNull(node0); - if (!(node0 instanceof FilterJoinNode)) { - throw new IllegalArgumentException(this + (signor ? " or " : " and ") + " a node but " + String.valueOf(node0) + " is not a " + FilterJoinNode.class.getSimpleName()); - } - final FilterJoinNode node = (FilterJoinNode) node0; - if (this.nodes == null) { - this.nodes = new FilterNode[]{node}; - this.or = signor; - return this; - } - if (or == signor || this.column == null) { - this.nodes = Utility.append(this.nodes, node); - if (this.column == null) this.or = signor; - return this; - } - this.nodes = new FilterNode[]{new FilterJoinNode(this), node}; - this.column = null; - this.express = null; - this.itemand = true; - this.value = null; - this.joinClass = null; - this.joinEntity = null; - this.joinColumns = null; - this.or = signor; - return this; - } - - @Override - protected CharSequence createSQLExpress(DataSqlSource source, final EntityInfo info, final Map joinTabalis) { - return super.createSQLExpress(source, this.joinEntity == null ? info : this.joinEntity, joinTabalis); - } - - @Override - protected Predicate createPredicate(final EntityCache cache) { - if (column == null && this.nodes == null) return null; - final EntityCache joinCache = this.joinEntity.getCache(); - final AtomicBoolean more = new AtomicBoolean(); - Predicate filter = createJoinPredicate(more); - Predicate rs = null; - if (filter == null && !more.get()) return rs; - if (filter != null) { - final Predicate inner = filter; - final String[][] localJoinColumns = new String[joinColumns.length][2]; - for (int i = 0; i < joinColumns.length; i++) { - int pos = joinColumns[i].indexOf('='); - if (pos > 0) { - localJoinColumns[i] = new String[]{joinColumns[i].substring(0, pos), joinColumns[i].substring(pos + 1)}; - } else { - localJoinColumns[i] = new String[]{joinColumns[i], joinColumns[i]}; - } - } - rs = new Predicate() { - - @Override - public boolean test(final T t) { - Predicate joinPredicate = null; - for (String[] localJoinColumn : localJoinColumns) { - final Serializable key = cache.getAttribute(localJoinColumn[0]).get(t); - final Attribute joinAttr = joinCache.getAttribute(localJoinColumn[1]); - Predicate p = (E e) -> key.equals(joinAttr.get(e)); - joinPredicate = joinPredicate == null ? p : joinPredicate.and(p); - } - return joinCache.exists(inner.and(joinPredicate)); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append(" #-- ON ").append(localJoinColumns[0][0]).append("=").append(joinClass == null ? "null" : joinClass.getSimpleName()).append(".").append(localJoinColumns[0][1]); - for (int i = 1; i < localJoinColumns.length; i++) { - sb.append(" AND ").append(localJoinColumns[i][0]).append("=").append(joinClass == null ? "null" : joinClass.getSimpleName()).append(".").append(localJoinColumns[i][1]); - } - sb.append(" --# ").append(inner.toString()); - return sb.toString(); - } - }; - } - if (more.get()) { //瀛樺湪涓嶅悓Class鐨勫叧鑱旇〃 - if (this.nodes != null) { - for (FilterNode node : this.nodes) { - if (((FilterJoinNode) node).joinClass == this.joinClass) continue; - Predicate f = node.createPredicate(cache); - if (f == null) continue; - final Predicate one = rs; - final Predicate two = f; - rs = (rs == null) ? f : (or ? new Predicate() { - - @Override - public boolean test(T t) { - return one.test(t) || two.test(t); - } - - @Override - public String toString() { - return "(" + one + " OR " + two + ")"; - } - } : new Predicate() { - - @Override - public boolean test(T t) { - return one.test(t) && two.test(t); - } - - @Override - public String toString() { - return "(" + one + " AND " + two + ")"; - } - }); - } - } - } - return rs; - } - - private Predicate createJoinPredicate(final AtomicBoolean more) { - if (column == null && this.nodes == null) return null; - final EntityCache joinCache = this.joinEntity.getCache(); - Predicate filter = createElementPredicate(joinCache, true); - if (this.nodes != null) { - for (FilterNode node : this.nodes) { - if (((FilterJoinNode) node).joinClass != this.joinClass) { - more.set(true); - continue; - } - Predicate f = ((FilterJoinNode) node).createJoinPredicate(more); - if (f == null) continue; - final Predicate one = filter; - final Predicate two = f; - filter = (filter == null) ? f : (or ? new Predicate() { - - @Override - public boolean test(E t) { - return one.test(t) || two.test(t); - } - - @Override - public String toString() { - return "(" + one + " OR " + two + ")"; - } - } : new Predicate() { - - @Override - public boolean test(E t) { - return one.test(t) && two.test(t); - } - - @Override - public String toString() { - return "(" + one + " AND " + two + ")"; - } - }); - } - } - return filter; - } - - @Override - protected CharSequence createSQLJoin(final Function func, final boolean update, final Map joinTabalis, final Set haset, final EntityInfo info) { - boolean morejoin = false; - if (this.joinEntity == null) { - if (this.joinClass != null) this.joinEntity = func.apply(this.joinClass); - if (this.nodes != null) { - for (FilterNode node : this.nodes) { - if (node instanceof FilterJoinNode) { - FilterJoinNode joinNode = ((FilterJoinNode) node); - if (joinNode.joinClass != null) { - joinNode.joinEntity = func.apply(joinNode.joinClass); - if (this.joinClass != null && this.joinClass != joinNode.joinClass) morejoin = true; - } - } - } - } - } - StringBuilder sb = new StringBuilder(); - if (this.joinClass != null) { - CharSequence cs = createElementSQLJoin(update, joinTabalis, haset, info, this); - if (cs != null) sb.append(cs); - } - if (morejoin) { - Set set = new HashSet<>(); - if (this.joinClass != null) set.add(this.joinClass); - for (FilterNode node : this.nodes) { - if (node instanceof FilterJoinNode) { - FilterJoinNode joinNode = ((FilterJoinNode) node); - if (!set.contains(joinNode.joinClass)) { - CharSequence cs = createElementSQLJoin(update, joinTabalis, haset, info, joinNode); - if (cs != null) { - sb.append(cs); - set.add(joinNode.joinClass); - } - } - } - } - } - return sb; - } - - private static CharSequence createElementSQLJoin(final boolean update, final Map joinTabalis, final Set haset, final EntityInfo info, final FilterJoinNode node) { - if (node.joinClass == null || (haset != null && haset.contains(joinTabalis.get(node.joinClass)))) return null; - StringBuilder sb = new StringBuilder(); - String[] joinColumns = node.joinColumns; - int pos = joinColumns[0].indexOf('='); - if (update) { - sb.append("[").append(node.joinEntity.getTable(node)).append(" ").append(joinTabalis.get(node.joinClass)).append(']'); - sb.append('{').append(info.getSQLColumn("a", pos > 0 ? joinColumns[0].substring(0, pos) : joinColumns[0])).append(" = ").append(node.joinEntity.getSQLColumn(joinTabalis.get(node.joinClass), pos > 0 ? joinColumns[0].substring(pos + 1) : joinColumns[0])); - for (int i = 1; i < joinColumns.length; i++) { - pos = joinColumns[i].indexOf('='); - sb.append(" AND ").append(info.getSQLColumn("a", pos > 0 ? joinColumns[i].substring(0, pos) : joinColumns[i])).append(" = ").append(node.joinEntity.getSQLColumn(joinTabalis.get(node.joinClass), pos > 0 ? joinColumns[i].substring(pos + 1) : joinColumns[i])); - } - sb.append('}'); - } else { - sb.append(" INNER JOIN ").append(node.joinEntity.getTable(node)).append(" ").append(joinTabalis.get(node.joinClass)) - .append(" ON ").append(info.getSQLColumn("a", pos > 0 ? joinColumns[0].substring(0, pos) : joinColumns[0])).append(" = ").append(node.joinEntity.getSQLColumn(joinTabalis.get(node.joinClass), pos > 0 ? joinColumns[0].substring(pos + 1) : joinColumns[0])); - for (int i = 1; i < joinColumns.length; i++) { - pos = joinColumns[i].indexOf('='); - sb.append(" AND ").append(info.getSQLColumn("a", pos > 0 ? joinColumns[i].substring(0, pos) : joinColumns[i])).append(" = ").append(node.joinEntity.getSQLColumn(joinTabalis.get(node.joinClass), pos > 0 ? joinColumns[i].substring(pos + 1) : joinColumns[i])); - } - } - if (haset != null) haset.add(joinTabalis.get(node.joinClass)); - return sb; - } - - @Override - protected boolean isCacheUseable(final Function entityApplyer) { - if (this.joinEntity == null) this.joinEntity = entityApplyer.apply(this.joinClass); - if (!this.joinEntity.isCacheFullLoaded()) return false; - if (this.nodes == null) return true; - for (FilterNode node : this.nodes) { - if (!node.isCacheUseable(entityApplyer)) return false; - } - return true; - } - - @Override - protected void putJoinTabalis(Map map) { - if (this.joinClass != null && !map.containsKey(this.joinClass)) map.put(joinClass, String.valueOf((char) ('b' + map.size()))); - if (this.nodes == null) return; - for (FilterNode node : this.nodes) { - node.putJoinTabalis(map); - } - } - - @Override - protected final boolean isjoin() { - return true; - } - - @Override - public String toString() { - return toString(joinClass == null ? null : joinClass.getSimpleName()).toString(); - } - - public Class getJoinClass() { - return joinClass; - } - - public void setJoinClass(Class joinClass) { - this.joinClass = joinClass; - } - - public String[] getJoinColumns() { - return joinColumns; - } - - public void setJoinColumns(String[] joinColumns) { - this.joinColumns = joinColumns; - } - -} +/* + * 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.source; + +import java.io.Serializable; +import java.util.*; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.*; +import static org.redkale.source.FilterExpress.EQUAL; +import org.redkale.util.*; + +/** + * @FilterJoinColumn瀵瑰簲鐨凢ilterNode瀵硅薄 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public class FilterJoinNode extends FilterNode { + + private Class joinClass; + + private EntityInfo joinEntity; //鍦ㄨ皟鐢 createSQLJoin 鍜 isCacheUseable 鏃朵細娉ㄥ叆 + + private String[] joinColumns; + + public FilterJoinNode() { + } + + protected FilterJoinNode(Class joinClass, String[] joinColumns, String column, FilterExpress express, boolean itemand, Serializable value) { + Objects.requireNonNull(joinClass); + Objects.requireNonNull(joinColumns); + if (express == null && value != null) { + if (value instanceof Range) { + express = FilterExpress.BETWEEN; + } else if (value instanceof Collection) { + express = FilterExpress.IN; + } else if (value.getClass().isArray()) { + express = FilterExpress.IN; + } + } + this.joinClass = joinClass; + this.joinColumns = joinColumns; + this.column = column; + this.express = express == null ? EQUAL : express; + this.itemand = itemand; + this.value = value; + } + + protected FilterJoinNode(FilterJoinNode node) { + this(node.joinClass, node.joinColumns, node.column, node.express, node.itemand, node.value); + this.joinEntity = node.joinEntity; + this.or = node.or; + this.nodes = node.nodes; + } + + public static FilterJoinNode create(Class joinClass, String joinColumn, String column, Serializable value) { + return create(joinClass, new String[]{joinColumn}, column, value); + } + + public static FilterJoinNode create(Class joinClass, String joinColumn, String column, FilterExpress express, Serializable value) { + return create(joinClass, new String[]{joinColumn}, column, express, value); + } + + public static FilterJoinNode create(Class joinClass, String joinColumn, String column, FilterExpress express, boolean itemand, Serializable value) { + return create(joinClass, new String[]{joinColumn}, column, express, itemand, value); + } + + public static FilterJoinNode create(Class joinClass, String[] joinColumns, String column, Serializable value) { + return create(joinClass, joinColumns, column, null, value); + } + + public static FilterJoinNode create(Class joinClass, String[] joinColumns, String column, FilterExpress express, Serializable value) { + return create(joinClass, joinColumns, column, express, true, value); + } + + public static FilterJoinNode create(Class joinClass, String[] joinColumns, String column, FilterExpress express, boolean itemand, Serializable value) { + return new FilterJoinNode(joinClass, joinColumns, column, express, itemand, value); + } + + @Override + public FilterJoinNode copy() { + FilterJoinNode node = (FilterJoinNode) copy(new FilterJoinNode()); + node.joinClass = this.joinClass; + node.joinEntity = this.joinEntity; + if (this.joinColumns != null) { + node.joinColumns = new String[this.joinColumns.length]; + System.arraycopy(this.joinColumns, 0, node.joinColumns, 0, this.joinColumns.length); + } + return node; + } + + @Override + protected FilterNode any(final FilterNode node0, boolean signor) { + Objects.requireNonNull(node0); + if (!(node0 instanceof FilterJoinNode)) { + throw new IllegalArgumentException(this + (signor ? " or " : " and ") + " a node but " + String.valueOf(node0) + " is not a " + FilterJoinNode.class.getSimpleName()); + } + final FilterJoinNode node = (FilterJoinNode) node0; + if (this.nodes == null) { + this.nodes = new FilterNode[]{node}; + this.or = signor; + return this; + } + if (or == signor || this.column == null) { + this.nodes = Utility.append(this.nodes, node); + if (this.column == null) this.or = signor; + return this; + } + this.nodes = new FilterNode[]{new FilterJoinNode(this), node}; + this.column = null; + this.express = null; + this.itemand = true; + this.value = null; + this.joinClass = null; + this.joinEntity = null; + this.joinColumns = null; + this.or = signor; + return this; + } + + @Override + protected CharSequence createSQLExpress(DataSqlSource source, final EntityInfo info, final Map joinTabalis) { + return super.createSQLExpress(source, this.joinEntity == null ? info : this.joinEntity, joinTabalis); + } + + @Override + protected Predicate createPredicate(final EntityCache cache) { + if (column == null && this.nodes == null) return null; + final EntityCache joinCache = this.joinEntity.getCache(); + final AtomicBoolean more = new AtomicBoolean(); + Predicate filter = createJoinPredicate(more); + Predicate rs = null; + if (filter == null && !more.get()) return rs; + if (filter != null) { + final Predicate inner = filter; + final String[][] localJoinColumns = new String[joinColumns.length][2]; + for (int i = 0; i < joinColumns.length; i++) { + int pos = joinColumns[i].indexOf('='); + if (pos > 0) { + localJoinColumns[i] = new String[]{joinColumns[i].substring(0, pos), joinColumns[i].substring(pos + 1)}; + } else { + localJoinColumns[i] = new String[]{joinColumns[i], joinColumns[i]}; + } + } + rs = new Predicate() { + + @Override + public boolean test(final T t) { + Predicate joinPredicate = null; + for (String[] localJoinColumn : localJoinColumns) { + final Serializable key = cache.getAttribute(localJoinColumn[0]).get(t); + final Attribute joinAttr = joinCache.getAttribute(localJoinColumn[1]); + Predicate p = (E e) -> key.equals(joinAttr.get(e)); + joinPredicate = joinPredicate == null ? p : joinPredicate.and(p); + } + return joinCache.exists(inner.and(joinPredicate)); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(" #-- ON ").append(localJoinColumns[0][0]).append("=").append(joinClass == null ? "null" : joinClass.getSimpleName()).append(".").append(localJoinColumns[0][1]); + for (int i = 1; i < localJoinColumns.length; i++) { + sb.append(" AND ").append(localJoinColumns[i][0]).append("=").append(joinClass == null ? "null" : joinClass.getSimpleName()).append(".").append(localJoinColumns[i][1]); + } + sb.append(" --# ").append(inner.toString()); + return sb.toString(); + } + }; + } + if (more.get()) { //瀛樺湪涓嶅悓Class鐨勫叧鑱旇〃 + if (this.nodes != null) { + for (FilterNode node : this.nodes) { + if (((FilterJoinNode) node).joinClass == this.joinClass) continue; + Predicate f = node.createPredicate(cache); + if (f == null) continue; + final Predicate one = rs; + final Predicate two = f; + rs = (rs == null) ? f : (or ? new Predicate() { + + @Override + public boolean test(T t) { + return one.test(t) || two.test(t); + } + + @Override + public String toString() { + return "(" + one + " OR " + two + ")"; + } + } : new Predicate() { + + @Override + public boolean test(T t) { + return one.test(t) && two.test(t); + } + + @Override + public String toString() { + return "(" + one + " AND " + two + ")"; + } + }); + } + } + } + return rs; + } + + private Predicate createJoinPredicate(final AtomicBoolean more) { + if (column == null && this.nodes == null) return null; + final EntityCache joinCache = this.joinEntity.getCache(); + Predicate filter = createElementPredicate(joinCache, true); + if (this.nodes != null) { + for (FilterNode node : this.nodes) { + if (((FilterJoinNode) node).joinClass != this.joinClass) { + more.set(true); + continue; + } + Predicate f = ((FilterJoinNode) node).createJoinPredicate(more); + if (f == null) continue; + final Predicate one = filter; + final Predicate two = f; + filter = (filter == null) ? f : (or ? new Predicate() { + + @Override + public boolean test(E t) { + return one.test(t) || two.test(t); + } + + @Override + public String toString() { + return "(" + one + " OR " + two + ")"; + } + } : new Predicate() { + + @Override + public boolean test(E t) { + return one.test(t) && two.test(t); + } + + @Override + public String toString() { + return "(" + one + " AND " + two + ")"; + } + }); + } + } + return filter; + } + + @Override + protected CharSequence createSQLJoin(final Function func, final boolean update, final Map joinTabalis, final Set haset, final EntityInfo info) { + boolean morejoin = false; + if (this.joinEntity == null) { + if (this.joinClass != null) this.joinEntity = func.apply(this.joinClass); + if (this.nodes != null) { + for (FilterNode node : this.nodes) { + if (node instanceof FilterJoinNode) { + FilterJoinNode joinNode = ((FilterJoinNode) node); + if (joinNode.joinClass != null) { + joinNode.joinEntity = func.apply(joinNode.joinClass); + if (this.joinClass != null && this.joinClass != joinNode.joinClass) morejoin = true; + } + } + } + } + } + StringBuilder sb = new StringBuilder(); + if (this.joinClass != null) { + CharSequence cs = createElementSQLJoin(update, joinTabalis, haset, info, this); + if (cs != null) sb.append(cs); + } + if (morejoin) { + Set set = new HashSet<>(); + if (this.joinClass != null) set.add(this.joinClass); + for (FilterNode node : this.nodes) { + if (node instanceof FilterJoinNode) { + FilterJoinNode joinNode = ((FilterJoinNode) node); + if (!set.contains(joinNode.joinClass)) { + CharSequence cs = createElementSQLJoin(update, joinTabalis, haset, info, joinNode); + if (cs != null) { + sb.append(cs); + set.add(joinNode.joinClass); + } + } + } + } + } + return sb; + } + + private static CharSequence createElementSQLJoin(final boolean update, final Map joinTabalis, final Set haset, final EntityInfo info, final FilterJoinNode node) { + if (node.joinClass == null || (haset != null && haset.contains(joinTabalis.get(node.joinClass)))) return null; + StringBuilder sb = new StringBuilder(); + String[] joinColumns = node.joinColumns; + int pos = joinColumns[0].indexOf('='); + if (update) { + sb.append("[").append(node.joinEntity.getTable(node)).append(" ").append(joinTabalis.get(node.joinClass)).append(']'); + sb.append('{').append(info.getSQLColumn("a", pos > 0 ? joinColumns[0].substring(0, pos) : joinColumns[0])).append(" = ").append(node.joinEntity.getSQLColumn(joinTabalis.get(node.joinClass), pos > 0 ? joinColumns[0].substring(pos + 1) : joinColumns[0])); + for (int i = 1; i < joinColumns.length; i++) { + pos = joinColumns[i].indexOf('='); + sb.append(" AND ").append(info.getSQLColumn("a", pos > 0 ? joinColumns[i].substring(0, pos) : joinColumns[i])).append(" = ").append(node.joinEntity.getSQLColumn(joinTabalis.get(node.joinClass), pos > 0 ? joinColumns[i].substring(pos + 1) : joinColumns[i])); + } + sb.append('}'); + } else { + sb.append(" INNER JOIN ").append(node.joinEntity.getTable(node)).append(" ").append(joinTabalis.get(node.joinClass)) + .append(" ON ").append(info.getSQLColumn("a", pos > 0 ? joinColumns[0].substring(0, pos) : joinColumns[0])).append(" = ").append(node.joinEntity.getSQLColumn(joinTabalis.get(node.joinClass), pos > 0 ? joinColumns[0].substring(pos + 1) : joinColumns[0])); + for (int i = 1; i < joinColumns.length; i++) { + pos = joinColumns[i].indexOf('='); + sb.append(" AND ").append(info.getSQLColumn("a", pos > 0 ? joinColumns[i].substring(0, pos) : joinColumns[i])).append(" = ").append(node.joinEntity.getSQLColumn(joinTabalis.get(node.joinClass), pos > 0 ? joinColumns[i].substring(pos + 1) : joinColumns[i])); + } + } + if (haset != null) haset.add(joinTabalis.get(node.joinClass)); + return sb; + } + + @Override + protected boolean isCacheUseable(final Function entityApplyer) { + if (this.joinEntity == null) this.joinEntity = entityApplyer.apply(this.joinClass); + if (!this.joinEntity.isCacheFullLoaded()) return false; + if (this.nodes == null) return true; + for (FilterNode node : this.nodes) { + if (!node.isCacheUseable(entityApplyer)) return false; + } + return true; + } + + @Override + protected void putJoinTabalis(Map map) { + if (this.joinClass != null && !map.containsKey(this.joinClass)) map.put(joinClass, String.valueOf((char) ('b' + map.size()))); + if (this.nodes == null) return; + for (FilterNode node : this.nodes) { + node.putJoinTabalis(map); + } + } + + @Override + protected final boolean isjoin() { + return true; + } + + @Override + public String toString() { + return toString(joinClass == null ? null : joinClass.getSimpleName()).toString(); + } + + public Class getJoinClass() { + return joinClass; + } + + public void setJoinClass(Class joinClass) { + this.joinClass = joinClass; + } + + public String[] getJoinColumns() { + return joinColumns; + } + + public void setJoinColumns(String[] joinColumns) { + this.joinColumns = joinColumns; + } + +} diff --git a/src/main/java/org/redkale/source/FilterKey.java b/src/main/java/org/redkale/source/FilterKey.java index 20740a4f9..b0a1b52fb 100644 --- a/src/main/java/org/redkale/source/FilterKey.java +++ b/src/main/java/org/redkale/source/FilterKey.java @@ -1,39 +1,39 @@ -/* - * 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.source; - -import java.util.Objects; -import org.redkale.util.ConstructorParameters; - -/** - * FilterKey涓昏鐢ㄤ簬鑷韩瀛楁闂寸殑琛ㄨ揪寮, 濡傦細 a.recordid = a.parentid , a.parentid灏遍渶瑕丗ilterKey鏉ヨ〃绀 new FilterKey("parentid") - *
- * 娉ㄦ剰锛氳绫诲瀷涓嶆敮鎸佽〃杈惧紡锛欶V_XXX銆丅ETWEEN銆丯OTBETWEEN銆両N銆丯OTIN - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public class FilterKey implements java.io.Serializable { - - private final String column; - - @ConstructorParameters({"column"}) - public FilterKey(String column) { - this.column = Objects.requireNonNull(column); - } - - public String getColumn() { - return column; - } - - @Override - public String toString() { - return "a." + getColumn(); - } - -} +/* + * 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.source; + +import java.util.Objects; +import org.redkale.util.ConstructorParameters; + +/** + * FilterKey涓昏鐢ㄤ簬鑷韩瀛楁闂寸殑琛ㄨ揪寮, 濡傦細 a.recordid = a.parentid , a.parentid灏遍渶瑕丗ilterKey鏉ヨ〃绀 new FilterKey("parentid") + *
+ * 娉ㄦ剰锛氳绫诲瀷涓嶆敮鎸佽〃杈惧紡锛欶V_XXX銆丅ETWEEN銆丯OTBETWEEN銆両N銆丯OTIN + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public class FilterKey implements java.io.Serializable { + + private final String column; + + @ConstructorParameters({"column"}) + public FilterKey(String column) { + this.column = Objects.requireNonNull(column); + } + + public String getColumn() { + return column; + } + + @Override + public String toString() { + return "a." + getColumn(); + } + +} diff --git a/src/main/java/org/redkale/source/FilterNode.java b/src/main/java/org/redkale/source/FilterNode.java index 52b31cca1..ac7f52b37 100644 --- a/src/main/java/org/redkale/source/FilterNode.java +++ b/src/main/java/org/redkale/source/FilterNode.java @@ -1,2025 +1,2025 @@ -/* - * 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.source; - -import java.io.Serializable; -import java.lang.reflect.Array; -import java.util.*; -import java.util.function.*; -import static org.redkale.source.FilterExpress.*; -import org.redkale.util.*; - -/** - * 娉ㄦ剰锛
- * column鐨勫间互#寮澶寸殑瑙嗕负铏氭嫙瀛楁锛屼笉鍦ㄨ繃婊よ寖鍥村唴
- * 鍦ㄨ皟鐢 createSQLExpress 涔嬪墠蹇呴』鍏堣皟鐢 createSQLJoin
- * 鍦ㄨ皟鐢 createPredicate 涔嬪墠蹇呴』鍏堣皟鐢 isCacheUseable
- * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public class FilterNode { //FilterNode 涓嶈兘瀹炵幇Serializable鎺ュ彛锛 鍚﹀垯DataSource寰堝閲嶈浇鎺ュ彛浼氬嚭鐜板啿绐 - - protected boolean readOnly; - - protected String column; - - protected FilterExpress express; - - protected Serializable value; - - protected boolean itemand; - - //---------------------------------------------- - protected boolean or; - - protected FilterNode[] nodes; - - public FilterNode() { - } - - protected FilterNode(String col, FilterExpress exp, boolean itemand, Serializable val) { - Objects.requireNonNull(col); - if (exp == null) { - if (val instanceof Range) { - exp = FilterExpress.BETWEEN; - } else if (val instanceof Collection) { - if (!((Collection) val).isEmpty()) { - Object subval = null; - for (Object obj : (Collection) val) { //鍙栫涓涓 - subval = obj; - break; - } - if (subval instanceof Range) { - exp = FilterExpress.BETWEEN; -// } else if (subval instanceof Collection) { -// exp = FilterExpress.IN; -// } else if (subval != null && val.getClass().isArray()) { -// exp = FilterExpress.IN; - } else { - exp = FilterExpress.IN; - } - } else { //绌洪泦鍚 - exp = FilterExpress.IN; - } - } else if (val != null && val.getClass().isArray()) { - Class comp = val.getClass().getComponentType(); - if (Range.class.isAssignableFrom(comp)) { - exp = FilterExpress.BETWEEN; - } else { - exp = FilterExpress.IN; - } - } - } - this.column = col; - this.express = exp == null ? EQUAL : exp; - this.itemand = itemand; - this.value = val; - } - - public FilterNode copy() { - return copy(new FilterNode()); - } - - protected FilterNode copy(FilterNode node) { - node.readOnly = this.readOnly; - node.column = this.column; - node.express = this.express; - node.value = this.value; - node.itemand = this.itemand; - node.or = this.or; - if (this.nodes != null) { - node.nodes = new FilterNode[this.nodes.length]; - for (int i = 0; i < node.nodes.length; i++) { - node.nodes[i] = this.nodes[i] == null ? null : this.nodes[i].copy(); - } - } - return node; - } - - public FilterNode asReadOnly() { - this.readOnly = true; - return this; - } - - public FilterNode readOnly(boolean readOnly) { - this.readOnly = readOnly; - return this; - } - - public long findLongValue(final String col, long defValue) { - Serializable val = findValue(col); - return val == null ? defValue : ((Number) val).longValue(); - } - - public int findIntValue(final String col, int defValue) { - Serializable val = findValue(col); - return val == null ? defValue : ((Number) val).intValue(); - } - - public String findStringValue(final String col) { - return (String) findValue(col); - } - - public Serializable findValue(final String col) { - if (this.column != null && this.column.equals(col)) return this.value; - if (this.nodes == null) return null; - for (FilterNode n : this.nodes) { - if (n == null) continue; - Serializable val = n.findValue(col); - if (val != null) return val; - } - return null; - } - - public final FilterNode and(FilterNode node) { - return any(node, false); - } - - public final FilterNode and(String column, Serializable value) { - return and(column, null, value); - } - - public final FilterNode and(String column, FilterExpress express, Serializable value) { - return and(column, express, true, value); - } - - public final FilterNode and(String column, FilterExpress express, boolean itemand, Serializable value) { - return and(new FilterNode(column, express, itemand, value)); - } - - public final FilterNode or(FilterNode node) { - return any(node, true); - } - - public final FilterNode or(String column, Serializable value) { - return or(column, null, value); - } - - public final FilterNode or(String column, FilterExpress express, Serializable value) { - return or(column, express, true, value); - } - - public final FilterNode or(String column, FilterExpress express, boolean itemand, Serializable value) { - return or(new FilterNode(column, express, itemand, value)); - } - - protected FilterNode any(FilterNode node, boolean signor) { - if (this.readOnly) throw new RuntimeException("FilterNode(" + this + ") is ReadOnly"); - Objects.requireNonNull(node); - if (this.column == null) { - this.column = node.column; - this.express = node.express; - this.itemand = node.itemand; - this.value = node.value; - return this; - } - if (this.nodes == null) { - this.nodes = new FilterNode[]{node}; - this.or = signor; - return this; - } - if (or == signor) { - this.nodes = Utility.append(this.nodes, node); - return this; - } - FilterNode newnode = new FilterNode(this.column, this.express, this.itemand, this.value); - newnode.or = this.or; - newnode.nodes = this.nodes; - this.nodes = new FilterNode[]{newnode, node}; - this.column = null; - this.express = null; - this.itemand = true; - this.or = signor; - this.value = null; - return this; - } - - /** - * 璇ユ柟娉曢渶瑕侀噸杞 - * - * @param Entity绫荤殑娉涘瀷 - * @param func EntityInfo鐨勫姞杞藉櫒 - * @param update 鏄惁鐢ㄤ簬鏇存柊鐨凧OIN - * @param joinTabalis 鍏宠仈琛ㄩ泦鍚 - * @param haset 宸叉嫾鎺ヨ繃鐨勫瓧娈靛悕 - * @param info Entity绫荤殑EntityInfo - * - * @return SQL鐨刯oin璇彞 涓嶅瓨鍦ㄨ繑鍥瀗ull - */ - protected CharSequence createSQLJoin(final Function func, final boolean update, final Map joinTabalis, final Set haset, final EntityInfo info) { - if (joinTabalis == null || this.nodes == null) return null; - StringBuilder sb = null; - for (FilterNode node : this.nodes) { - CharSequence cs = node.createSQLJoin(func, update, joinTabalis, haset, info); - if (cs == null) continue; - if (sb == null) sb = new StringBuilder(); - sb.append(cs); - } - return sb; - } - - /** - * 璇ユ柟娉曢渶瑕侀噸杞 - * - * @return 鏄惁瀛樺湪鍏宠仈琛 - */ - protected boolean isjoin() { - if (this.nodes == null) return false; - for (FilterNode node : this.nodes) { - if (node.isjoin()) return true; - } - return false; - } - - protected final Map getJoinTabalis() { - if (!isjoin()) return null; - Map map = new HashMap<>(); - putJoinTabalis(map); - return map; - } - - protected void putJoinTabalis(Map map) { - if (this.nodes == null) return; - for (FilterNode node : this.nodes) { - node.putJoinTabalis(map); - } - } - - /** - * 璇ユ柟娉曢渶瑕侀噸杞 - * - * @param entityApplyer EntityInfo鐨勫姞杞藉櫒 - * - * @return 鏄惁鍙互浣跨敤缂撳瓨 - */ - protected boolean isCacheUseable(final Function entityApplyer) { - if (this.nodes == null) return true; - for (FilterNode node : this.nodes) { - if (!node.isCacheUseable(entityApplyer)) return false; - } - return true; - } - - /** - * 璇ユ柟娉曢渶瑕侀噸杞 - * - * @param source DataSqlSource - * @param Entity绫荤殑娉涘瀷 - * @param joinTabalis 鍏宠仈琛ㄧ殑闆嗗悎 - * @param info EntityInfo - * - * @return JOIN鐨凷QL璇彞 - */ - protected CharSequence createSQLExpress(DataSqlSource source, final EntityInfo info, final Map joinTabalis) { - CharSequence sb0 = this.column == null || this.column.isEmpty() || this.column.charAt(0) == '#' || info == null - ? null : createElementSQLExpress(source, info, joinTabalis == null ? null : joinTabalis.get(info.getType())); - if (this.nodes == null) return sb0; - final StringBuilder rs = new StringBuilder(); - rs.append('('); - boolean more = false; - if (sb0 != null && sb0.length() > 2) { - more = true; - rs.append(sb0); - } - for (FilterNode node : this.nodes) { - CharSequence f = node.createSQLExpress(source, info, joinTabalis); - if (f == null || f.length() < 3) continue; - if (more) rs.append(or ? " OR " : " AND "); - rs.append(f); - more = true; - } - rs.append(')'); - if (rs.length() < 5) return null; - return rs; - } - - public static FilterNode create(String column, Serializable value) { - return create(column, null, value); - } - - public static FilterNode create(String column, FilterExpress express, Serializable value) { - return create(column, express, true, value); - } - - public static FilterNode create(String column, FilterExpress express, boolean itemand, Serializable value) { - return new FilterNode(column, express, itemand, value); - } - - private boolean needSplit(final Object val0) { - return needSplit(express, val0); - } - - private static boolean needSplit(final FilterExpress express, final Object val0) { - if (val0 == null) return false; - boolean items = express != IN && express != NOTIN; //鏄惁鏁扮粍闆嗗悎鐨勮〃杈惧紡 - if (!items) { - if (val0.getClass().isArray()) { - Class comp = val0.getClass().getComponentType(); - if (comp == java.io.Serializable.class) comp = ((Object[]) val0)[0].getClass(); - if (!(comp.isPrimitive() || CharSequence.class.isAssignableFrom(comp) || Number.class.isAssignableFrom(comp))) { - items = true; - } - } else if (val0 instanceof Collection) { - for (Object fv : (Collection) val0) { - if (fv == null) continue; - Class comp = fv.getClass(); - if (!(comp.isPrimitive() || CharSequence.class.isAssignableFrom(comp) || Number.class.isAssignableFrom(comp))) { - items = true; - } - break; //鍙渶妫娴嬬涓涓 - } - } - } - return items; - } - - protected final CharSequence createElementSQLExpress(DataSqlSource source, final EntityInfo info, String talis) { - final Object val0 = getValue(); - if (needSplit(val0)) { - if (val0 instanceof Collection) { - StringBuilder sb = new StringBuilder(); - boolean more = ((Collection) val0).size() > 1; - if (more) sb.append('('); - for (Object fv : (Collection) val0) { - if (fv == null) continue; - CharSequence cs = createElementSQLExpress(source, info, talis, fv); - if (cs == null) continue; - if (sb.length() > 2) sb.append(itemand ? " AND " : " OR "); - sb.append(cs); - } - if (more) sb.append(')'); - return sb.length() > 3 ? sb : null; //鑻b鐨勫煎彧鏄()锛屽垯涓嶈繃婊 - } else if (val0.getClass().isArray()) { - StringBuilder sb = new StringBuilder(); - Object[] fvs = (Object[]) val0; - boolean more = fvs.length > 1; - if (more) sb.append('('); - for (Object fv : fvs) { - if (fv == null) continue; - CharSequence cs = createElementSQLExpress(source, info, talis, fv); - if (cs == null) continue; - if (sb.length() > 2) sb.append(itemand ? " AND " : " OR "); - sb.append(cs); - } - if (more) sb.append(')'); - return sb.length() > 3 ? sb : null; //鑻b鐨勫煎彧鏄()锛屽垯涓嶈繃婊 - } - } - return createElementSQLExpress(source, info, talis, val0); - - } - - private CharSequence createElementSQLExpress(DataSqlSource source, final EntityInfo info, String talis, Object val0) { - if (column == null || this.column.isEmpty() || this.column.charAt(0) == '#') return null; - if (talis == null) talis = "a"; - if (express == ISNULL || express == ISNOTNULL) { - return new StringBuilder().append(info.getSQLColumn(talis, column)).append(' ').append(express.value()); - } - if (express == ISEMPTY || express == ISNOTEMPTY) { - return new StringBuilder().append(info.getSQLColumn(talis, column)).append(' ').append(express.value()).append(" ''"); - } - if (val0 == null) return null; - if (express == FV_MOD || express == FV_DIV) { - FilterValue fv = (FilterValue) val0; - return new StringBuilder().append(info.getSQLColumn(talis, column)).append(' ').append(express.value()).append(' ').append(fv.getOptvalue()) - .append(' ').append(fv.getExpress().value()).append(' ').append(fv.getDestvalue()); - } - final boolean fk = (val0 instanceof FilterKey); - CharSequence val = fk ? info.getSQLColumn(talis, ((FilterKey) val0).getColumn()) : formatToString(express, info.getSQLValue(column, (Serializable) val0)); - if (val == null) return null; - StringBuilder sb = new StringBuilder(32); - if (express == CONTAIN) return source.containSQL.replace("${column}", info.getSQLColumn(talis, column)).replace("${keystr}", val); - if (express == IGNORECASECONTAIN) return source.containSQL.replace("${column}", "LOWER(" + info.getSQLColumn(talis, column) + ")").replace("${keystr}", val); - if (express == NOTCONTAIN) return source.notcontainSQL.replace("${column}", info.getSQLColumn(talis, column)).replace("${keystr}", val); - if (express == IGNORECASENOTCONTAIN) return source.notcontainSQL.replace("${column}", "LOWER(" + info.getSQLColumn(talis, column) + ")").replace("${keystr}", val); - - if (express == LENGTH_EQUAL || express == LENGTH_LESSTHAN || express == LENGTH_LESSTHANOREQUALTO - || express == LENGTH_GREATERTHAN || express == LENGTH_GREATERTHANOREQUALTO) { - sb.append("LENGTH(").append(info.getSQLColumn(talis, column)).append(')'); - } else if (express == IGNORECASEEQUAL || express == IGNORECASENOTEQUAL || express == IGNORECASELIKE || express == IGNORECASENOTLIKE) { - sb.append("LOWER(").append(info.getSQLColumn(talis, column)).append(')'); - if (fk) val = "LOWER(" + info.getSQLColumn(talis, ((FilterKey) val0).getColumn()) + ')'; - } else { - sb.append(info.getSQLColumn(talis, column)); - } - sb.append(' '); - switch (express) { - case OPAND: - case OPOR: - sb.append(express.value()).append(' ').append(val).append(" > 0"); - break; - case OPANDNO: - sb.append(express.value()).append(' ').append(val).append(" = 0"); - break; - default: - sb.append(express.value()).append(' ').append(val); - break; - } - return sb; - } - - protected Predicate createPredicate(final EntityCache cache) { - if (cache == null || (column == null && this.nodes == null)) return null; - Predicate filter = createElementPredicate(cache, false); - if (this.nodes == null) return filter; - for (FilterNode node : this.nodes) { - Predicate f = node.createPredicate(cache); - if (f == null) continue; - final Predicate one = filter; - final Predicate two = f; - filter = (filter == null) ? f : (or ? new Predicate() { - - @Override - public boolean test(T t) { - return one.test(t) || two.test(t); - } - - @Override - public String toString() { - return "(" + one + " OR " + two + ")"; - } - } : new Predicate() { - - @Override - public boolean test(T t) { - return one.test(t) && two.test(t); - } - - @Override - public String toString() { - return "(" + one + " AND " + two + ")"; - } - }); - } - return filter; - } - - protected final Predicate createElementPredicate(final EntityCache cache, final boolean join) { - if (this.column == null || this.column.isEmpty() || this.column.charAt(0) == '#') return null; - return createElementPredicate(cache, join, cache.getAttribute(column)); - } - - @SuppressWarnings("unchecked") - protected final Predicate createElementPredicate(final EntityCache cache, final boolean join, final Attribute attr) { - final Object val0 = getValue(); - if (needSplit(val0)) { - if (val0 instanceof Collection) { - Predicate filter = null; - for (Object fv : (Collection) val0) { - if (fv == null) continue; - Predicate f = createElementPredicate(cache, join, attr, fv); - if (f == null) continue; - final Predicate one = filter; - final Predicate two = f; - filter = (filter == null) ? f : (!itemand ? new Predicate() { - - @Override - public boolean test(T t) { - return one.test(t) || two.test(t); - } - - @Override - public String toString() { - return "(" + one + " OR " + two + ")"; - } - } : new Predicate() { - - @Override - public boolean test(T t) { - return one.test(t) && two.test(t); - } - - @Override - public String toString() { - return "(" + one + " AND " + two + ")"; - } - }); - } - return filter; - } else if (val0.getClass().isArray()) { - final Class primtype = val0.getClass(); - Object val2 = val0; - int ix = -1; - if (primtype == boolean[].class) { - boolean[] bs = (boolean[]) val0; - Boolean[] ns = new Boolean[bs.length]; - for (boolean v : bs) { - ns[++ix] = v; - } - val2 = ns; - } else if (primtype == byte[].class) { - byte[] bs = (byte[]) val0; - Byte[] ns = new Byte[bs.length]; - for (byte v : bs) { - ns[++ix] = v; - } - val2 = ns; - } else if (primtype == short[].class) { - short[] bs = (short[]) val0; - Short[] ns = new Short[bs.length]; - for (short v : bs) { - ns[++ix] = v; - } - val2 = ns; - } else if (primtype == char[].class) { - char[] bs = (char[]) val0; - Character[] ns = new Character[bs.length]; - for (char v : bs) { - ns[++ix] = v; - } - val2 = ns; - } else if (primtype == int[].class) { - int[] bs = (int[]) val0; - Integer[] ns = new Integer[bs.length]; - for (int v : bs) { - ns[++ix] = v; - } - val2 = ns; - } else if (primtype == float[].class) { - float[] bs = (float[]) val0; - Float[] ns = new Float[bs.length]; - for (float v : bs) { - ns[++ix] = v; - } - val2 = ns; - } else if (primtype == long[].class) { - long[] bs = (long[]) val0; - Long[] ns = new Long[bs.length]; - for (long v : bs) { - ns[++ix] = v; - } - val2 = ns; - } else if (primtype == double[].class) { - double[] bs = (double[]) val0; - Double[] ns = new Double[bs.length]; - for (double v : bs) { - ns[++ix] = v; - } - val2 = ns; - } - Predicate filter = null; - for (Object fv : (Object[]) val2) { - if (fv == null) continue; - Predicate f = createElementPredicate(cache, join, attr, fv); - if (f == null) continue; - final Predicate one = filter; - final Predicate two = f; - filter = (filter == null) ? f : (!itemand ? new Predicate() { - - @Override - public boolean test(T t) { - return one.test(t) || two.test(t); - } - - @Override - public String toString() { - return "(" + one + " OR " + two + ")"; - } - } : new Predicate() { - - @Override - public boolean test(T t) { - return one.test(t) && two.test(t); - } - - @Override - public String toString() { - return "(" + one + " AND " + two + ")"; - } - }); - } - return filter; - } - } - return createElementPredicate(cache, join, attr, val0); - } - - @SuppressWarnings("unchecked") - protected final Predicate createElementPredicate(final EntityCache cache, final boolean join, final Attribute attr, Object val0) { - if (attr == null) return null; - final String field = join ? (cache.getType().getSimpleName() + "." + attr.field()) : attr.field(); - if (express == ISNULL) return new Predicate() { - - @Override - public boolean test(T t) { - return attr.get(t) == null; - } - - @Override - public String toString() { - return field + " = null"; - } - }; - if (express == ISNOTNULL) return new Predicate() { - - @Override - public boolean test(T t) { - return attr.get(t) != null; - } - - @Override - public String toString() { - return field + " != null"; - } - }; - if (express == ISEMPTY) return new Predicate() { - - @Override - public boolean test(T t) { - Object v = attr.get(t); - return v == null || v.toString().isEmpty(); - } - - @Override - public String toString() { - return field + " = ''"; - } - }; - if (express == ISNOTEMPTY) return new Predicate() { - - @Override - public boolean test(T t) { - Object v = attr.get(t); - return v != null && !v.toString().isEmpty(); - } - - @Override - public String toString() { - return field + " != ''"; - } - }; - if (val0 == null) return null; - - final Class atype = attr.type(); - final Class valtype = val0.getClass(); - if (atype != valtype && val0 instanceof Number) { - if (atype == int.class || atype == Integer.class) { - val0 = ((Number) val0).intValue(); - } else if (atype == long.class || atype == Long.class) { - val0 = ((Number) val0).longValue(); - } else if (atype == short.class || atype == Short.class) { - val0 = ((Number) val0).shortValue(); - } else if (atype == float.class || atype == Float.class) { - val0 = ((Number) val0).floatValue(); - } else if (atype == byte.class || atype == Byte.class) { - val0 = ((Number) val0).byteValue(); - } else if (atype == double.class || atype == Double.class) { - val0 = ((Number) val0).doubleValue(); - } - } else if (valtype.isArray()) { - final int len = Array.getLength(val0); - if (len == 0 && express == NOTIN) return null; - final Class compType = valtype.getComponentType(); - if (atype != compType && len > 0) { - if (!compType.isPrimitive() && Number.class.isAssignableFrom(compType)) throw new RuntimeException("param(" + val0 + ") type not match " + atype + " for column " + column); - if (atype == int.class || atype == Integer.class) { - int[] vs = new int[len]; - for (int i = 0; i < len; i++) { - vs[i] = ((Number) Array.get(val0, i)).intValue(); - } - val0 = vs; - } else if (atype == long.class || atype == Long.class) { - long[] vs = new long[len]; - for (int i = 0; i < len; i++) { - vs[i] = ((Number) Array.get(val0, i)).longValue(); - } - val0 = vs; - } else if (atype == short.class || atype == Short.class) { - short[] vs = new short[len]; - for (int i = 0; i < len; i++) { - vs[i] = ((Number) Array.get(val0, i)).shortValue(); - } - val0 = vs; - } else if (atype == float.class || atype == Float.class) { - float[] vs = new float[len]; - for (int i = 0; i < len; i++) { - vs[i] = ((Number) Array.get(val0, i)).floatValue(); - } - val0 = vs; - } else if (atype == byte.class || atype == Byte.class) { - byte[] vs = new byte[len]; - for (int i = 0; i < len; i++) { - vs[i] = ((Number) Array.get(val0, i)).byteValue(); - } - val0 = vs; - } else if (atype == double.class || atype == Double.class) { - double[] vs = new double[len]; - for (int i = 0; i < len; i++) { - vs[i] = ((Number) Array.get(val0, i)).doubleValue(); - } - val0 = vs; - } - } - } else if (val0 instanceof Collection) { - final Collection collection = (Collection) val0; - if (collection.isEmpty() && express == NOTIN) return null; - if (!collection.isEmpty()) { - Iterator it = collection.iterator(); - it.hasNext(); - Class fs = it.next().getClass(); - Class pfs = fs; - if (fs == Integer.class) { - pfs = int.class; - } else if (fs == Long.class) { - pfs = long.class; - } else if (fs == Short.class) { - pfs = short.class; - } else if (fs == Float.class) { - pfs = float.class; - } else if (fs == Byte.class) { - pfs = byte.class; - } else if (fs == Double.class) { - pfs = double.class; - } - if (Number.class.isAssignableFrom(fs) && atype != fs && atype != pfs) { //闇瑕佽浆鎹 - ArrayList list = new ArrayList(collection.size()); - if (atype == int.class || atype == Integer.class) { - for (Number num : (Collection) collection) { - list.add(num.intValue()); - } - } else if (atype == long.class || atype == Long.class) { - for (Number num : (Collection) collection) { - list.add(num.longValue()); - } - } else if (atype == short.class || atype == Short.class) { - for (Number num : (Collection) collection) { - list.add(num.shortValue()); - } - } else if (atype == float.class || atype == Float.class) { - for (Number num : (Collection) collection) { - list.add(num.floatValue()); - } - } else if (atype == byte.class || atype == Byte.class) { - for (Number num : (Collection) collection) { - list.add(num.byteValue()); - } - } else if (atype == double.class || atype == Double.class) { - for (Number num : (Collection) collection) { - list.add(num.doubleValue()); - } - } - val0 = list; - } - } - } - final Serializable val = (Serializable) val0; - final boolean fk = (val instanceof FilterKey); - final Attribute fkattr = fk ? cache.getAttribute(((FilterKey) val).getColumn()) : null; - if (fk && fkattr == null) throw new RuntimeException(cache.getType() + " not found column(" + ((FilterKey) val).getColumn() + ")"); - switch (express) { - case EQUAL: - return fk ? new Predicate() { - - @Override - public boolean test(T t) { - return Objects.equals(fkattr.get(t), attr.get(t)); - } - - @Override - public String toString() { - return field + ' ' + express.value() + ' ' + fkattr.field(); - } - } : new Predicate() { - - @Override - public boolean test(T t) { - return val.equals(attr.get(t)); - } - - @Override - public String toString() { - return field + ' ' + express.value() + ' ' + formatToString(val); - } - }; - case IGNORECASEEQUAL: - return fk ? new Predicate() { - - @Override - public boolean test(T t) { - Object rs = attr.get(t); - Object rs2 = fkattr.get(t); - if (rs == null && rs2 == null) return true; - if (rs == null || rs2 == null) return false; - return Objects.equals(rs.toString().toLowerCase(), rs2.toString().toLowerCase()); - } - - @Override - public String toString() { - return "LOWER(" + field + ") " + express.value() + " LOWER(" + fkattr.field() + ')'; - } - } : new Predicate() { - - @Override - public boolean test(T t) { - Object rs = attr.get(t); - if (rs == null) return false; - return val.toString().equalsIgnoreCase(rs.toString()); - } - - @Override - public String toString() { - return "LOWER(" + field + ") " + express.value() + ' ' + formatToString(val); - } - }; - case NOTEQUAL: - return fk ? new Predicate() { - - @Override - public boolean test(T t) { - return !Objects.equals(fkattr.get(t), attr.get(t)); - } - - @Override - public String toString() { - return field + ' ' + express.value() + ' ' + fkattr.field(); - } - } : new Predicate() { - - @Override - public boolean test(T t) { - return !val.equals(attr.get(t)); - } - - @Override - public String toString() { - return field + ' ' + express.value() + ' ' + formatToString(val); - } - }; - case IGNORECASENOTEQUAL: - return fk ? new Predicate() { - - @Override - public boolean test(T t) { - Object rs = attr.get(t); - Object rs2 = fkattr.get(t); - if (rs == null && rs2 == null) return false; - if (rs == null || rs2 == null) return true; - return !Objects.equals(rs.toString().toLowerCase(), rs2.toString().toLowerCase()); - } - - @Override - public String toString() { - return "LOWER(" + field + ") " + express.value() + " LOWER(" + fkattr.field() + ')'; - } - } : new Predicate() { - - @Override - public boolean test(T t) { - Object rs = attr.get(t); - if (rs == null) return true; - return !val.toString().equalsIgnoreCase(rs.toString()); - } - - @Override - public String toString() { - return "LOWER(" + field + ") " + express.value() + ' ' + formatToString(val); - } - }; - case GREATERTHAN: - return fk ? new Predicate() { - - @Override - public boolean test(T t) { - return ((Comparable) attr.get(t)).compareTo((Comparable) fkattr.get(t)) > 0; - } - - @Override - public String toString() { - return field + ' ' + express.value() + ' ' + fkattr.field(); - } - } : new Predicate() { - - @Override - public boolean test(T t) { - return ((Comparable) attr.get(t)).compareTo(((Comparable) val)) > 0; - } - - @Override - public String toString() { - return field + ' ' + express.value() + ' ' + val; - } - }; - case LESSTHAN: - return fk ? new Predicate() { - - @Override - public boolean test(T t) { - return ((Comparable) attr.get(t)).compareTo((Comparable) fkattr.get(t)) < 0; - } - - @Override - public String toString() { - return field + ' ' + express.value() + ' ' + fkattr.field(); - } - } : new Predicate() { - - @Override - public boolean test(T t) { - return ((Comparable) attr.get(t)).compareTo(((Comparable) val)) < 0; - } - - @Override - public String toString() { - return field + ' ' + express.value() + ' ' + val; - } - }; - case GREATERTHANOREQUALTO: - return fk ? new Predicate() { - - @Override - public boolean test(T t) { - return ((Comparable) attr.get(t)).compareTo((Comparable) fkattr.get(t)) >= 0; - } - - @Override - public String toString() { - return field + ' ' + express.value() + ' ' + fkattr.field(); - } - } : new Predicate() { - - @Override - public boolean test(T t) { - return ((Comparable) attr.get(t)).compareTo(((Comparable) val)) >= 0; - } - - @Override - public String toString() { - return field + ' ' + express.value() + ' ' + val; - } - }; - case LESSTHANOREQUALTO: - return fk ? new Predicate() { - - @Override - public boolean test(T t) { - return ((Comparable) attr.get(t)).compareTo((Comparable) fkattr.get(t)) <= 0; - } - - @Override - public String toString() { - return field + ' ' + express.value() + ' ' + fkattr.field(); - } - } : new Predicate() { - - @Override - public boolean test(T t) { - return ((Comparable) attr.get(t)).compareTo(((Comparable) val)) <= 0; - } - - @Override - public String toString() { - return field + ' ' + express.value() + ' ' + val; - } - }; - - case FV_MOD: - FilterValue fv0 = (FilterValue) val; - switch (fv0.getExpress()) { - case EQUAL: - return new Predicate() { - - @Override - public boolean test(T t) { - return (((Number) attr.get(t)).longValue() % fv0.getOptvalue().longValue()) == fv0.getDestvalue().longValue(); - } - - @Override - public String toString() { - return field + " " + express.value() + " " + fv0.getOptvalue() + " " + fv0.getExpress().value() + " " + fv0.getDestvalue(); - } - }; - case NOTEQUAL: - return new Predicate() { - - @Override - public boolean test(T t) { - return (((Number) attr.get(t)).longValue() % fv0.getOptvalue().longValue()) != fv0.getDestvalue().longValue(); - } - - @Override - public String toString() { - return field + " " + express.value() + " " + fv0.getOptvalue() + " " + fv0.getExpress().value() + " " + fv0.getDestvalue(); - } - }; - case GREATERTHAN: - return new Predicate() { - - @Override - public boolean test(T t) { - return (((Number) attr.get(t)).longValue() % fv0.getOptvalue().longValue()) > fv0.getDestvalue().longValue(); - } - - @Override - public String toString() { - return field + " " + express.value() + " " + fv0.getOptvalue() + " " + fv0.getExpress().value() + " " + fv0.getDestvalue(); - } - }; - case LESSTHAN: - return new Predicate() { - - @Override - public boolean test(T t) { - return (((Number) attr.get(t)).longValue() % fv0.getOptvalue().longValue()) < fv0.getDestvalue().longValue(); - } - - @Override - public String toString() { - return field + " " + express.value() + " " + fv0.getOptvalue() + " " + fv0.getExpress().value() + " " + fv0.getDestvalue(); - } - }; - case GREATERTHANOREQUALTO: - return new Predicate() { - - @Override - public boolean test(T t) { - return (((Number) attr.get(t)).longValue() % fv0.getOptvalue().longValue()) >= fv0.getDestvalue().longValue(); - } - - @Override - public String toString() { - return field + " " + express.value() + " " + fv0.getOptvalue() + " " + fv0.getExpress().value() + " " + fv0.getDestvalue(); - } - }; - case LESSTHANOREQUALTO: - return new Predicate() { - - @Override - public boolean test(T t) { - return (((Number) attr.get(t)).longValue() % fv0.getOptvalue().longValue()) <= fv0.getDestvalue().longValue(); - } - - @Override - public String toString() { - return field + " " + express.value() + " " + fv0.getOptvalue() + " " + fv0.getExpress().value() + " " + fv0.getDestvalue(); - } - }; - default: - throw new RuntimeException("(" + fv0 + ")'s express illegal, must be =, !=, <, >, <=, >="); - } - case FV_DIV: - FilterValue fv1 = (FilterValue) val; - switch (fv1.getExpress()) { - case EQUAL: - return new Predicate() { - - @Override - public boolean test(T t) { - return (((Number) attr.get(t)).longValue() / fv1.getOptvalue().longValue()) == fv1.getDestvalue().longValue(); - } - - @Override - public String toString() { - return field + " " + express.value() + " " + fv1.getOptvalue() + " " + fv1.getExpress().value() + " " + fv1.getDestvalue(); - } - }; - case NOTEQUAL: - return new Predicate() { - - @Override - public boolean test(T t) { - return (((Number) attr.get(t)).longValue() / fv1.getOptvalue().longValue()) != fv1.getDestvalue().longValue(); - } - - @Override - public String toString() { - return field + " " + express.value() + " " + fv1.getOptvalue() + " " + fv1.getExpress().value() + " " + fv1.getDestvalue(); - } - }; - case GREATERTHAN: - return new Predicate() { - - @Override - public boolean test(T t) { - return (((Number) attr.get(t)).longValue() / fv1.getOptvalue().longValue()) > fv1.getDestvalue().longValue(); - } - - @Override - public String toString() { - return field + " " + express.value() + " " + fv1.getOptvalue() + " " + fv1.getExpress().value() + " " + fv1.getDestvalue(); - } - }; - case LESSTHAN: - return new Predicate() { - - @Override - public boolean test(T t) { - return (((Number) attr.get(t)).longValue() / fv1.getOptvalue().longValue()) < fv1.getDestvalue().longValue(); - } - - @Override - public String toString() { - return field + " " + express.value() + " " + fv1.getOptvalue() + " " + fv1.getExpress().value() + " " + fv1.getDestvalue(); - } - }; - case GREATERTHANOREQUALTO: - return new Predicate() { - - @Override - public boolean test(T t) { - return (((Number) attr.get(t)).longValue() / fv1.getOptvalue().longValue()) >= fv1.getDestvalue().longValue(); - } - - @Override - public String toString() { - return field + " " + express.value() + " " + fv1.getOptvalue() + " " + fv1.getExpress().value() + " " + fv1.getDestvalue(); - } - }; - case LESSTHANOREQUALTO: - return new Predicate() { - - @Override - public boolean test(T t) { - return (((Number) attr.get(t)).longValue() / fv1.getOptvalue().longValue()) <= fv1.getDestvalue().longValue(); - } - - @Override - public String toString() { - return field + " " + express.value() + " " + fv1.getOptvalue() + " " + fv1.getExpress().value() + " " + fv1.getDestvalue(); - } - }; - default: - throw new RuntimeException("(" + fv1 + ")'s express illegal, must be =, !=, <, >, <=, >="); - } - case OPAND: - return fk ? new Predicate() { - - @Override - public boolean test(T t) { - return (((Number) attr.get(t)).longValue() & ((Number) fkattr.get(t)).longValue()) > 0; - } - - @Override - public String toString() { - return field + " & " + fkattr.field() + " > 0"; - } - } : new Predicate() { - - @Override - public boolean test(T t) { - return (((Number) attr.get(t)).longValue() & ((Number) val).longValue()) > 0; - } - - @Override - public String toString() { - return field + " & " + val + " > 0"; - } - }; - case OPOR: - return fk ? new Predicate() { - - @Override - public boolean test(T t) { - return (((Number) attr.get(t)).longValue() | ((Number) fkattr.get(t)).longValue()) > 0; - } - - @Override - public String toString() { - return field + " | " + fkattr.field() + " > 0"; - } - } : new Predicate() { - - @Override - public boolean test(T t) { - return (((Number) attr.get(t)).longValue() | ((Number) val).longValue()) > 0; - } - - @Override - public String toString() { - return field + " | " + val + " > 0"; - } - }; - case OPANDNO: - return fk ? new Predicate() { - - @Override - public boolean test(T t) { - return (((Number) attr.get(t)).longValue() & ((Number) fkattr.get(t)).longValue()) == 0; - } - - @Override - public String toString() { - return field + " & " + fkattr.field() + " = 0"; - } - } : new Predicate() { - - @Override - public boolean test(T t) { - return (((Number) attr.get(t)).longValue() & ((Number) val).longValue()) == 0; - } - - @Override - public String toString() { - return field + " & " + val + " = 0"; - } - }; - case LIKE: - return fk ? new Predicate() { - - @Override - public boolean test(T t) { - Object rs = attr.get(t); - Object rs2 = fkattr.get(t); - return rs != null && rs2 != null && rs.toString().contains(rs2.toString()); - } - - @Override - public String toString() { - return field + ' ' + express.value() + ' ' + fkattr.field(); - } - } : new Predicate() { - - @Override - public boolean test(T t) { - Object rs = attr.get(t); - return rs != null && rs.toString().contains(val.toString()); - } - - @Override - public String toString() { - return field + ' ' + express.value() + ' ' + formatToString(val); - } - }; - case STARTSWITH: - return fk ? new Predicate() { - - @Override - public boolean test(T t) { - Object rs = attr.get(t); - Object rs2 = fkattr.get(t); - return rs != null && rs2 != null && rs.toString().startsWith(rs2.toString()); - } - - @Override - public String toString() { - return field + " STARTSWITH " + fkattr.field(); - } - } : new Predicate() { - - @Override - public boolean test(T t) { - Object rs = attr.get(t); - return rs != null && rs.toString().startsWith(val.toString()); - } - - @Override - public String toString() { - return field + " STARTSWITH " + formatToString(val); - } - }; - case ENDSWITH: - return fk ? new Predicate() { - - @Override - public boolean test(T t) { - Object rs = attr.get(t); - Object rs2 = fkattr.get(t); - return rs != null && rs2 != null && rs.toString().endsWith(rs2.toString()); - } - - @Override - public String toString() { - return field + " ENDSWITH " + fkattr.field(); - } - } : new Predicate() { - - @Override - public boolean test(T t) { - Object rs = attr.get(t); - return rs != null && rs.toString().endsWith(val.toString()); - } - - @Override - public String toString() { - return field + " ENDSWITH " + formatToString(val); - } - }; - case IGNORECASELIKE: - if (fk) return new Predicate() { - - @Override - public boolean test(T t) { - Object rs = attr.get(t); - Object rs2 = fkattr.get(t); - return rs != null && rs2 != null && rs.toString().toLowerCase().contains(rs2.toString().toLowerCase()); - } - - @Override - public String toString() { - return "LOWER(" + field + ") " + express.value() + " LOWER(" + fkattr.field() + ')'; - } - }; - final String valstr = val.toString().toLowerCase(); - return new Predicate() { - - @Override - public boolean test(T t) { - Object rs = attr.get(t); - return rs != null && rs.toString().toLowerCase().contains(valstr); - } - - @Override - public String toString() { - return "LOWER(" + field + ") " + express.value() + ' ' + formatToString(valstr); - } - }; - case NOTSTARTSWITH: - return fk ? new Predicate() { - - @Override - public boolean test(T t) { - Object rs = attr.get(t); - Object rs2 = fkattr.get(t); - return rs == null || rs2 == null || !rs.toString().startsWith(rs2.toString()); - } - - @Override - public String toString() { - return field + " NOT STARTSWITH " + fkattr.field(); - } - } : new Predicate() { - - @Override - public boolean test(T t) { - Object rs = attr.get(t); - return rs == null || !rs.toString().startsWith(val.toString()); - } - - @Override - public String toString() { - return field + " NOT STARTSWITH " + formatToString(val); - } - }; - case NOTENDSWITH: - return fk ? new Predicate() { - - @Override - public boolean test(T t) { - Object rs = attr.get(t); - Object rs2 = fkattr.get(t); - return rs == null || rs2 == null || !rs.toString().endsWith(rs2.toString()); - } - - @Override - public String toString() { - return field + " NOT ENDSWITH " + fkattr.field(); - } - } : new Predicate() { - - @Override - public boolean test(T t) { - Object rs = attr.get(t); - return rs == null || !rs.toString().endsWith(val.toString()); - } - - @Override - public String toString() { - return field + " NOT ENDSWITH " + formatToString(val); - } - }; - case IGNORECASENOTLIKE: - if (fk) return new Predicate() { - - @Override - public boolean test(T t) { - Object rs = attr.get(t); - Object rs2 = fkattr.get(t); - return rs == null || rs2 == null || !rs.toString().toLowerCase().contains(rs2.toString().toLowerCase()); - } - - @Override - public String toString() { - return "LOWER(" + field + ") " + express.value() + " LOWER(" + fkattr.field() + ')'; - } - }; - final String valstr2 = val.toString().toLowerCase(); - return new Predicate() { - - @Override - public boolean test(T t) { - Object rs = attr.get(t); - return rs == null || !rs.toString().toLowerCase().contains(valstr2); - } - - @Override - public String toString() { - return "LOWER(" + field + ") " + express.value() + ' ' + formatToString(valstr2); - } - }; - case LENGTH_EQUAL: - final int intval = ((Number) val).intValue(); - return new Predicate() { - - @Override - public boolean test(T t) { - Object rs = attr.get(t); - return (rs == null && 0 == intval) || (rs != null && rs.toString().length() == intval); - } - - @Override - public String toString() { - return "LENGTH(" + field + ") " + express.value() + ' ' + intval; - } - }; - case LENGTH_LESSTHAN: - final int intval2 = ((Number) val).intValue(); - return new Predicate() { - - @Override - public boolean test(T t) { - Object rs = attr.get(t); - return (rs == null && 0 < intval2) || (rs != null && rs.toString().length() < intval2); - } - - @Override - public String toString() { - return "LENGTH(" + field + ") " + express.value() + ' ' + intval2; - } - }; - case LENGTH_LESSTHANOREQUALTO: - final int intval3 = ((Number) val).intValue(); - return new Predicate() { - - @Override - public boolean test(T t) { - Object rs = attr.get(t); - return (rs == null && 0 <= intval3) || (rs != null && rs.toString().length() <= intval3); - } - - @Override - public String toString() { - return "LENGTH(" + field + ") " + express.value() + ' ' + intval3; - } - }; - case LENGTH_GREATERTHAN: - final int intval4 = ((Number) val).intValue(); - return new Predicate() { - - @Override - public boolean test(T t) { - Object rs = attr.get(t); - return (rs == null && 0 > intval4) || (rs != null && rs.toString().length() > intval4); - } - - @Override - public String toString() { - return "LENGTH(" + field + ") " + express.value() + ' ' + intval4; - } - }; - case LENGTH_GREATERTHANOREQUALTO: - final int intval5 = ((Number) val).intValue(); - return new Predicate() { - - @Override - public boolean test(T t) { - Object rs = attr.get(t); - return (rs == null && 0 >= intval5) || (rs != null && rs.toString().length() >= intval5); - } - - @Override - public String toString() { - return "LENGTH(" + field + ") " + express.value() + ' ' + intval5; - } - }; - case CONTAIN: - return fk ? new Predicate() { - - @Override - public boolean test(T t) { - Object rs = attr.get(t); - Object rs2 = fkattr.get(t); - return rs != null && rs2 != null && rs2.toString().contains(rs.toString()); - } - - @Override - public String toString() { - return fkattr.field() + ' ' + express.value() + ' ' + field; - } - } : new Predicate() { - - @Override - public boolean test(T t) { - Object rs = attr.get(t); - return rs != null && val.toString().contains(rs.toString()); - } - - @Override - public String toString() { - return "" + formatToString(val) + ' ' + express.value() + ' ' + field; - } - }; - case IGNORECASECONTAIN: - if (fk) return new Predicate() { - - @Override - public boolean test(T t) { - Object rs = attr.get(t); - Object rs2 = fkattr.get(t); - return rs != null && rs2 != null && rs2.toString().toLowerCase().contains(rs.toString().toLowerCase()); - } - - @Override - public String toString() { - return " LOWER(" + fkattr.field() + ") " + express.value() + ' ' + "LOWER(" + field + ") "; - } - }; - final String valstr3 = val.toString().toLowerCase(); - return new Predicate() { - - @Override - public boolean test(T t) { - Object rs = attr.get(t); - return rs != null && valstr3.contains(rs.toString().toLowerCase()); - } - - @Override - public String toString() { - return "" + formatToString(valstr3) + express.value() + ' ' + "LOWER(" + field + ") "; - } - }; - case NOTCONTAIN: - return fk ? new Predicate() { - - @Override - public boolean test(T t) { - Object rs = attr.get(t); - Object rs2 = fkattr.get(t); - return rs == null || rs2 == null || !rs2.toString().contains(rs.toString()); - } - - @Override - public String toString() { - return fkattr.field() + ' ' + express.value() + ' ' + field; - } - } : new Predicate() { - - @Override - public boolean test(T t) { - Object rs = attr.get(t); - return rs == null || !val.toString().contains(rs.toString()); - } - - @Override - public String toString() { - return "" + formatToString(val) + ' ' + express.value() + ' ' + field; - } - }; - case IGNORECASENOTCONTAIN: - if (fk) return new Predicate() { - - @Override - public boolean test(T t) { - Object rs = attr.get(t); - Object rs2 = fkattr.get(t); - return rs == null || rs2 == null || !rs2.toString().toLowerCase().contains(rs.toString().toLowerCase()); - } - - @Override - public String toString() { - return " LOWER(" + fkattr.field() + ") " + express.value() + ' ' + "LOWER(" + field + ") "; - } - }; - final String valstr4 = val.toString().toLowerCase(); - return new Predicate() { - - @Override - public boolean test(T t) { - Object rs = attr.get(t); - return rs == null || !valstr4.contains(rs.toString().toLowerCase()); - } - - @Override - public String toString() { - return "" + formatToString(valstr4) + express.value() + ' ' + "LOWER(" + field + ") "; - } - }; - case BETWEEN: - case NOTBETWEEN: - Range range = (Range) val; - final Comparable min = range.getMin(); - final Comparable max = range.getMax(); - if (express == BETWEEN) return new Predicate() { - - @Override - public boolean test(T t) { - Comparable rs = (Comparable) attr.get(t); - if (rs == null) return false; - if (min != null && min.compareTo(rs) >= 0) return false; - return !(max != null && max.compareTo(rs) <= 0); - } - - @Override - public String toString() { - return field + " BETWEEN " + min + " AND " + max; - } - }; - if (express == NOTBETWEEN) return new Predicate() { - - @Override - public boolean test(T t) { - Comparable rs = (Comparable) attr.get(t); - if (rs == null) return true; - if (min != null && min.compareTo(rs) >= 0) return true; - return (max != null && max.compareTo(rs) <= 0); - } - - @Override - public String toString() { - return field + " NOT BETWEEN " + min + " AND " + max; - } - }; - return null; - case IN: - case NOTIN: - Predicate filter; - if (val instanceof Collection) { - Collection array = (Collection) val; - if (array.isEmpty()) { //express 鍙細鏄 IN - filter = new Predicate() { - - @Override - public boolean test(T t) { - return false; - } - - @Override - public String toString() { - return field + ' ' + express.value() + " []"; - } - }; - } else { - filter = new Predicate() { - - @Override - public boolean test(T t) { - Object rs = attr.get(t); - return rs != null && array.contains(rs); - } - - @Override - public String toString() { - return field + ' ' + express.value() + ' ' + val; - } - }; - } - } else { - Class type = val.getClass(); - if (Array.getLength(val) == 0) {//express 鍙細鏄 IN - filter = new Predicate() { - - @Override - public boolean test(T t) { - return false; - } - - @Override - public String toString() { - return field + ' ' + express.value() + " []"; - } - }; - } else if (type == int[].class) { - filter = new Predicate() { - - @Override - public boolean test(T t) { - Object rs = attr.get(t); - if (rs == null) return false; - int k = (int) rs; - for (int v : (int[]) val) { - if (v == k) return true; - } - return false; - } - - @Override - public String toString() { - return field + ' ' + express.value() + ' ' + Arrays.toString((int[]) val); - } - }; - } else if (type == short[].class) { - filter = new Predicate() { - - @Override - public boolean test(T t) { - Object rs = attr.get(t); - if (rs == null) return false; - short k = (short) rs; - for (short v : (short[]) val) { - if (v == k) return true; - } - return false; - } - - @Override - public String toString() { - return field + ' ' + express.value() + ' ' + Arrays.toString((short[]) val); - } - }; - } else if (type == long[].class) { - filter = new Predicate() { - - @Override - public boolean test(T t) { - Object rs = attr.get(t); - if (rs == null) return false; - long k = (long) rs; - for (long v : (long[]) val) { - if (v == k) return true; - } - return false; - } - - @Override - public String toString() { - return field + ' ' + express.value() + ' ' + Arrays.toString((long[]) val); - } - }; - } else if (type == float[].class) { - filter = new Predicate() { - - @Override - public boolean test(T t) { - Object rs = attr.get(t); - if (rs == null) return false; - float k = (float) rs; - for (float v : (float[]) val) { - if (v == k) return true; - } - return false; - } - - @Override - public String toString() { - return field + ' ' + express.value() + ' ' + Arrays.toString((float[]) val); - } - }; - } else if (type == double[].class) { - filter = new Predicate() { - - @Override - public boolean test(T t) { - Object rs = attr.get(t); - if (rs == null) return false; - double k = (double) rs; - for (double v : (double[]) val) { - if (v == k) return true; - } - return false; - } - - @Override - public String toString() { - return field + ' ' + express.value() + ' ' + Arrays.toString((double[]) val); - } - }; - } else { - filter = new Predicate() { - - @Override - public boolean test(T t) { - Object rs = attr.get(t); - if (rs == null) return false; - for (Object v : (Object[]) val) { - if (rs.equals(v)) return true; - } - return false; - } - - @Override - public String toString() { - return field + ' ' + express.value() + ' ' + Arrays.toString((Object[]) val); - } - }; - } - } - if (express == NOTIN) { - final Predicate filter2 = filter; - filter = new Predicate() { - - @Override - public boolean test(T t) { - return !filter2.test(t); - } - - @Override - public String toString() { - return filter2.toString(); - } - }; - } - return filter; - } - return null; - } - - @Override - public String toString() { - return toString(null).toString(); - } - - protected StringBuilder toString(final String prefix) { - StringBuilder sb = new StringBuilder(); - StringBuilder element = toElementString(prefix); - boolean more = element != null && element.length() > 0 && this.nodes != null; - if (more) sb.append('('); - sb.append(element); - if (this.nodes != null) { - for (FilterNode node : this.nodes) { - String s = node.toString(); - if (s.length() < 1) continue; - if (sb.length() > 1) sb.append(or ? " OR " : " AND "); - sb.append(s); - } - } - if (more) sb.append(')'); - return sb; - } - - protected final StringBuilder toElementString(final String prefix) { - Serializable val0 = getValue(); - if (needSplit(val0)) { - if (val0 instanceof Collection) { - StringBuilder sb = new StringBuilder(); - boolean more = ((Collection) val0).size() > 1; - if (more) sb.append('('); - for (Object fv : (Collection) val0) { - if (fv == null) continue; - CharSequence cs = toElementString(prefix, fv); - if (cs == null) continue; - if (sb.length() > 2) sb.append(itemand ? " AND " : " OR "); - sb.append(cs); - } - if (more) sb.append(')'); - return sb.length() > 3 ? sb : null; //鑻b鐨勫煎彧鏄()锛屽垯涓嶈繃婊 - } else if (val0.getClass().isArray()) { - StringBuilder sb = new StringBuilder(); - Object[] fvs = (Object[]) val0; - boolean more = fvs.length > 1; - if (more) sb.append('('); - for (Object fv : fvs) { - if (fv == null) continue; - CharSequence cs = toElementString(prefix, fv); - if (cs == null) continue; - if (sb.length() > 2) sb.append(itemand ? " AND " : " OR "); - sb.append(cs); - } - if (more) sb.append(')'); - return sb.length() > 3 ? sb : null; //鑻b鐨勫煎彧鏄()锛屽垯涓嶈繃婊 - } - } - return toElementString(prefix, val0); - } - - protected final StringBuilder toElementString(final String prefix, Object ev) { - StringBuilder sb = new StringBuilder(); - if (column != null) { - String col = prefix == null ? column : (prefix + "." + column); - if (express == ISNULL || express == ISNOTNULL) { - sb.append(col).append(' ').append(express.value()); - } else if (express == ISEMPTY || express == ISNOTEMPTY) { - sb.append(col).append(' ').append(express.value()).append(" ''"); - } else if (ev != null) { - boolean lower = (express == IGNORECASELIKE || express == IGNORECASENOTLIKE || express == IGNORECASECONTAIN || express == IGNORECASENOTCONTAIN); - sb.append(lower ? ("LOWER(" + col + ')') : col).append(' ').append(express.value()).append(' ').append(formatToString(express, ev)); - } - } - return sb; - } - - private static CharSequence formatToString(Object value) { - CharSequence sb = formatToString(null, value); - return sb == null ? null : sb.toString(); - } - - private static CharSequence formatToString(FilterExpress express, Object value) { - if (value == null) return null; - if (value instanceof Number) return String.valueOf(value); - if (value instanceof CharSequence) { - if (express == LIKE || express == NOTLIKE) { - value = "%" + value + '%'; - } else if (express == STARTSWITH || express == NOTSTARTSWITH) { - value = value + "%"; - } else if (express == ENDSWITH || express == NOTENDSWITH) { - value = "%" + value; - } else if (express == IGNORECASELIKE || express == IGNORECASENOTLIKE) { - value = "%" + value.toString().toLowerCase() + '%'; - } else if (express == IGNORECASECONTAIN || express == IGNORECASENOTCONTAIN - || express == IGNORECASEEQUAL || express == IGNORECASENOTEQUAL) { - value = value.toString().toLowerCase(); - } - return new StringBuilder().append('\'').append(value.toString().replace("'", "\\'")).append('\''); - } else if (value instanceof Range) { - Range range = (Range) value; - boolean rangestring = range.getClass() == Range.StringRange.class; - StringBuilder sb = new StringBuilder(); - if (rangestring) { - sb.append('\'').append(range.getMin().toString().replace("'", "\\'")).append('\''); - } else { - sb.append(range.getMin()); - } - sb.append(" AND "); - if (rangestring) { - sb.append('\'').append(range.getMax().toString().replace("'", "\\'")).append('\''); - } else { - sb.append(range.getMax()); - } - return sb; - } else if (value.getClass().isArray()) { - int len = Array.getLength(value); - if (len == 0) return express == NOTIN ? null : new StringBuilder("(NULL)"); - if (len == 1) { - Object firstval = Array.get(value, 0); - if (firstval != null && firstval.getClass().isArray()) return formatToString(express, firstval); - } - StringBuilder sb = new StringBuilder(); - sb.append('('); - for (int i = 0; i < len; i++) { - Object o = Array.get(value, i); - if (sb.length() > 1) sb.append(','); - if (o instanceof CharSequence) { - sb.append('\'').append(o.toString().replace("'", "\\'")).append('\''); - } else { - sb.append(o); - } - } - return sb.append(')'); - } else if (value instanceof Collection) { - Collection c = (Collection) value; - if (c.isEmpty()) return express == NOTIN ? null : new StringBuilder("(NULL)"); - StringBuilder sb = new StringBuilder(); - sb.append('('); - for (Object o : c) { - if (sb.length() > 1) sb.append(','); - if (o instanceof CharSequence) { - sb.append('\'').append(o.toString().replace("'", "\\'")).append('\''); - } else { - sb.append(o); - } - } - return sb.append(')'); - } - return String.valueOf(value); - } - - public final Serializable getValue() { - return value; - } - - public final void setValue(Serializable value) { - this.value = value; - } - - public boolean isReadOnly() { - return readOnly; - } - - public void setReadOnly(boolean readOnly) { - this.readOnly = readOnly; - } - - public final boolean isOr() { - return or; - } - - public final void setOr(boolean or) { - this.or = or; - } - - public final String getColumn() { - return column; - } - - public final void setColumn(String column) { - this.column = column; - } - - public final FilterExpress getExpress() { - return express; - } - - public final void setExpress(FilterExpress express) { - this.express = express; - } - - public final boolean isItemand() { - return itemand; - } - - public final void setItemand(boolean itemand) { - this.itemand = itemand; - } - - public final FilterNode[] getNodes() { - return nodes; - } - - public final void setNodes(FilterNode[] nodes) { - this.nodes = nodes; - } - -} +/* + * 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.source; + +import java.io.Serializable; +import java.lang.reflect.Array; +import java.util.*; +import java.util.function.*; +import static org.redkale.source.FilterExpress.*; +import org.redkale.util.*; + +/** + * 娉ㄦ剰锛
+ * column鐨勫间互#寮澶寸殑瑙嗕负铏氭嫙瀛楁锛屼笉鍦ㄨ繃婊よ寖鍥村唴
+ * 鍦ㄨ皟鐢 createSQLExpress 涔嬪墠蹇呴』鍏堣皟鐢 createSQLJoin
+ * 鍦ㄨ皟鐢 createPredicate 涔嬪墠蹇呴』鍏堣皟鐢 isCacheUseable
+ * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public class FilterNode { //FilterNode 涓嶈兘瀹炵幇Serializable鎺ュ彛锛 鍚﹀垯DataSource寰堝閲嶈浇鎺ュ彛浼氬嚭鐜板啿绐 + + protected boolean readOnly; + + protected String column; + + protected FilterExpress express; + + protected Serializable value; + + protected boolean itemand; + + //---------------------------------------------- + protected boolean or; + + protected FilterNode[] nodes; + + public FilterNode() { + } + + protected FilterNode(String col, FilterExpress exp, boolean itemand, Serializable val) { + Objects.requireNonNull(col); + if (exp == null) { + if (val instanceof Range) { + exp = FilterExpress.BETWEEN; + } else if (val instanceof Collection) { + if (!((Collection) val).isEmpty()) { + Object subval = null; + for (Object obj : (Collection) val) { //鍙栫涓涓 + subval = obj; + break; + } + if (subval instanceof Range) { + exp = FilterExpress.BETWEEN; +// } else if (subval instanceof Collection) { +// exp = FilterExpress.IN; +// } else if (subval != null && val.getClass().isArray()) { +// exp = FilterExpress.IN; + } else { + exp = FilterExpress.IN; + } + } else { //绌洪泦鍚 + exp = FilterExpress.IN; + } + } else if (val != null && val.getClass().isArray()) { + Class comp = val.getClass().getComponentType(); + if (Range.class.isAssignableFrom(comp)) { + exp = FilterExpress.BETWEEN; + } else { + exp = FilterExpress.IN; + } + } + } + this.column = col; + this.express = exp == null ? EQUAL : exp; + this.itemand = itemand; + this.value = val; + } + + public FilterNode copy() { + return copy(new FilterNode()); + } + + protected FilterNode copy(FilterNode node) { + node.readOnly = this.readOnly; + node.column = this.column; + node.express = this.express; + node.value = this.value; + node.itemand = this.itemand; + node.or = this.or; + if (this.nodes != null) { + node.nodes = new FilterNode[this.nodes.length]; + for (int i = 0; i < node.nodes.length; i++) { + node.nodes[i] = this.nodes[i] == null ? null : this.nodes[i].copy(); + } + } + return node; + } + + public FilterNode asReadOnly() { + this.readOnly = true; + return this; + } + + public FilterNode readOnly(boolean readOnly) { + this.readOnly = readOnly; + return this; + } + + public long findLongValue(final String col, long defValue) { + Serializable val = findValue(col); + return val == null ? defValue : ((Number) val).longValue(); + } + + public int findIntValue(final String col, int defValue) { + Serializable val = findValue(col); + return val == null ? defValue : ((Number) val).intValue(); + } + + public String findStringValue(final String col) { + return (String) findValue(col); + } + + public Serializable findValue(final String col) { + if (this.column != null && this.column.equals(col)) return this.value; + if (this.nodes == null) return null; + for (FilterNode n : this.nodes) { + if (n == null) continue; + Serializable val = n.findValue(col); + if (val != null) return val; + } + return null; + } + + public final FilterNode and(FilterNode node) { + return any(node, false); + } + + public final FilterNode and(String column, Serializable value) { + return and(column, null, value); + } + + public final FilterNode and(String column, FilterExpress express, Serializable value) { + return and(column, express, true, value); + } + + public final FilterNode and(String column, FilterExpress express, boolean itemand, Serializable value) { + return and(new FilterNode(column, express, itemand, value)); + } + + public final FilterNode or(FilterNode node) { + return any(node, true); + } + + public final FilterNode or(String column, Serializable value) { + return or(column, null, value); + } + + public final FilterNode or(String column, FilterExpress express, Serializable value) { + return or(column, express, true, value); + } + + public final FilterNode or(String column, FilterExpress express, boolean itemand, Serializable value) { + return or(new FilterNode(column, express, itemand, value)); + } + + protected FilterNode any(FilterNode node, boolean signor) { + if (this.readOnly) throw new RuntimeException("FilterNode(" + this + ") is ReadOnly"); + Objects.requireNonNull(node); + if (this.column == null) { + this.column = node.column; + this.express = node.express; + this.itemand = node.itemand; + this.value = node.value; + return this; + } + if (this.nodes == null) { + this.nodes = new FilterNode[]{node}; + this.or = signor; + return this; + } + if (or == signor) { + this.nodes = Utility.append(this.nodes, node); + return this; + } + FilterNode newnode = new FilterNode(this.column, this.express, this.itemand, this.value); + newnode.or = this.or; + newnode.nodes = this.nodes; + this.nodes = new FilterNode[]{newnode, node}; + this.column = null; + this.express = null; + this.itemand = true; + this.or = signor; + this.value = null; + return this; + } + + /** + * 璇ユ柟娉曢渶瑕侀噸杞 + * + * @param Entity绫荤殑娉涘瀷 + * @param func EntityInfo鐨勫姞杞藉櫒 + * @param update 鏄惁鐢ㄤ簬鏇存柊鐨凧OIN + * @param joinTabalis 鍏宠仈琛ㄩ泦鍚 + * @param haset 宸叉嫾鎺ヨ繃鐨勫瓧娈靛悕 + * @param info Entity绫荤殑EntityInfo + * + * @return SQL鐨刯oin璇彞 涓嶅瓨鍦ㄨ繑鍥瀗ull + */ + protected CharSequence createSQLJoin(final Function func, final boolean update, final Map joinTabalis, final Set haset, final EntityInfo info) { + if (joinTabalis == null || this.nodes == null) return null; + StringBuilder sb = null; + for (FilterNode node : this.nodes) { + CharSequence cs = node.createSQLJoin(func, update, joinTabalis, haset, info); + if (cs == null) continue; + if (sb == null) sb = new StringBuilder(); + sb.append(cs); + } + return sb; + } + + /** + * 璇ユ柟娉曢渶瑕侀噸杞 + * + * @return 鏄惁瀛樺湪鍏宠仈琛 + */ + protected boolean isjoin() { + if (this.nodes == null) return false; + for (FilterNode node : this.nodes) { + if (node.isjoin()) return true; + } + return false; + } + + protected final Map getJoinTabalis() { + if (!isjoin()) return null; + Map map = new HashMap<>(); + putJoinTabalis(map); + return map; + } + + protected void putJoinTabalis(Map map) { + if (this.nodes == null) return; + for (FilterNode node : this.nodes) { + node.putJoinTabalis(map); + } + } + + /** + * 璇ユ柟娉曢渶瑕侀噸杞 + * + * @param entityApplyer EntityInfo鐨勫姞杞藉櫒 + * + * @return 鏄惁鍙互浣跨敤缂撳瓨 + */ + protected boolean isCacheUseable(final Function entityApplyer) { + if (this.nodes == null) return true; + for (FilterNode node : this.nodes) { + if (!node.isCacheUseable(entityApplyer)) return false; + } + return true; + } + + /** + * 璇ユ柟娉曢渶瑕侀噸杞 + * + * @param source DataSqlSource + * @param Entity绫荤殑娉涘瀷 + * @param joinTabalis 鍏宠仈琛ㄧ殑闆嗗悎 + * @param info EntityInfo + * + * @return JOIN鐨凷QL璇彞 + */ + protected CharSequence createSQLExpress(DataSqlSource source, final EntityInfo info, final Map joinTabalis) { + CharSequence sb0 = this.column == null || this.column.isEmpty() || this.column.charAt(0) == '#' || info == null + ? null : createElementSQLExpress(source, info, joinTabalis == null ? null : joinTabalis.get(info.getType())); + if (this.nodes == null) return sb0; + final StringBuilder rs = new StringBuilder(); + rs.append('('); + boolean more = false; + if (sb0 != null && sb0.length() > 2) { + more = true; + rs.append(sb0); + } + for (FilterNode node : this.nodes) { + CharSequence f = node.createSQLExpress(source, info, joinTabalis); + if (f == null || f.length() < 3) continue; + if (more) rs.append(or ? " OR " : " AND "); + rs.append(f); + more = true; + } + rs.append(')'); + if (rs.length() < 5) return null; + return rs; + } + + public static FilterNode create(String column, Serializable value) { + return create(column, null, value); + } + + public static FilterNode create(String column, FilterExpress express, Serializable value) { + return create(column, express, true, value); + } + + public static FilterNode create(String column, FilterExpress express, boolean itemand, Serializable value) { + return new FilterNode(column, express, itemand, value); + } + + private boolean needSplit(final Object val0) { + return needSplit(express, val0); + } + + private static boolean needSplit(final FilterExpress express, final Object val0) { + if (val0 == null) return false; + boolean items = express != IN && express != NOTIN; //鏄惁鏁扮粍闆嗗悎鐨勮〃杈惧紡 + if (!items) { + if (val0.getClass().isArray()) { + Class comp = val0.getClass().getComponentType(); + if (comp == java.io.Serializable.class) comp = ((Object[]) val0)[0].getClass(); + if (!(comp.isPrimitive() || CharSequence.class.isAssignableFrom(comp) || Number.class.isAssignableFrom(comp))) { + items = true; + } + } else if (val0 instanceof Collection) { + for (Object fv : (Collection) val0) { + if (fv == null) continue; + Class comp = fv.getClass(); + if (!(comp.isPrimitive() || CharSequence.class.isAssignableFrom(comp) || Number.class.isAssignableFrom(comp))) { + items = true; + } + break; //鍙渶妫娴嬬涓涓 + } + } + } + return items; + } + + protected final CharSequence createElementSQLExpress(DataSqlSource source, final EntityInfo info, String talis) { + final Object val0 = getValue(); + if (needSplit(val0)) { + if (val0 instanceof Collection) { + StringBuilder sb = new StringBuilder(); + boolean more = ((Collection) val0).size() > 1; + if (more) sb.append('('); + for (Object fv : (Collection) val0) { + if (fv == null) continue; + CharSequence cs = createElementSQLExpress(source, info, talis, fv); + if (cs == null) continue; + if (sb.length() > 2) sb.append(itemand ? " AND " : " OR "); + sb.append(cs); + } + if (more) sb.append(')'); + return sb.length() > 3 ? sb : null; //鑻b鐨勫煎彧鏄()锛屽垯涓嶈繃婊 + } else if (val0.getClass().isArray()) { + StringBuilder sb = new StringBuilder(); + Object[] fvs = (Object[]) val0; + boolean more = fvs.length > 1; + if (more) sb.append('('); + for (Object fv : fvs) { + if (fv == null) continue; + CharSequence cs = createElementSQLExpress(source, info, talis, fv); + if (cs == null) continue; + if (sb.length() > 2) sb.append(itemand ? " AND " : " OR "); + sb.append(cs); + } + if (more) sb.append(')'); + return sb.length() > 3 ? sb : null; //鑻b鐨勫煎彧鏄()锛屽垯涓嶈繃婊 + } + } + return createElementSQLExpress(source, info, talis, val0); + + } + + private CharSequence createElementSQLExpress(DataSqlSource source, final EntityInfo info, String talis, Object val0) { + if (column == null || this.column.isEmpty() || this.column.charAt(0) == '#') return null; + if (talis == null) talis = "a"; + if (express == ISNULL || express == ISNOTNULL) { + return new StringBuilder().append(info.getSQLColumn(talis, column)).append(' ').append(express.value()); + } + if (express == ISEMPTY || express == ISNOTEMPTY) { + return new StringBuilder().append(info.getSQLColumn(talis, column)).append(' ').append(express.value()).append(" ''"); + } + if (val0 == null) return null; + if (express == FV_MOD || express == FV_DIV) { + FilterValue fv = (FilterValue) val0; + return new StringBuilder().append(info.getSQLColumn(talis, column)).append(' ').append(express.value()).append(' ').append(fv.getOptvalue()) + .append(' ').append(fv.getExpress().value()).append(' ').append(fv.getDestvalue()); + } + final boolean fk = (val0 instanceof FilterKey); + CharSequence val = fk ? info.getSQLColumn(talis, ((FilterKey) val0).getColumn()) : formatToString(express, info.getSQLValue(column, (Serializable) val0)); + if (val == null) return null; + StringBuilder sb = new StringBuilder(32); + if (express == CONTAIN) return source.containSQL.replace("${column}", info.getSQLColumn(talis, column)).replace("${keystr}", val); + if (express == IGNORECASECONTAIN) return source.containSQL.replace("${column}", "LOWER(" + info.getSQLColumn(talis, column) + ")").replace("${keystr}", val); + if (express == NOTCONTAIN) return source.notcontainSQL.replace("${column}", info.getSQLColumn(talis, column)).replace("${keystr}", val); + if (express == IGNORECASENOTCONTAIN) return source.notcontainSQL.replace("${column}", "LOWER(" + info.getSQLColumn(talis, column) + ")").replace("${keystr}", val); + + if (express == LENGTH_EQUAL || express == LENGTH_LESSTHAN || express == LENGTH_LESSTHANOREQUALTO + || express == LENGTH_GREATERTHAN || express == LENGTH_GREATERTHANOREQUALTO) { + sb.append("LENGTH(").append(info.getSQLColumn(talis, column)).append(')'); + } else if (express == IGNORECASEEQUAL || express == IGNORECASENOTEQUAL || express == IGNORECASELIKE || express == IGNORECASENOTLIKE) { + sb.append("LOWER(").append(info.getSQLColumn(talis, column)).append(')'); + if (fk) val = "LOWER(" + info.getSQLColumn(talis, ((FilterKey) val0).getColumn()) + ')'; + } else { + sb.append(info.getSQLColumn(talis, column)); + } + sb.append(' '); + switch (express) { + case OPAND: + case OPOR: + sb.append(express.value()).append(' ').append(val).append(" > 0"); + break; + case OPANDNO: + sb.append(express.value()).append(' ').append(val).append(" = 0"); + break; + default: + sb.append(express.value()).append(' ').append(val); + break; + } + return sb; + } + + protected Predicate createPredicate(final EntityCache cache) { + if (cache == null || (column == null && this.nodes == null)) return null; + Predicate filter = createElementPredicate(cache, false); + if (this.nodes == null) return filter; + for (FilterNode node : this.nodes) { + Predicate f = node.createPredicate(cache); + if (f == null) continue; + final Predicate one = filter; + final Predicate two = f; + filter = (filter == null) ? f : (or ? new Predicate() { + + @Override + public boolean test(T t) { + return one.test(t) || two.test(t); + } + + @Override + public String toString() { + return "(" + one + " OR " + two + ")"; + } + } : new Predicate() { + + @Override + public boolean test(T t) { + return one.test(t) && two.test(t); + } + + @Override + public String toString() { + return "(" + one + " AND " + two + ")"; + } + }); + } + return filter; + } + + protected final Predicate createElementPredicate(final EntityCache cache, final boolean join) { + if (this.column == null || this.column.isEmpty() || this.column.charAt(0) == '#') return null; + return createElementPredicate(cache, join, cache.getAttribute(column)); + } + + @SuppressWarnings("unchecked") + protected final Predicate createElementPredicate(final EntityCache cache, final boolean join, final Attribute attr) { + final Object val0 = getValue(); + if (needSplit(val0)) { + if (val0 instanceof Collection) { + Predicate filter = null; + for (Object fv : (Collection) val0) { + if (fv == null) continue; + Predicate f = createElementPredicate(cache, join, attr, fv); + if (f == null) continue; + final Predicate one = filter; + final Predicate two = f; + filter = (filter == null) ? f : (!itemand ? new Predicate() { + + @Override + public boolean test(T t) { + return one.test(t) || two.test(t); + } + + @Override + public String toString() { + return "(" + one + " OR " + two + ")"; + } + } : new Predicate() { + + @Override + public boolean test(T t) { + return one.test(t) && two.test(t); + } + + @Override + public String toString() { + return "(" + one + " AND " + two + ")"; + } + }); + } + return filter; + } else if (val0.getClass().isArray()) { + final Class primtype = val0.getClass(); + Object val2 = val0; + int ix = -1; + if (primtype == boolean[].class) { + boolean[] bs = (boolean[]) val0; + Boolean[] ns = new Boolean[bs.length]; + for (boolean v : bs) { + ns[++ix] = v; + } + val2 = ns; + } else if (primtype == byte[].class) { + byte[] bs = (byte[]) val0; + Byte[] ns = new Byte[bs.length]; + for (byte v : bs) { + ns[++ix] = v; + } + val2 = ns; + } else if (primtype == short[].class) { + short[] bs = (short[]) val0; + Short[] ns = new Short[bs.length]; + for (short v : bs) { + ns[++ix] = v; + } + val2 = ns; + } else if (primtype == char[].class) { + char[] bs = (char[]) val0; + Character[] ns = new Character[bs.length]; + for (char v : bs) { + ns[++ix] = v; + } + val2 = ns; + } else if (primtype == int[].class) { + int[] bs = (int[]) val0; + Integer[] ns = new Integer[bs.length]; + for (int v : bs) { + ns[++ix] = v; + } + val2 = ns; + } else if (primtype == float[].class) { + float[] bs = (float[]) val0; + Float[] ns = new Float[bs.length]; + for (float v : bs) { + ns[++ix] = v; + } + val2 = ns; + } else if (primtype == long[].class) { + long[] bs = (long[]) val0; + Long[] ns = new Long[bs.length]; + for (long v : bs) { + ns[++ix] = v; + } + val2 = ns; + } else if (primtype == double[].class) { + double[] bs = (double[]) val0; + Double[] ns = new Double[bs.length]; + for (double v : bs) { + ns[++ix] = v; + } + val2 = ns; + } + Predicate filter = null; + for (Object fv : (Object[]) val2) { + if (fv == null) continue; + Predicate f = createElementPredicate(cache, join, attr, fv); + if (f == null) continue; + final Predicate one = filter; + final Predicate two = f; + filter = (filter == null) ? f : (!itemand ? new Predicate() { + + @Override + public boolean test(T t) { + return one.test(t) || two.test(t); + } + + @Override + public String toString() { + return "(" + one + " OR " + two + ")"; + } + } : new Predicate() { + + @Override + public boolean test(T t) { + return one.test(t) && two.test(t); + } + + @Override + public String toString() { + return "(" + one + " AND " + two + ")"; + } + }); + } + return filter; + } + } + return createElementPredicate(cache, join, attr, val0); + } + + @SuppressWarnings("unchecked") + protected final Predicate createElementPredicate(final EntityCache cache, final boolean join, final Attribute attr, Object val0) { + if (attr == null) return null; + final String field = join ? (cache.getType().getSimpleName() + "." + attr.field()) : attr.field(); + if (express == ISNULL) return new Predicate() { + + @Override + public boolean test(T t) { + return attr.get(t) == null; + } + + @Override + public String toString() { + return field + " = null"; + } + }; + if (express == ISNOTNULL) return new Predicate() { + + @Override + public boolean test(T t) { + return attr.get(t) != null; + } + + @Override + public String toString() { + return field + " != null"; + } + }; + if (express == ISEMPTY) return new Predicate() { + + @Override + public boolean test(T t) { + Object v = attr.get(t); + return v == null || v.toString().isEmpty(); + } + + @Override + public String toString() { + return field + " = ''"; + } + }; + if (express == ISNOTEMPTY) return new Predicate() { + + @Override + public boolean test(T t) { + Object v = attr.get(t); + return v != null && !v.toString().isEmpty(); + } + + @Override + public String toString() { + return field + " != ''"; + } + }; + if (val0 == null) return null; + + final Class atype = attr.type(); + final Class valtype = val0.getClass(); + if (atype != valtype && val0 instanceof Number) { + if (atype == int.class || atype == Integer.class) { + val0 = ((Number) val0).intValue(); + } else if (atype == long.class || atype == Long.class) { + val0 = ((Number) val0).longValue(); + } else if (atype == short.class || atype == Short.class) { + val0 = ((Number) val0).shortValue(); + } else if (atype == float.class || atype == Float.class) { + val0 = ((Number) val0).floatValue(); + } else if (atype == byte.class || atype == Byte.class) { + val0 = ((Number) val0).byteValue(); + } else if (atype == double.class || atype == Double.class) { + val0 = ((Number) val0).doubleValue(); + } + } else if (valtype.isArray()) { + final int len = Array.getLength(val0); + if (len == 0 && express == NOTIN) return null; + final Class compType = valtype.getComponentType(); + if (atype != compType && len > 0) { + if (!compType.isPrimitive() && Number.class.isAssignableFrom(compType)) throw new RuntimeException("param(" + val0 + ") type not match " + atype + " for column " + column); + if (atype == int.class || atype == Integer.class) { + int[] vs = new int[len]; + for (int i = 0; i < len; i++) { + vs[i] = ((Number) Array.get(val0, i)).intValue(); + } + val0 = vs; + } else if (atype == long.class || atype == Long.class) { + long[] vs = new long[len]; + for (int i = 0; i < len; i++) { + vs[i] = ((Number) Array.get(val0, i)).longValue(); + } + val0 = vs; + } else if (atype == short.class || atype == Short.class) { + short[] vs = new short[len]; + for (int i = 0; i < len; i++) { + vs[i] = ((Number) Array.get(val0, i)).shortValue(); + } + val0 = vs; + } else if (atype == float.class || atype == Float.class) { + float[] vs = new float[len]; + for (int i = 0; i < len; i++) { + vs[i] = ((Number) Array.get(val0, i)).floatValue(); + } + val0 = vs; + } else if (atype == byte.class || atype == Byte.class) { + byte[] vs = new byte[len]; + for (int i = 0; i < len; i++) { + vs[i] = ((Number) Array.get(val0, i)).byteValue(); + } + val0 = vs; + } else if (atype == double.class || atype == Double.class) { + double[] vs = new double[len]; + for (int i = 0; i < len; i++) { + vs[i] = ((Number) Array.get(val0, i)).doubleValue(); + } + val0 = vs; + } + } + } else if (val0 instanceof Collection) { + final Collection collection = (Collection) val0; + if (collection.isEmpty() && express == NOTIN) return null; + if (!collection.isEmpty()) { + Iterator it = collection.iterator(); + it.hasNext(); + Class fs = it.next().getClass(); + Class pfs = fs; + if (fs == Integer.class) { + pfs = int.class; + } else if (fs == Long.class) { + pfs = long.class; + } else if (fs == Short.class) { + pfs = short.class; + } else if (fs == Float.class) { + pfs = float.class; + } else if (fs == Byte.class) { + pfs = byte.class; + } else if (fs == Double.class) { + pfs = double.class; + } + if (Number.class.isAssignableFrom(fs) && atype != fs && atype != pfs) { //闇瑕佽浆鎹 + ArrayList list = new ArrayList(collection.size()); + if (atype == int.class || atype == Integer.class) { + for (Number num : (Collection) collection) { + list.add(num.intValue()); + } + } else if (atype == long.class || atype == Long.class) { + for (Number num : (Collection) collection) { + list.add(num.longValue()); + } + } else if (atype == short.class || atype == Short.class) { + for (Number num : (Collection) collection) { + list.add(num.shortValue()); + } + } else if (atype == float.class || atype == Float.class) { + for (Number num : (Collection) collection) { + list.add(num.floatValue()); + } + } else if (atype == byte.class || atype == Byte.class) { + for (Number num : (Collection) collection) { + list.add(num.byteValue()); + } + } else if (atype == double.class || atype == Double.class) { + for (Number num : (Collection) collection) { + list.add(num.doubleValue()); + } + } + val0 = list; + } + } + } + final Serializable val = (Serializable) val0; + final boolean fk = (val instanceof FilterKey); + final Attribute fkattr = fk ? cache.getAttribute(((FilterKey) val).getColumn()) : null; + if (fk && fkattr == null) throw new RuntimeException(cache.getType() + " not found column(" + ((FilterKey) val).getColumn() + ")"); + switch (express) { + case EQUAL: + return fk ? new Predicate() { + + @Override + public boolean test(T t) { + return Objects.equals(fkattr.get(t), attr.get(t)); + } + + @Override + public String toString() { + return field + ' ' + express.value() + ' ' + fkattr.field(); + } + } : new Predicate() { + + @Override + public boolean test(T t) { + return val.equals(attr.get(t)); + } + + @Override + public String toString() { + return field + ' ' + express.value() + ' ' + formatToString(val); + } + }; + case IGNORECASEEQUAL: + return fk ? new Predicate() { + + @Override + public boolean test(T t) { + Object rs = attr.get(t); + Object rs2 = fkattr.get(t); + if (rs == null && rs2 == null) return true; + if (rs == null || rs2 == null) return false; + return Objects.equals(rs.toString().toLowerCase(), rs2.toString().toLowerCase()); + } + + @Override + public String toString() { + return "LOWER(" + field + ") " + express.value() + " LOWER(" + fkattr.field() + ')'; + } + } : new Predicate() { + + @Override + public boolean test(T t) { + Object rs = attr.get(t); + if (rs == null) return false; + return val.toString().equalsIgnoreCase(rs.toString()); + } + + @Override + public String toString() { + return "LOWER(" + field + ") " + express.value() + ' ' + formatToString(val); + } + }; + case NOTEQUAL: + return fk ? new Predicate() { + + @Override + public boolean test(T t) { + return !Objects.equals(fkattr.get(t), attr.get(t)); + } + + @Override + public String toString() { + return field + ' ' + express.value() + ' ' + fkattr.field(); + } + } : new Predicate() { + + @Override + public boolean test(T t) { + return !val.equals(attr.get(t)); + } + + @Override + public String toString() { + return field + ' ' + express.value() + ' ' + formatToString(val); + } + }; + case IGNORECASENOTEQUAL: + return fk ? new Predicate() { + + @Override + public boolean test(T t) { + Object rs = attr.get(t); + Object rs2 = fkattr.get(t); + if (rs == null && rs2 == null) return false; + if (rs == null || rs2 == null) return true; + return !Objects.equals(rs.toString().toLowerCase(), rs2.toString().toLowerCase()); + } + + @Override + public String toString() { + return "LOWER(" + field + ") " + express.value() + " LOWER(" + fkattr.field() + ')'; + } + } : new Predicate() { + + @Override + public boolean test(T t) { + Object rs = attr.get(t); + if (rs == null) return true; + return !val.toString().equalsIgnoreCase(rs.toString()); + } + + @Override + public String toString() { + return "LOWER(" + field + ") " + express.value() + ' ' + formatToString(val); + } + }; + case GREATERTHAN: + return fk ? new Predicate() { + + @Override + public boolean test(T t) { + return ((Comparable) attr.get(t)).compareTo((Comparable) fkattr.get(t)) > 0; + } + + @Override + public String toString() { + return field + ' ' + express.value() + ' ' + fkattr.field(); + } + } : new Predicate() { + + @Override + public boolean test(T t) { + return ((Comparable) attr.get(t)).compareTo(((Comparable) val)) > 0; + } + + @Override + public String toString() { + return field + ' ' + express.value() + ' ' + val; + } + }; + case LESSTHAN: + return fk ? new Predicate() { + + @Override + public boolean test(T t) { + return ((Comparable) attr.get(t)).compareTo((Comparable) fkattr.get(t)) < 0; + } + + @Override + public String toString() { + return field + ' ' + express.value() + ' ' + fkattr.field(); + } + } : new Predicate() { + + @Override + public boolean test(T t) { + return ((Comparable) attr.get(t)).compareTo(((Comparable) val)) < 0; + } + + @Override + public String toString() { + return field + ' ' + express.value() + ' ' + val; + } + }; + case GREATERTHANOREQUALTO: + return fk ? new Predicate() { + + @Override + public boolean test(T t) { + return ((Comparable) attr.get(t)).compareTo((Comparable) fkattr.get(t)) >= 0; + } + + @Override + public String toString() { + return field + ' ' + express.value() + ' ' + fkattr.field(); + } + } : new Predicate() { + + @Override + public boolean test(T t) { + return ((Comparable) attr.get(t)).compareTo(((Comparable) val)) >= 0; + } + + @Override + public String toString() { + return field + ' ' + express.value() + ' ' + val; + } + }; + case LESSTHANOREQUALTO: + return fk ? new Predicate() { + + @Override + public boolean test(T t) { + return ((Comparable) attr.get(t)).compareTo((Comparable) fkattr.get(t)) <= 0; + } + + @Override + public String toString() { + return field + ' ' + express.value() + ' ' + fkattr.field(); + } + } : new Predicate() { + + @Override + public boolean test(T t) { + return ((Comparable) attr.get(t)).compareTo(((Comparable) val)) <= 0; + } + + @Override + public String toString() { + return field + ' ' + express.value() + ' ' + val; + } + }; + + case FV_MOD: + FilterValue fv0 = (FilterValue) val; + switch (fv0.getExpress()) { + case EQUAL: + return new Predicate() { + + @Override + public boolean test(T t) { + return (((Number) attr.get(t)).longValue() % fv0.getOptvalue().longValue()) == fv0.getDestvalue().longValue(); + } + + @Override + public String toString() { + return field + " " + express.value() + " " + fv0.getOptvalue() + " " + fv0.getExpress().value() + " " + fv0.getDestvalue(); + } + }; + case NOTEQUAL: + return new Predicate() { + + @Override + public boolean test(T t) { + return (((Number) attr.get(t)).longValue() % fv0.getOptvalue().longValue()) != fv0.getDestvalue().longValue(); + } + + @Override + public String toString() { + return field + " " + express.value() + " " + fv0.getOptvalue() + " " + fv0.getExpress().value() + " " + fv0.getDestvalue(); + } + }; + case GREATERTHAN: + return new Predicate() { + + @Override + public boolean test(T t) { + return (((Number) attr.get(t)).longValue() % fv0.getOptvalue().longValue()) > fv0.getDestvalue().longValue(); + } + + @Override + public String toString() { + return field + " " + express.value() + " " + fv0.getOptvalue() + " " + fv0.getExpress().value() + " " + fv0.getDestvalue(); + } + }; + case LESSTHAN: + return new Predicate() { + + @Override + public boolean test(T t) { + return (((Number) attr.get(t)).longValue() % fv0.getOptvalue().longValue()) < fv0.getDestvalue().longValue(); + } + + @Override + public String toString() { + return field + " " + express.value() + " " + fv0.getOptvalue() + " " + fv0.getExpress().value() + " " + fv0.getDestvalue(); + } + }; + case GREATERTHANOREQUALTO: + return new Predicate() { + + @Override + public boolean test(T t) { + return (((Number) attr.get(t)).longValue() % fv0.getOptvalue().longValue()) >= fv0.getDestvalue().longValue(); + } + + @Override + public String toString() { + return field + " " + express.value() + " " + fv0.getOptvalue() + " " + fv0.getExpress().value() + " " + fv0.getDestvalue(); + } + }; + case LESSTHANOREQUALTO: + return new Predicate() { + + @Override + public boolean test(T t) { + return (((Number) attr.get(t)).longValue() % fv0.getOptvalue().longValue()) <= fv0.getDestvalue().longValue(); + } + + @Override + public String toString() { + return field + " " + express.value() + " " + fv0.getOptvalue() + " " + fv0.getExpress().value() + " " + fv0.getDestvalue(); + } + }; + default: + throw new RuntimeException("(" + fv0 + ")'s express illegal, must be =, !=, <, >, <=, >="); + } + case FV_DIV: + FilterValue fv1 = (FilterValue) val; + switch (fv1.getExpress()) { + case EQUAL: + return new Predicate() { + + @Override + public boolean test(T t) { + return (((Number) attr.get(t)).longValue() / fv1.getOptvalue().longValue()) == fv1.getDestvalue().longValue(); + } + + @Override + public String toString() { + return field + " " + express.value() + " " + fv1.getOptvalue() + " " + fv1.getExpress().value() + " " + fv1.getDestvalue(); + } + }; + case NOTEQUAL: + return new Predicate() { + + @Override + public boolean test(T t) { + return (((Number) attr.get(t)).longValue() / fv1.getOptvalue().longValue()) != fv1.getDestvalue().longValue(); + } + + @Override + public String toString() { + return field + " " + express.value() + " " + fv1.getOptvalue() + " " + fv1.getExpress().value() + " " + fv1.getDestvalue(); + } + }; + case GREATERTHAN: + return new Predicate() { + + @Override + public boolean test(T t) { + return (((Number) attr.get(t)).longValue() / fv1.getOptvalue().longValue()) > fv1.getDestvalue().longValue(); + } + + @Override + public String toString() { + return field + " " + express.value() + " " + fv1.getOptvalue() + " " + fv1.getExpress().value() + " " + fv1.getDestvalue(); + } + }; + case LESSTHAN: + return new Predicate() { + + @Override + public boolean test(T t) { + return (((Number) attr.get(t)).longValue() / fv1.getOptvalue().longValue()) < fv1.getDestvalue().longValue(); + } + + @Override + public String toString() { + return field + " " + express.value() + " " + fv1.getOptvalue() + " " + fv1.getExpress().value() + " " + fv1.getDestvalue(); + } + }; + case GREATERTHANOREQUALTO: + return new Predicate() { + + @Override + public boolean test(T t) { + return (((Number) attr.get(t)).longValue() / fv1.getOptvalue().longValue()) >= fv1.getDestvalue().longValue(); + } + + @Override + public String toString() { + return field + " " + express.value() + " " + fv1.getOptvalue() + " " + fv1.getExpress().value() + " " + fv1.getDestvalue(); + } + }; + case LESSTHANOREQUALTO: + return new Predicate() { + + @Override + public boolean test(T t) { + return (((Number) attr.get(t)).longValue() / fv1.getOptvalue().longValue()) <= fv1.getDestvalue().longValue(); + } + + @Override + public String toString() { + return field + " " + express.value() + " " + fv1.getOptvalue() + " " + fv1.getExpress().value() + " " + fv1.getDestvalue(); + } + }; + default: + throw new RuntimeException("(" + fv1 + ")'s express illegal, must be =, !=, <, >, <=, >="); + } + case OPAND: + return fk ? new Predicate() { + + @Override + public boolean test(T t) { + return (((Number) attr.get(t)).longValue() & ((Number) fkattr.get(t)).longValue()) > 0; + } + + @Override + public String toString() { + return field + " & " + fkattr.field() + " > 0"; + } + } : new Predicate() { + + @Override + public boolean test(T t) { + return (((Number) attr.get(t)).longValue() & ((Number) val).longValue()) > 0; + } + + @Override + public String toString() { + return field + " & " + val + " > 0"; + } + }; + case OPOR: + return fk ? new Predicate() { + + @Override + public boolean test(T t) { + return (((Number) attr.get(t)).longValue() | ((Number) fkattr.get(t)).longValue()) > 0; + } + + @Override + public String toString() { + return field + " | " + fkattr.field() + " > 0"; + } + } : new Predicate() { + + @Override + public boolean test(T t) { + return (((Number) attr.get(t)).longValue() | ((Number) val).longValue()) > 0; + } + + @Override + public String toString() { + return field + " | " + val + " > 0"; + } + }; + case OPANDNO: + return fk ? new Predicate() { + + @Override + public boolean test(T t) { + return (((Number) attr.get(t)).longValue() & ((Number) fkattr.get(t)).longValue()) == 0; + } + + @Override + public String toString() { + return field + " & " + fkattr.field() + " = 0"; + } + } : new Predicate() { + + @Override + public boolean test(T t) { + return (((Number) attr.get(t)).longValue() & ((Number) val).longValue()) == 0; + } + + @Override + public String toString() { + return field + " & " + val + " = 0"; + } + }; + case LIKE: + return fk ? new Predicate() { + + @Override + public boolean test(T t) { + Object rs = attr.get(t); + Object rs2 = fkattr.get(t); + return rs != null && rs2 != null && rs.toString().contains(rs2.toString()); + } + + @Override + public String toString() { + return field + ' ' + express.value() + ' ' + fkattr.field(); + } + } : new Predicate() { + + @Override + public boolean test(T t) { + Object rs = attr.get(t); + return rs != null && rs.toString().contains(val.toString()); + } + + @Override + public String toString() { + return field + ' ' + express.value() + ' ' + formatToString(val); + } + }; + case STARTSWITH: + return fk ? new Predicate() { + + @Override + public boolean test(T t) { + Object rs = attr.get(t); + Object rs2 = fkattr.get(t); + return rs != null && rs2 != null && rs.toString().startsWith(rs2.toString()); + } + + @Override + public String toString() { + return field + " STARTSWITH " + fkattr.field(); + } + } : new Predicate() { + + @Override + public boolean test(T t) { + Object rs = attr.get(t); + return rs != null && rs.toString().startsWith(val.toString()); + } + + @Override + public String toString() { + return field + " STARTSWITH " + formatToString(val); + } + }; + case ENDSWITH: + return fk ? new Predicate() { + + @Override + public boolean test(T t) { + Object rs = attr.get(t); + Object rs2 = fkattr.get(t); + return rs != null && rs2 != null && rs.toString().endsWith(rs2.toString()); + } + + @Override + public String toString() { + return field + " ENDSWITH " + fkattr.field(); + } + } : new Predicate() { + + @Override + public boolean test(T t) { + Object rs = attr.get(t); + return rs != null && rs.toString().endsWith(val.toString()); + } + + @Override + public String toString() { + return field + " ENDSWITH " + formatToString(val); + } + }; + case IGNORECASELIKE: + if (fk) return new Predicate() { + + @Override + public boolean test(T t) { + Object rs = attr.get(t); + Object rs2 = fkattr.get(t); + return rs != null && rs2 != null && rs.toString().toLowerCase().contains(rs2.toString().toLowerCase()); + } + + @Override + public String toString() { + return "LOWER(" + field + ") " + express.value() + " LOWER(" + fkattr.field() + ')'; + } + }; + final String valstr = val.toString().toLowerCase(); + return new Predicate() { + + @Override + public boolean test(T t) { + Object rs = attr.get(t); + return rs != null && rs.toString().toLowerCase().contains(valstr); + } + + @Override + public String toString() { + return "LOWER(" + field + ") " + express.value() + ' ' + formatToString(valstr); + } + }; + case NOTSTARTSWITH: + return fk ? new Predicate() { + + @Override + public boolean test(T t) { + Object rs = attr.get(t); + Object rs2 = fkattr.get(t); + return rs == null || rs2 == null || !rs.toString().startsWith(rs2.toString()); + } + + @Override + public String toString() { + return field + " NOT STARTSWITH " + fkattr.field(); + } + } : new Predicate() { + + @Override + public boolean test(T t) { + Object rs = attr.get(t); + return rs == null || !rs.toString().startsWith(val.toString()); + } + + @Override + public String toString() { + return field + " NOT STARTSWITH " + formatToString(val); + } + }; + case NOTENDSWITH: + return fk ? new Predicate() { + + @Override + public boolean test(T t) { + Object rs = attr.get(t); + Object rs2 = fkattr.get(t); + return rs == null || rs2 == null || !rs.toString().endsWith(rs2.toString()); + } + + @Override + public String toString() { + return field + " NOT ENDSWITH " + fkattr.field(); + } + } : new Predicate() { + + @Override + public boolean test(T t) { + Object rs = attr.get(t); + return rs == null || !rs.toString().endsWith(val.toString()); + } + + @Override + public String toString() { + return field + " NOT ENDSWITH " + formatToString(val); + } + }; + case IGNORECASENOTLIKE: + if (fk) return new Predicate() { + + @Override + public boolean test(T t) { + Object rs = attr.get(t); + Object rs2 = fkattr.get(t); + return rs == null || rs2 == null || !rs.toString().toLowerCase().contains(rs2.toString().toLowerCase()); + } + + @Override + public String toString() { + return "LOWER(" + field + ") " + express.value() + " LOWER(" + fkattr.field() + ')'; + } + }; + final String valstr2 = val.toString().toLowerCase(); + return new Predicate() { + + @Override + public boolean test(T t) { + Object rs = attr.get(t); + return rs == null || !rs.toString().toLowerCase().contains(valstr2); + } + + @Override + public String toString() { + return "LOWER(" + field + ") " + express.value() + ' ' + formatToString(valstr2); + } + }; + case LENGTH_EQUAL: + final int intval = ((Number) val).intValue(); + return new Predicate() { + + @Override + public boolean test(T t) { + Object rs = attr.get(t); + return (rs == null && 0 == intval) || (rs != null && rs.toString().length() == intval); + } + + @Override + public String toString() { + return "LENGTH(" + field + ") " + express.value() + ' ' + intval; + } + }; + case LENGTH_LESSTHAN: + final int intval2 = ((Number) val).intValue(); + return new Predicate() { + + @Override + public boolean test(T t) { + Object rs = attr.get(t); + return (rs == null && 0 < intval2) || (rs != null && rs.toString().length() < intval2); + } + + @Override + public String toString() { + return "LENGTH(" + field + ") " + express.value() + ' ' + intval2; + } + }; + case LENGTH_LESSTHANOREQUALTO: + final int intval3 = ((Number) val).intValue(); + return new Predicate() { + + @Override + public boolean test(T t) { + Object rs = attr.get(t); + return (rs == null && 0 <= intval3) || (rs != null && rs.toString().length() <= intval3); + } + + @Override + public String toString() { + return "LENGTH(" + field + ") " + express.value() + ' ' + intval3; + } + }; + case LENGTH_GREATERTHAN: + final int intval4 = ((Number) val).intValue(); + return new Predicate() { + + @Override + public boolean test(T t) { + Object rs = attr.get(t); + return (rs == null && 0 > intval4) || (rs != null && rs.toString().length() > intval4); + } + + @Override + public String toString() { + return "LENGTH(" + field + ") " + express.value() + ' ' + intval4; + } + }; + case LENGTH_GREATERTHANOREQUALTO: + final int intval5 = ((Number) val).intValue(); + return new Predicate() { + + @Override + public boolean test(T t) { + Object rs = attr.get(t); + return (rs == null && 0 >= intval5) || (rs != null && rs.toString().length() >= intval5); + } + + @Override + public String toString() { + return "LENGTH(" + field + ") " + express.value() + ' ' + intval5; + } + }; + case CONTAIN: + return fk ? new Predicate() { + + @Override + public boolean test(T t) { + Object rs = attr.get(t); + Object rs2 = fkattr.get(t); + return rs != null && rs2 != null && rs2.toString().contains(rs.toString()); + } + + @Override + public String toString() { + return fkattr.field() + ' ' + express.value() + ' ' + field; + } + } : new Predicate() { + + @Override + public boolean test(T t) { + Object rs = attr.get(t); + return rs != null && val.toString().contains(rs.toString()); + } + + @Override + public String toString() { + return "" + formatToString(val) + ' ' + express.value() + ' ' + field; + } + }; + case IGNORECASECONTAIN: + if (fk) return new Predicate() { + + @Override + public boolean test(T t) { + Object rs = attr.get(t); + Object rs2 = fkattr.get(t); + return rs != null && rs2 != null && rs2.toString().toLowerCase().contains(rs.toString().toLowerCase()); + } + + @Override + public String toString() { + return " LOWER(" + fkattr.field() + ") " + express.value() + ' ' + "LOWER(" + field + ") "; + } + }; + final String valstr3 = val.toString().toLowerCase(); + return new Predicate() { + + @Override + public boolean test(T t) { + Object rs = attr.get(t); + return rs != null && valstr3.contains(rs.toString().toLowerCase()); + } + + @Override + public String toString() { + return "" + formatToString(valstr3) + express.value() + ' ' + "LOWER(" + field + ") "; + } + }; + case NOTCONTAIN: + return fk ? new Predicate() { + + @Override + public boolean test(T t) { + Object rs = attr.get(t); + Object rs2 = fkattr.get(t); + return rs == null || rs2 == null || !rs2.toString().contains(rs.toString()); + } + + @Override + public String toString() { + return fkattr.field() + ' ' + express.value() + ' ' + field; + } + } : new Predicate() { + + @Override + public boolean test(T t) { + Object rs = attr.get(t); + return rs == null || !val.toString().contains(rs.toString()); + } + + @Override + public String toString() { + return "" + formatToString(val) + ' ' + express.value() + ' ' + field; + } + }; + case IGNORECASENOTCONTAIN: + if (fk) return new Predicate() { + + @Override + public boolean test(T t) { + Object rs = attr.get(t); + Object rs2 = fkattr.get(t); + return rs == null || rs2 == null || !rs2.toString().toLowerCase().contains(rs.toString().toLowerCase()); + } + + @Override + public String toString() { + return " LOWER(" + fkattr.field() + ") " + express.value() + ' ' + "LOWER(" + field + ") "; + } + }; + final String valstr4 = val.toString().toLowerCase(); + return new Predicate() { + + @Override + public boolean test(T t) { + Object rs = attr.get(t); + return rs == null || !valstr4.contains(rs.toString().toLowerCase()); + } + + @Override + public String toString() { + return "" + formatToString(valstr4) + express.value() + ' ' + "LOWER(" + field + ") "; + } + }; + case BETWEEN: + case NOTBETWEEN: + Range range = (Range) val; + final Comparable min = range.getMin(); + final Comparable max = range.getMax(); + if (express == BETWEEN) return new Predicate() { + + @Override + public boolean test(T t) { + Comparable rs = (Comparable) attr.get(t); + if (rs == null) return false; + if (min != null && min.compareTo(rs) >= 0) return false; + return !(max != null && max.compareTo(rs) <= 0); + } + + @Override + public String toString() { + return field + " BETWEEN " + min + " AND " + max; + } + }; + if (express == NOTBETWEEN) return new Predicate() { + + @Override + public boolean test(T t) { + Comparable rs = (Comparable) attr.get(t); + if (rs == null) return true; + if (min != null && min.compareTo(rs) >= 0) return true; + return (max != null && max.compareTo(rs) <= 0); + } + + @Override + public String toString() { + return field + " NOT BETWEEN " + min + " AND " + max; + } + }; + return null; + case IN: + case NOTIN: + Predicate filter; + if (val instanceof Collection) { + Collection array = (Collection) val; + if (array.isEmpty()) { //express 鍙細鏄 IN + filter = new Predicate() { + + @Override + public boolean test(T t) { + return false; + } + + @Override + public String toString() { + return field + ' ' + express.value() + " []"; + } + }; + } else { + filter = new Predicate() { + + @Override + public boolean test(T t) { + Object rs = attr.get(t); + return rs != null && array.contains(rs); + } + + @Override + public String toString() { + return field + ' ' + express.value() + ' ' + val; + } + }; + } + } else { + Class type = val.getClass(); + if (Array.getLength(val) == 0) {//express 鍙細鏄 IN + filter = new Predicate() { + + @Override + public boolean test(T t) { + return false; + } + + @Override + public String toString() { + return field + ' ' + express.value() + " []"; + } + }; + } else if (type == int[].class) { + filter = new Predicate() { + + @Override + public boolean test(T t) { + Object rs = attr.get(t); + if (rs == null) return false; + int k = (int) rs; + for (int v : (int[]) val) { + if (v == k) return true; + } + return false; + } + + @Override + public String toString() { + return field + ' ' + express.value() + ' ' + Arrays.toString((int[]) val); + } + }; + } else if (type == short[].class) { + filter = new Predicate() { + + @Override + public boolean test(T t) { + Object rs = attr.get(t); + if (rs == null) return false; + short k = (short) rs; + for (short v : (short[]) val) { + if (v == k) return true; + } + return false; + } + + @Override + public String toString() { + return field + ' ' + express.value() + ' ' + Arrays.toString((short[]) val); + } + }; + } else if (type == long[].class) { + filter = new Predicate() { + + @Override + public boolean test(T t) { + Object rs = attr.get(t); + if (rs == null) return false; + long k = (long) rs; + for (long v : (long[]) val) { + if (v == k) return true; + } + return false; + } + + @Override + public String toString() { + return field + ' ' + express.value() + ' ' + Arrays.toString((long[]) val); + } + }; + } else if (type == float[].class) { + filter = new Predicate() { + + @Override + public boolean test(T t) { + Object rs = attr.get(t); + if (rs == null) return false; + float k = (float) rs; + for (float v : (float[]) val) { + if (v == k) return true; + } + return false; + } + + @Override + public String toString() { + return field + ' ' + express.value() + ' ' + Arrays.toString((float[]) val); + } + }; + } else if (type == double[].class) { + filter = new Predicate() { + + @Override + public boolean test(T t) { + Object rs = attr.get(t); + if (rs == null) return false; + double k = (double) rs; + for (double v : (double[]) val) { + if (v == k) return true; + } + return false; + } + + @Override + public String toString() { + return field + ' ' + express.value() + ' ' + Arrays.toString((double[]) val); + } + }; + } else { + filter = new Predicate() { + + @Override + public boolean test(T t) { + Object rs = attr.get(t); + if (rs == null) return false; + for (Object v : (Object[]) val) { + if (rs.equals(v)) return true; + } + return false; + } + + @Override + public String toString() { + return field + ' ' + express.value() + ' ' + Arrays.toString((Object[]) val); + } + }; + } + } + if (express == NOTIN) { + final Predicate filter2 = filter; + filter = new Predicate() { + + @Override + public boolean test(T t) { + return !filter2.test(t); + } + + @Override + public String toString() { + return filter2.toString(); + } + }; + } + return filter; + } + return null; + } + + @Override + public String toString() { + return toString(null).toString(); + } + + protected StringBuilder toString(final String prefix) { + StringBuilder sb = new StringBuilder(); + StringBuilder element = toElementString(prefix); + boolean more = element != null && element.length() > 0 && this.nodes != null; + if (more) sb.append('('); + sb.append(element); + if (this.nodes != null) { + for (FilterNode node : this.nodes) { + String s = node.toString(); + if (s.length() < 1) continue; + if (sb.length() > 1) sb.append(or ? " OR " : " AND "); + sb.append(s); + } + } + if (more) sb.append(')'); + return sb; + } + + protected final StringBuilder toElementString(final String prefix) { + Serializable val0 = getValue(); + if (needSplit(val0)) { + if (val0 instanceof Collection) { + StringBuilder sb = new StringBuilder(); + boolean more = ((Collection) val0).size() > 1; + if (more) sb.append('('); + for (Object fv : (Collection) val0) { + if (fv == null) continue; + CharSequence cs = toElementString(prefix, fv); + if (cs == null) continue; + if (sb.length() > 2) sb.append(itemand ? " AND " : " OR "); + sb.append(cs); + } + if (more) sb.append(')'); + return sb.length() > 3 ? sb : null; //鑻b鐨勫煎彧鏄()锛屽垯涓嶈繃婊 + } else if (val0.getClass().isArray()) { + StringBuilder sb = new StringBuilder(); + Object[] fvs = (Object[]) val0; + boolean more = fvs.length > 1; + if (more) sb.append('('); + for (Object fv : fvs) { + if (fv == null) continue; + CharSequence cs = toElementString(prefix, fv); + if (cs == null) continue; + if (sb.length() > 2) sb.append(itemand ? " AND " : " OR "); + sb.append(cs); + } + if (more) sb.append(')'); + return sb.length() > 3 ? sb : null; //鑻b鐨勫煎彧鏄()锛屽垯涓嶈繃婊 + } + } + return toElementString(prefix, val0); + } + + protected final StringBuilder toElementString(final String prefix, Object ev) { + StringBuilder sb = new StringBuilder(); + if (column != null) { + String col = prefix == null ? column : (prefix + "." + column); + if (express == ISNULL || express == ISNOTNULL) { + sb.append(col).append(' ').append(express.value()); + } else if (express == ISEMPTY || express == ISNOTEMPTY) { + sb.append(col).append(' ').append(express.value()).append(" ''"); + } else if (ev != null) { + boolean lower = (express == IGNORECASELIKE || express == IGNORECASENOTLIKE || express == IGNORECASECONTAIN || express == IGNORECASENOTCONTAIN); + sb.append(lower ? ("LOWER(" + col + ')') : col).append(' ').append(express.value()).append(' ').append(formatToString(express, ev)); + } + } + return sb; + } + + private static CharSequence formatToString(Object value) { + CharSequence sb = formatToString(null, value); + return sb == null ? null : sb.toString(); + } + + private static CharSequence formatToString(FilterExpress express, Object value) { + if (value == null) return null; + if (value instanceof Number) return String.valueOf(value); + if (value instanceof CharSequence) { + if (express == LIKE || express == NOTLIKE) { + value = "%" + value + '%'; + } else if (express == STARTSWITH || express == NOTSTARTSWITH) { + value = value + "%"; + } else if (express == ENDSWITH || express == NOTENDSWITH) { + value = "%" + value; + } else if (express == IGNORECASELIKE || express == IGNORECASENOTLIKE) { + value = "%" + value.toString().toLowerCase() + '%'; + } else if (express == IGNORECASECONTAIN || express == IGNORECASENOTCONTAIN + || express == IGNORECASEEQUAL || express == IGNORECASENOTEQUAL) { + value = value.toString().toLowerCase(); + } + return new StringBuilder().append('\'').append(value.toString().replace("'", "\\'")).append('\''); + } else if (value instanceof Range) { + Range range = (Range) value; + boolean rangestring = range.getClass() == Range.StringRange.class; + StringBuilder sb = new StringBuilder(); + if (rangestring) { + sb.append('\'').append(range.getMin().toString().replace("'", "\\'")).append('\''); + } else { + sb.append(range.getMin()); + } + sb.append(" AND "); + if (rangestring) { + sb.append('\'').append(range.getMax().toString().replace("'", "\\'")).append('\''); + } else { + sb.append(range.getMax()); + } + return sb; + } else if (value.getClass().isArray()) { + int len = Array.getLength(value); + if (len == 0) return express == NOTIN ? null : new StringBuilder("(NULL)"); + if (len == 1) { + Object firstval = Array.get(value, 0); + if (firstval != null && firstval.getClass().isArray()) return formatToString(express, firstval); + } + StringBuilder sb = new StringBuilder(); + sb.append('('); + for (int i = 0; i < len; i++) { + Object o = Array.get(value, i); + if (sb.length() > 1) sb.append(','); + if (o instanceof CharSequence) { + sb.append('\'').append(o.toString().replace("'", "\\'")).append('\''); + } else { + sb.append(o); + } + } + return sb.append(')'); + } else if (value instanceof Collection) { + Collection c = (Collection) value; + if (c.isEmpty()) return express == NOTIN ? null : new StringBuilder("(NULL)"); + StringBuilder sb = new StringBuilder(); + sb.append('('); + for (Object o : c) { + if (sb.length() > 1) sb.append(','); + if (o instanceof CharSequence) { + sb.append('\'').append(o.toString().replace("'", "\\'")).append('\''); + } else { + sb.append(o); + } + } + return sb.append(')'); + } + return String.valueOf(value); + } + + public final Serializable getValue() { + return value; + } + + public final void setValue(Serializable value) { + this.value = value; + } + + public boolean isReadOnly() { + return readOnly; + } + + public void setReadOnly(boolean readOnly) { + this.readOnly = readOnly; + } + + public final boolean isOr() { + return or; + } + + public final void setOr(boolean or) { + this.or = or; + } + + public final String getColumn() { + return column; + } + + public final void setColumn(String column) { + this.column = column; + } + + public final FilterExpress getExpress() { + return express; + } + + public final void setExpress(FilterExpress express) { + this.express = express; + } + + public final boolean isItemand() { + return itemand; + } + + public final void setItemand(boolean itemand) { + this.itemand = itemand; + } + + public final FilterNode[] getNodes() { + return nodes; + } + + public final void setNodes(FilterNode[] nodes) { + this.nodes = nodes; + } + +} diff --git a/src/main/java/org/redkale/source/FilterNodeBean.java b/src/main/java/org/redkale/source/FilterNodeBean.java index d4ed4b6a1..f6c8a3007 100644 --- a/src/main/java/org/redkale/source/FilterNodeBean.java +++ b/src/main/java/org/redkale/source/FilterNodeBean.java @@ -1,384 +1,384 @@ -/* - * 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.source; - -import java.io.Serializable; -import java.lang.reflect.*; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import javax.persistence.Transient; -import static org.redkale.source.FilterExpress.*; -import org.redkale.util.*; - -/** - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param FilterBean娉涘瀷 - */ -public final class FilterNodeBean implements Comparable> { - - private static final ConcurrentHashMap beanodes = new ConcurrentHashMap<>(); - - private Attribute beanAttr; - - private String column; - - private FilterExpress express; - - private boolean itemand; - - private boolean or; - - private FilterNodeBean[] nodeBeans; - - //-----------------join table-------------------------- - private Class joinClass; - - private String[] joinColumns; - - //---------------------------------------------------- - private long least; - - private boolean string; - - private boolean number; - - public FilterNodeBean(FilterNodeBean bean) { - this.beanAttr = bean == null ? null : bean.beanAttr; - this.column = bean == null ? null : bean.column; - this.express = bean == null ? null : bean.express; - this.itemand = bean == null ? true : bean.itemand; - this.joinClass = bean == null ? null : bean.joinClass; - this.joinColumns = bean == null ? null : bean.joinColumns; - this.least = bean == null ? 1 : bean.least; - this.string = bean == null ? false : bean.string; - this.number = bean == null ? false : bean.number; - this.or = bean == null ? false : bean.or; - this.nodeBeans = bean == null ? null : bean.nodeBeans; - } - - private FilterNodeBean(final FilterJoinColumn joinCol, final FilterColumn filterCol, final Attribute attr, final Type genericType) { - this.beanAttr = attr; - this.joinClass = joinCol == null ? null : joinCol.table(); - this.joinColumns = joinCol == null ? null : joinCol.columns(); - - final Class type = attr.type(); - this.column = (filterCol != null && !filterCol.name().isEmpty()) ? filterCol.name() : attr.field(); - - FilterExpress exp = filterCol == null ? null : filterCol.express(); - Class compType = type.getComponentType(); - if (Collection.class.isAssignableFrom(type) && genericType instanceof ParameterizedType) { - Type pt = ((ParameterizedType) genericType).getActualTypeArguments()[0]; - if (pt instanceof Class) compType = (Class) pt; - } - if ((exp == null || exp == EQUAL) && (type.isArray() || Collection.class.isAssignableFrom(type))) { - if (compType != null && Range.class.isAssignableFrom(compType)) { - if (AND != exp) exp = OR; - } else if (NOTIN != exp) { - exp = IN; - } - } else if (Range.class.isAssignableFrom(type)) { - if (NOTBETWEEN != exp) exp = BETWEEN; - } - if (exp == null) exp = EQUAL; - this.express = exp; - - this.least = filterCol == null ? 1 : filterCol.least(); - this.number = (type.isPrimitive() && type != boolean.class) || Number.class.isAssignableFrom(type); - this.string = CharSequence.class.isAssignableFrom(type); - } - - private FilterNodeBean or(FilterNodeBean node) { - return any(node, true); - } - - private FilterNodeBean and(FilterNodeBean node) { - return any(node, false); - } - - private FilterNodeBean any(FilterNodeBean node, boolean signor) { - Objects.requireNonNull(node); - if (this.column == null) { - this.beanAttr = node.beanAttr; - this.column = node.column; - this.express = node.express; - this.itemand = node.itemand; - this.joinClass = node.joinClass; - this.joinColumns = node.joinColumns; - this.least = node.least; - this.string = node.string; - this.number = node.number; - return this; - } - if (this.nodeBeans == null) { - this.nodeBeans = new FilterNodeBean[]{node}; - this.or = signor; - return this; - } - if (or == signor) { - this.nodeBeans = Utility.append(this.nodeBeans, node); - return this; - } - this.nodeBeans = new FilterNodeBean[]{new FilterNodeBean(this), node}; - this.column = null; - this.or = signor; - return this; - } - - public static FilterNode createFilterNode(final FilterBean bean) { - if (bean == null) return null; - return load(bean.getClass()).create(bean); - } - - public static FilterNodeBean load(Class clazz) { - FilterNodeBean rs = beanodes.get(clazz); - if (rs != null) return rs; - synchronized (beanodes) { - rs = beanodes.get(clazz); - if (rs == null) { - rs = createFilterNodeBean(clazz); - beanodes.put(clazz, rs); - } - return rs; - } - } - - private FilterNode create(final T bean) { - if (bean == null || beanAttr == null) return null; - FilterNode node = null; - final Serializable val = beanAttr.get(bean); - if (column != null && val != null) { - boolean skip = false; - if (string && ((CharSequence) val).length() == 0) { //绌哄瓧绗︿覆涓嶉渶瑕佽繘琛岃繃婊 - skip = true; - } else if (number && ((Number) val).longValue() < least) { //鏁板煎皬浜庤繃婊や笅鍊奸檺鍒欎笉闇瑕佽繃婊 - skip = true; - } - if (!skip) { - if (this.joinClass == null) { - node = FilterNode.create(column, express, itemand, val); - } else { - node = FilterJoinNode.create(joinClass, joinColumns, column, express, itemand, val); - } - } - } - if (this.nodeBeans == null) return node; - for (final FilterNodeBean fnb : this.nodeBeans) { - FilterNode n = fnb.create(bean); - if (n == null) continue; - node = node == null ? n : ((!(n instanceof FilterJoinNode)) ? n.any(node, or) : node.any(n, or)); - } - return node; - } - - private static FilterNodeBean createFilterNodeBean(final Class clazz) { - final Set fields = new HashSet<>(); - final Map nodemap = new LinkedHashMap(); - Class cltmp = clazz; - do { - for (final Field field : cltmp.getDeclaredFields()) { - if (Modifier.isStatic(field.getModifiers())) continue; - if (fields.contains(field.getName())) continue; - if (field.getAnnotation(Transient.class) != null) continue; - if (field.getAnnotation(FilterColumn.class) != null && field.getAnnotation(FilterColumn.class).ignore()) continue; - - final boolean pubmod = Modifier.isPublic(field.getModifiers()); - - char[] chars = field.getName().toCharArray(); - chars[0] = Character.toUpperCase(chars[0]); - final Class t = field.getType(); - Method getter = null; - try { - getter = cltmp.getMethod(((t == boolean.class || t == Boolean.class) ? "is" : "get") + new String(chars)); - } catch (NoSuchMethodException ex) { - try { - getter = cltmp.getMethod(field.getName()); - } catch (NoSuchMethodException ex2) { - if (t == Boolean.class) { - try { - getter = cltmp.getMethod("get" + new String(chars)); - } catch (Exception ex3) { - if (!pubmod) continue; - } - } else if (!pubmod) { - continue; - } - } - } - fields.add(field.getName()); - - final Attribute beanAttr = pubmod ? Attribute.create(field) : Attribute.create(getter, null); - FilterNodeBean nodeBean = new FilterNodeBean(field.getAnnotation(FilterJoinColumn.class), field.getAnnotation(FilterColumn.class), beanAttr, field.getGenericType()); - - //------------------------------------ - { - FilterGroup[] refs = field.getAnnotationsByType(FilterGroup.class); - String[] groups = new String[refs.length]; - for (int i = 0; i < refs.length; i++) { - groups[i] = refs[i].value(); - } - if (groups.length == 0) groups = new String[]{"[AND]"}; - for (String key : groups) { - if (!key.startsWith("[AND]") && !key.startsWith("[OR]")) { - throw new RuntimeException(field + "'s FilterGroup.value(" + key + ") illegal, must be [AND] or [OR] startsWith"); - } - FilterNodeBean node = nodemap.get(key); - if (node == null) { - nodemap.put(key, nodeBean); - } else if (nodeBean.joinClass == null && node.joinClass != null) { //闈瀓oinNode 鍏宠仈 joinNode - nodemap.put(key, nodeBean.any(node, key.substring(key.lastIndexOf('.') + 1).contains("[OR]"))); - } else { - node.any(nodeBean, key.substring(key.lastIndexOf('.') + 1).contains("[OR]")); - } - } - } - } - } while ((cltmp = cltmp.getSuperclass()) != Object.class); - final Map linkes = new LinkedHashMap<>(); - nodemap.forEach((k, v) -> { - String[] keys = k.split("\\."); - LinkNode link = linkes.get(keys[0]); - if (link == null) { - linkes.put(keys[0], new LinkNode(k, v)); - } else { - link.put(keys, 0, v); - } - }); - FilterNodeBean rs = null; - for (LinkNode link : linkes.values()) { - FilterNodeBean f = link.createFilterNodeBean(); - if (f == null) continue; - rs = rs == null ? f : rs.and(f); - } - if (rs != null && rs.nodeBeans != null) Arrays.sort(rs.nodeBeans); - return rs == null ? new FilterNodeBean(null) : rs; - } - - @Override - public int compareTo(FilterNodeBean o) { - if (this.joinClass == null && o.joinClass == null) return 0; - if (this.joinClass != null && o.joinClass != null) return 0; - return this.joinClass == null ? -1 : 1; - } - - private static class LinkNode { - - public final boolean or; - - public final String key; - - public final List beans = new ArrayList<>(); - - public final Map nexts = new LinkedHashMap<>(); - - public LinkNode(String keyString, FilterNodeBean node) { - String[] keys = keyString.split("\\."); - this.key = keys[0]; - this.or = this.key.contains("[OR]"); - put(keys, 0, node); - } - - public LinkNode(String[] keyStrings, int pos, FilterNodeBean node) { - this.key = keyStrings[pos]; - this.or = this.key.contains("[OR]"); - put(keyStrings, pos, node); - } - - public FilterNodeBean createFilterNodeBean() { - FilterNodeBean node = null; - for (FilterNodeBean bean : beans) { - node = node == null ? bean : node.any(bean, or); - } - for (LinkNode link : nexts.values()) { - FilterNodeBean f = link.createFilterNodeBean(); - if (f == null) continue; - node = node == null ? f : node.any(f, or); - } - return node; - } - - public final void put(final String[] keys, int pos, final FilterNodeBean node) { - if (keys.length == pos + 1 && this.key.equals(keys[pos])) { - this.beans.add(node); - return; - } - LinkNode link = nexts.get(keys[pos + 1]); - if (link == null) { - nexts.put(keys[pos + 1], new LinkNode(keys, pos + 1, node)); - } else { - link.put(keys, pos + 1, node); - } - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("{key = '").append(key).append("', or = ").append(or); - if (!beans.isEmpty()) { - sb.append(", beans = [\r\n"); - for (FilterNodeBean bean : this.beans) { - sb.append(" ").append(bean).append("\r\n"); - } - sb.append("]"); - } - if (!nexts.isEmpty()) { - sb.append(", nexts = [\r\n"); - for (LinkNode link : this.nexts.values()) { - sb.append(" ").append(link).append("\r\n"); - } - sb.append("]"); - } - sb.append("}"); - return sb.toString(); - } - } - - @Override - public String toString() { - return toString(joinClass == null ? null : joinClass.getSimpleName()).toString(); - } - - protected StringBuilder toString(final String prefix) { - StringBuilder sb = new StringBuilder(); - StringBuilder element = toElementString(prefix); - boolean more = element.length() > 0 && this.nodeBeans != null; - if (more) sb.append('('); - sb.append(element); - if (this.nodeBeans != null) { - for (FilterNodeBean node : this.nodeBeans) { - String s = node.toString(); - if (s.length() < 1) continue; - if (sb.length() > 1) sb.append(or ? " OR " : " AND "); - sb.append(s); - } - } - if (more) sb.append(')'); - return sb; - } - - protected final StringBuilder toElementString(final String prefix) { - StringBuilder sb = new StringBuilder(); - if (column != null) { - String col = prefix == null ? column : (prefix + "." + column); - if (express == ISNULL || express == ISNOTNULL) { - sb.append(col).append(' ').append(express.value()); - } else if (express == ISEMPTY || express == ISNOTEMPTY) { - sb.append(col).append(' ').append(express.value()).append(" ''"); - } else if (express == LENGTH_EQUAL || express == LENGTH_LESSTHAN || express == LENGTH_LESSTHANOREQUALTO - || express == LENGTH_GREATERTHAN || express == LENGTH_GREATERTHANOREQUALTO) { - sb.append("LENGTH(").append(col).append(") ").append(express.value()).append(" ?"); - } else { - boolean lower = (express == IGNORECASEEQUAL || express == IGNORECASENOTEQUAL || express == IGNORECASELIKE - || express == IGNORECASENOTLIKE || express == IGNORECASECONTAIN || express == IGNORECASENOTCONTAIN); - sb.append(lower ? ("LOWER(" + col + ')') : col).append(' ').append(express.value()).append(" ?"); - } - } - return sb; - } -} +/* + * 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.source; + +import java.io.Serializable; +import java.lang.reflect.*; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import javax.persistence.Transient; +import static org.redkale.source.FilterExpress.*; +import org.redkale.util.*; + +/** + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param FilterBean娉涘瀷 + */ +public final class FilterNodeBean implements Comparable> { + + private static final ConcurrentHashMap beanodes = new ConcurrentHashMap<>(); + + private Attribute beanAttr; + + private String column; + + private FilterExpress express; + + private boolean itemand; + + private boolean or; + + private FilterNodeBean[] nodeBeans; + + //-----------------join table-------------------------- + private Class joinClass; + + private String[] joinColumns; + + //---------------------------------------------------- + private long least; + + private boolean string; + + private boolean number; + + public FilterNodeBean(FilterNodeBean bean) { + this.beanAttr = bean == null ? null : bean.beanAttr; + this.column = bean == null ? null : bean.column; + this.express = bean == null ? null : bean.express; + this.itemand = bean == null ? true : bean.itemand; + this.joinClass = bean == null ? null : bean.joinClass; + this.joinColumns = bean == null ? null : bean.joinColumns; + this.least = bean == null ? 1 : bean.least; + this.string = bean == null ? false : bean.string; + this.number = bean == null ? false : bean.number; + this.or = bean == null ? false : bean.or; + this.nodeBeans = bean == null ? null : bean.nodeBeans; + } + + private FilterNodeBean(final FilterJoinColumn joinCol, final FilterColumn filterCol, final Attribute attr, final Type genericType) { + this.beanAttr = attr; + this.joinClass = joinCol == null ? null : joinCol.table(); + this.joinColumns = joinCol == null ? null : joinCol.columns(); + + final Class type = attr.type(); + this.column = (filterCol != null && !filterCol.name().isEmpty()) ? filterCol.name() : attr.field(); + + FilterExpress exp = filterCol == null ? null : filterCol.express(); + Class compType = type.getComponentType(); + if (Collection.class.isAssignableFrom(type) && genericType instanceof ParameterizedType) { + Type pt = ((ParameterizedType) genericType).getActualTypeArguments()[0]; + if (pt instanceof Class) compType = (Class) pt; + } + if ((exp == null || exp == EQUAL) && (type.isArray() || Collection.class.isAssignableFrom(type))) { + if (compType != null && Range.class.isAssignableFrom(compType)) { + if (AND != exp) exp = OR; + } else if (NOTIN != exp) { + exp = IN; + } + } else if (Range.class.isAssignableFrom(type)) { + if (NOTBETWEEN != exp) exp = BETWEEN; + } + if (exp == null) exp = EQUAL; + this.express = exp; + + this.least = filterCol == null ? 1 : filterCol.least(); + this.number = (type.isPrimitive() && type != boolean.class) || Number.class.isAssignableFrom(type); + this.string = CharSequence.class.isAssignableFrom(type); + } + + private FilterNodeBean or(FilterNodeBean node) { + return any(node, true); + } + + private FilterNodeBean and(FilterNodeBean node) { + return any(node, false); + } + + private FilterNodeBean any(FilterNodeBean node, boolean signor) { + Objects.requireNonNull(node); + if (this.column == null) { + this.beanAttr = node.beanAttr; + this.column = node.column; + this.express = node.express; + this.itemand = node.itemand; + this.joinClass = node.joinClass; + this.joinColumns = node.joinColumns; + this.least = node.least; + this.string = node.string; + this.number = node.number; + return this; + } + if (this.nodeBeans == null) { + this.nodeBeans = new FilterNodeBean[]{node}; + this.or = signor; + return this; + } + if (or == signor) { + this.nodeBeans = Utility.append(this.nodeBeans, node); + return this; + } + this.nodeBeans = new FilterNodeBean[]{new FilterNodeBean(this), node}; + this.column = null; + this.or = signor; + return this; + } + + public static FilterNode createFilterNode(final FilterBean bean) { + if (bean == null) return null; + return load(bean.getClass()).create(bean); + } + + public static FilterNodeBean load(Class clazz) { + FilterNodeBean rs = beanodes.get(clazz); + if (rs != null) return rs; + synchronized (beanodes) { + rs = beanodes.get(clazz); + if (rs == null) { + rs = createFilterNodeBean(clazz); + beanodes.put(clazz, rs); + } + return rs; + } + } + + private FilterNode create(final T bean) { + if (bean == null || beanAttr == null) return null; + FilterNode node = null; + final Serializable val = beanAttr.get(bean); + if (column != null && val != null) { + boolean skip = false; + if (string && ((CharSequence) val).length() == 0) { //绌哄瓧绗︿覆涓嶉渶瑕佽繘琛岃繃婊 + skip = true; + } else if (number && ((Number) val).longValue() < least) { //鏁板煎皬浜庤繃婊や笅鍊奸檺鍒欎笉闇瑕佽繃婊 + skip = true; + } + if (!skip) { + if (this.joinClass == null) { + node = FilterNode.create(column, express, itemand, val); + } else { + node = FilterJoinNode.create(joinClass, joinColumns, column, express, itemand, val); + } + } + } + if (this.nodeBeans == null) return node; + for (final FilterNodeBean fnb : this.nodeBeans) { + FilterNode n = fnb.create(bean); + if (n == null) continue; + node = node == null ? n : ((!(n instanceof FilterJoinNode)) ? n.any(node, or) : node.any(n, or)); + } + return node; + } + + private static FilterNodeBean createFilterNodeBean(final Class clazz) { + final Set fields = new HashSet<>(); + final Map nodemap = new LinkedHashMap(); + Class cltmp = clazz; + do { + for (final Field field : cltmp.getDeclaredFields()) { + if (Modifier.isStatic(field.getModifiers())) continue; + if (fields.contains(field.getName())) continue; + if (field.getAnnotation(Transient.class) != null) continue; + if (field.getAnnotation(FilterColumn.class) != null && field.getAnnotation(FilterColumn.class).ignore()) continue; + + final boolean pubmod = Modifier.isPublic(field.getModifiers()); + + char[] chars = field.getName().toCharArray(); + chars[0] = Character.toUpperCase(chars[0]); + final Class t = field.getType(); + Method getter = null; + try { + getter = cltmp.getMethod(((t == boolean.class || t == Boolean.class) ? "is" : "get") + new String(chars)); + } catch (NoSuchMethodException ex) { + try { + getter = cltmp.getMethod(field.getName()); + } catch (NoSuchMethodException ex2) { + if (t == Boolean.class) { + try { + getter = cltmp.getMethod("get" + new String(chars)); + } catch (Exception ex3) { + if (!pubmod) continue; + } + } else if (!pubmod) { + continue; + } + } + } + fields.add(field.getName()); + + final Attribute beanAttr = pubmod ? Attribute.create(field) : Attribute.create(getter, null); + FilterNodeBean nodeBean = new FilterNodeBean(field.getAnnotation(FilterJoinColumn.class), field.getAnnotation(FilterColumn.class), beanAttr, field.getGenericType()); + + //------------------------------------ + { + FilterGroup[] refs = field.getAnnotationsByType(FilterGroup.class); + String[] groups = new String[refs.length]; + for (int i = 0; i < refs.length; i++) { + groups[i] = refs[i].value(); + } + if (groups.length == 0) groups = new String[]{"[AND]"}; + for (String key : groups) { + if (!key.startsWith("[AND]") && !key.startsWith("[OR]")) { + throw new RuntimeException(field + "'s FilterGroup.value(" + key + ") illegal, must be [AND] or [OR] startsWith"); + } + FilterNodeBean node = nodemap.get(key); + if (node == null) { + nodemap.put(key, nodeBean); + } else if (nodeBean.joinClass == null && node.joinClass != null) { //闈瀓oinNode 鍏宠仈 joinNode + nodemap.put(key, nodeBean.any(node, key.substring(key.lastIndexOf('.') + 1).contains("[OR]"))); + } else { + node.any(nodeBean, key.substring(key.lastIndexOf('.') + 1).contains("[OR]")); + } + } + } + } + } while ((cltmp = cltmp.getSuperclass()) != Object.class); + final Map linkes = new LinkedHashMap<>(); + nodemap.forEach((k, v) -> { + String[] keys = k.split("\\."); + LinkNode link = linkes.get(keys[0]); + if (link == null) { + linkes.put(keys[0], new LinkNode(k, v)); + } else { + link.put(keys, 0, v); + } + }); + FilterNodeBean rs = null; + for (LinkNode link : linkes.values()) { + FilterNodeBean f = link.createFilterNodeBean(); + if (f == null) continue; + rs = rs == null ? f : rs.and(f); + } + if (rs != null && rs.nodeBeans != null) Arrays.sort(rs.nodeBeans); + return rs == null ? new FilterNodeBean(null) : rs; + } + + @Override + public int compareTo(FilterNodeBean o) { + if (this.joinClass == null && o.joinClass == null) return 0; + if (this.joinClass != null && o.joinClass != null) return 0; + return this.joinClass == null ? -1 : 1; + } + + private static class LinkNode { + + public final boolean or; + + public final String key; + + public final List beans = new ArrayList<>(); + + public final Map nexts = new LinkedHashMap<>(); + + public LinkNode(String keyString, FilterNodeBean node) { + String[] keys = keyString.split("\\."); + this.key = keys[0]; + this.or = this.key.contains("[OR]"); + put(keys, 0, node); + } + + public LinkNode(String[] keyStrings, int pos, FilterNodeBean node) { + this.key = keyStrings[pos]; + this.or = this.key.contains("[OR]"); + put(keyStrings, pos, node); + } + + public FilterNodeBean createFilterNodeBean() { + FilterNodeBean node = null; + for (FilterNodeBean bean : beans) { + node = node == null ? bean : node.any(bean, or); + } + for (LinkNode link : nexts.values()) { + FilterNodeBean f = link.createFilterNodeBean(); + if (f == null) continue; + node = node == null ? f : node.any(f, or); + } + return node; + } + + public final void put(final String[] keys, int pos, final FilterNodeBean node) { + if (keys.length == pos + 1 && this.key.equals(keys[pos])) { + this.beans.add(node); + return; + } + LinkNode link = nexts.get(keys[pos + 1]); + if (link == null) { + nexts.put(keys[pos + 1], new LinkNode(keys, pos + 1, node)); + } else { + link.put(keys, pos + 1, node); + } + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("{key = '").append(key).append("', or = ").append(or); + if (!beans.isEmpty()) { + sb.append(", beans = [\r\n"); + for (FilterNodeBean bean : this.beans) { + sb.append(" ").append(bean).append("\r\n"); + } + sb.append("]"); + } + if (!nexts.isEmpty()) { + sb.append(", nexts = [\r\n"); + for (LinkNode link : this.nexts.values()) { + sb.append(" ").append(link).append("\r\n"); + } + sb.append("]"); + } + sb.append("}"); + return sb.toString(); + } + } + + @Override + public String toString() { + return toString(joinClass == null ? null : joinClass.getSimpleName()).toString(); + } + + protected StringBuilder toString(final String prefix) { + StringBuilder sb = new StringBuilder(); + StringBuilder element = toElementString(prefix); + boolean more = element.length() > 0 && this.nodeBeans != null; + if (more) sb.append('('); + sb.append(element); + if (this.nodeBeans != null) { + for (FilterNodeBean node : this.nodeBeans) { + String s = node.toString(); + if (s.length() < 1) continue; + if (sb.length() > 1) sb.append(or ? " OR " : " AND "); + sb.append(s); + } + } + if (more) sb.append(')'); + return sb; + } + + protected final StringBuilder toElementString(final String prefix) { + StringBuilder sb = new StringBuilder(); + if (column != null) { + String col = prefix == null ? column : (prefix + "." + column); + if (express == ISNULL || express == ISNOTNULL) { + sb.append(col).append(' ').append(express.value()); + } else if (express == ISEMPTY || express == ISNOTEMPTY) { + sb.append(col).append(' ').append(express.value()).append(" ''"); + } else if (express == LENGTH_EQUAL || express == LENGTH_LESSTHAN || express == LENGTH_LESSTHANOREQUALTO + || express == LENGTH_GREATERTHAN || express == LENGTH_GREATERTHANOREQUALTO) { + sb.append("LENGTH(").append(col).append(") ").append(express.value()).append(" ?"); + } else { + boolean lower = (express == IGNORECASEEQUAL || express == IGNORECASENOTEQUAL || express == IGNORECASELIKE + || express == IGNORECASENOTLIKE || express == IGNORECASECONTAIN || express == IGNORECASENOTCONTAIN); + sb.append(lower ? ("LOWER(" + col + ')') : col).append(' ').append(express.value()).append(" ?"); + } + } + return sb; + } +} diff --git a/src/main/java/org/redkale/source/FilterValue.java b/src/main/java/org/redkale/source/FilterValue.java index d19515863..5b62bd33b 100644 --- a/src/main/java/org/redkale/source/FilterValue.java +++ b/src/main/java/org/redkale/source/FilterValue.java @@ -1,70 +1,70 @@ -/* - * 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.source; - -/** - * FilterValue涓昏鐢ㄤ簬澶嶆潅鐨勮〃杈惧紡銆
- * 渚嬪: col / 10 = 3 銆丮OD(col, 8) > 0 杩欎簺閮戒笉鏄崟鐙竴涓暟鍊艰兘琛ㄨ揪鐨勶紝鍥犳闇瑕丗ilterValue 鎵嶆瀯寤 8 銆 > 銆0 缁勫悎鍊笺 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public class FilterValue implements java.io.Serializable { - - private Number optvalue; - - private FilterExpress express; - - private Number destvalue; - - public FilterValue() { - } - - public FilterValue(Number optvalue, Number destvalue) { - this(optvalue, FilterExpress.EQUAL, destvalue); - } - - public FilterValue(Number optvalue, FilterExpress express) { - this(optvalue, express, 0); - } - - public FilterValue(Number optvalue, FilterExpress express, Number destvalue) { - this.optvalue = optvalue; - this.express = express; - this.destvalue = destvalue; - } - - public Number getOptvalue() { - return optvalue == null ? 0 : optvalue; - } - - public void setOptvalue(Number optvalue) { - this.optvalue = optvalue; - } - - public FilterExpress getExpress() { - return express == null ? FilterExpress.EQUAL : express; - } - - public void setExpress(FilterExpress express) { - this.express = express; - } - - public Number getDestvalue() { - return destvalue == null ? 0 : destvalue; - } - - public void setDestvalue(Number destvalue) { - this.destvalue = destvalue; - } - - @Override - public String toString() { - return FilterValue.class.getSimpleName() + "[optvalue=" + getOptvalue() + ", express=" + getExpress() + ", destvalue=" + getDestvalue() + "]"; - } -} +/* + * 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.source; + +/** + * FilterValue涓昏鐢ㄤ簬澶嶆潅鐨勮〃杈惧紡銆
+ * 渚嬪: col / 10 = 3 銆丮OD(col, 8) > 0 杩欎簺閮戒笉鏄崟鐙竴涓暟鍊艰兘琛ㄨ揪鐨勶紝鍥犳闇瑕丗ilterValue 鎵嶆瀯寤 8 銆 > 銆0 缁勫悎鍊笺 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public class FilterValue implements java.io.Serializable { + + private Number optvalue; + + private FilterExpress express; + + private Number destvalue; + + public FilterValue() { + } + + public FilterValue(Number optvalue, Number destvalue) { + this(optvalue, FilterExpress.EQUAL, destvalue); + } + + public FilterValue(Number optvalue, FilterExpress express) { + this(optvalue, express, 0); + } + + public FilterValue(Number optvalue, FilterExpress express, Number destvalue) { + this.optvalue = optvalue; + this.express = express; + this.destvalue = destvalue; + } + + public Number getOptvalue() { + return optvalue == null ? 0 : optvalue; + } + + public void setOptvalue(Number optvalue) { + this.optvalue = optvalue; + } + + public FilterExpress getExpress() { + return express == null ? FilterExpress.EQUAL : express; + } + + public void setExpress(FilterExpress express) { + this.express = express; + } + + public Number getDestvalue() { + return destvalue == null ? 0 : destvalue; + } + + public void setDestvalue(Number destvalue) { + this.destvalue = destvalue; + } + + @Override + public String toString() { + return FilterValue.class.getSimpleName() + "[optvalue=" + getOptvalue() + ", express=" + getExpress() + ", destvalue=" + getDestvalue() + "]"; + } +} diff --git a/src/main/java/org/redkale/source/Flipper.java b/src/main/java/org/redkale/source/Flipper.java index 563b1e36f..cb72a5b03 100644 --- a/src/main/java/org/redkale/source/Flipper.java +++ b/src/main/java/org/redkale/source/Flipper.java @@ -1,177 +1,177 @@ -/* - * 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.source; - -import java.io.Serializable; -import java.util.Objects; -import org.redkale.convert.ConvertColumn; -import org.redkale.util.Comment; - -/** - * 缈婚〉瀵硅薄, offset浠0寮濮, limit蹇呴』澶т簬0 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public final class Flipper implements Serializable, Cloneable { - - public static int DEFAULT_LIMIT = 20; - - @ConvertColumn(index = 1) - @Comment("璁板綍琛岀殑鍋忕Щ閲忥紝浠0寮濮") - private int offset = 0; - - @ConvertColumn(index = 2) - @Comment("姣忛〉澶氬皯琛") - private int limit = DEFAULT_LIMIT; - - @ConvertColumn(index = 3) - @Comment("鎺掑簭瀛楁, 鍙瀛楁鎺掑簭") - private String sort = ""; - - public Flipper() { - } - - public Flipper(int limit) { - this.limit = limit > 0 ? limit : 0; - } - - public Flipper(String sortColumn) { - this.sort = sortColumn; - } - - public Flipper(int limit, int offset) { - this.limit = limit > 0 ? limit : 0; - this.offset = offset < 0 ? 0 : offset; - } - - public Flipper(int limit, String sortColumn) { - this.limit = limit > 0 ? limit : 0; - this.sort = sortColumn; - } - - public Flipper(int limit, int offset, String sortColumn) { - this.limit = limit > 0 ? limit : 0; - this.offset = offset < 0 ? 0 : offset; - this.sort = sortColumn; - } - - public Flipper copyTo(Flipper copy) { - if (copy == null) return copy; - copy.offset = this.offset; - copy.limit = this.limit; - copy.sort = this.sort; - return copy; - } - - public Flipper copyFrom(Flipper copy) { - if (copy == null) return this; - this.offset = copy.offset; - this.limit = copy.limit; - this.sort = copy.sort; - return this; - } - - public Flipper next() { - this.offset = getOffset() + this.limit; - return this; - } - - @Override - @SuppressWarnings("CloneDoesntCallSuperClone") - public Flipper clone() { - return this.copyTo(new Flipper()); - } - - @Override - public String toString() { - return this.getClass().getSimpleName() + "{offset:" + this.offset + ", limit:" + this.limit + ", sort:" + this.sort + "}"; - } - - @Override - public int hashCode() { - int hash = 5; - hash = 37 * hash + this.offset; - hash = 37 * hash + this.limit; - hash = 37 * hash + Objects.hashCode(this.sort); - return hash; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; - final Flipper other = (Flipper) obj; - if (this.offset != other.offset) return false; - if (this.limit != other.limit) return false; - return Objects.equals(this.sort, other.sort); - } - - public int getLimit() { - return limit; - } - - public void setLimit(int limit) { - this.limit = limit; - } - - public Flipper limit(int limit) { - setLimit(limit); - return this; - } - - public Flipper maxLimit(int maxlimit) { - setLimit(Math.max(1, Math.min(maxlimit, limit))); - return this; - } - - public Flipper unlimit() { - this.limit = 0; - return this; - } - - public int getOffset() { - return offset; - } - - public void setOffset(int offset) { - this.offset = offset < 0 ? 0 : offset; - } - - public Flipper offset(int offset) { - setOffset(offset); - return this; - } - - public String getSort() { - return sort; - } - - public void setSort(String sort) { - this.sort = sort == null ? "" : sort.trim(); - } - - public Flipper sort(String sort) { - setSort(sort); - return this; - } - - public static Flipper sortIfAbsent(Flipper flipper, String sort) { - if (flipper != null) return flipper.sortIfAbsent(sort); - return flipper; - } - - public Flipper sortIfAbsent(String sort) { - if (this.sort == null || this.sort.isEmpty()) { - this.sort = sort; - } - return this; - } - -} +/* + * 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.source; + +import java.io.Serializable; +import java.util.Objects; +import org.redkale.convert.ConvertColumn; +import org.redkale.util.Comment; + +/** + * 缈婚〉瀵硅薄, offset浠0寮濮, limit蹇呴』澶т簬0 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public final class Flipper implements Serializable, Cloneable { + + public static int DEFAULT_LIMIT = 20; + + @ConvertColumn(index = 1) + @Comment("璁板綍琛岀殑鍋忕Щ閲忥紝浠0寮濮") + private int offset = 0; + + @ConvertColumn(index = 2) + @Comment("姣忛〉澶氬皯琛") + private int limit = DEFAULT_LIMIT; + + @ConvertColumn(index = 3) + @Comment("鎺掑簭瀛楁, 鍙瀛楁鎺掑簭") + private String sort = ""; + + public Flipper() { + } + + public Flipper(int limit) { + this.limit = limit > 0 ? limit : 0; + } + + public Flipper(String sortColumn) { + this.sort = sortColumn; + } + + public Flipper(int limit, int offset) { + this.limit = limit > 0 ? limit : 0; + this.offset = offset < 0 ? 0 : offset; + } + + public Flipper(int limit, String sortColumn) { + this.limit = limit > 0 ? limit : 0; + this.sort = sortColumn; + } + + public Flipper(int limit, int offset, String sortColumn) { + this.limit = limit > 0 ? limit : 0; + this.offset = offset < 0 ? 0 : offset; + this.sort = sortColumn; + } + + public Flipper copyTo(Flipper copy) { + if (copy == null) return copy; + copy.offset = this.offset; + copy.limit = this.limit; + copy.sort = this.sort; + return copy; + } + + public Flipper copyFrom(Flipper copy) { + if (copy == null) return this; + this.offset = copy.offset; + this.limit = copy.limit; + this.sort = copy.sort; + return this; + } + + public Flipper next() { + this.offset = getOffset() + this.limit; + return this; + } + + @Override + @SuppressWarnings("CloneDoesntCallSuperClone") + public Flipper clone() { + return this.copyTo(new Flipper()); + } + + @Override + public String toString() { + return this.getClass().getSimpleName() + "{offset:" + this.offset + ", limit:" + this.limit + ", sort:" + this.sort + "}"; + } + + @Override + public int hashCode() { + int hash = 5; + hash = 37 * hash + this.offset; + hash = 37 * hash + this.limit; + hash = 37 * hash + Objects.hashCode(this.sort); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + final Flipper other = (Flipper) obj; + if (this.offset != other.offset) return false; + if (this.limit != other.limit) return false; + return Objects.equals(this.sort, other.sort); + } + + public int getLimit() { + return limit; + } + + public void setLimit(int limit) { + this.limit = limit; + } + + public Flipper limit(int limit) { + setLimit(limit); + return this; + } + + public Flipper maxLimit(int maxlimit) { + setLimit(Math.max(1, Math.min(maxlimit, limit))); + return this; + } + + public Flipper unlimit() { + this.limit = 0; + return this; + } + + public int getOffset() { + return offset; + } + + public void setOffset(int offset) { + this.offset = offset < 0 ? 0 : offset; + } + + public Flipper offset(int offset) { + setOffset(offset); + return this; + } + + public String getSort() { + return sort; + } + + public void setSort(String sort) { + this.sort = sort == null ? "" : sort.trim(); + } + + public Flipper sort(String sort) { + setSort(sort); + return this; + } + + public static Flipper sortIfAbsent(Flipper flipper, String sort) { + if (flipper != null) return flipper.sortIfAbsent(sort); + return flipper; + } + + public Flipper sortIfAbsent(String sort) { + if (this.sort == null || this.sort.isEmpty()) { + this.sort = sort; + } + return this; + } + +} diff --git a/src/main/java/org/redkale/source/Range.java b/src/main/java/org/redkale/source/Range.java index 575f15709..69cb83278 100644 --- a/src/main/java/org/redkale/source/Range.java +++ b/src/main/java/org/redkale/source/Range.java @@ -1,387 +1,387 @@ -/* - * 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.source; - -import java.util.function.*; -import org.redkale.convert.ConvertColumn; -import org.redkale.util.Utility; - -/** - * - * 鍙栧艰寖鍥达紝鍖呭惈涓よ竟鐨勫 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Comparable鐨勫瓙绫诲瀷 - */ -public interface Range extends java.io.Serializable, Predicate { - - public E getMin(); - - public E getMax(); - - public static ByteRange create(byte min, byte max) { - return new ByteRange(min, max); - } - - public static ShortRange create(short min, short max) { - return new ShortRange(min, max); - } - - public static IntRange create(int min, int max) { - return new IntRange(min, max); - } - - public static LongRange create(long min, long max) { - return new LongRange(min, max); - } - - public static FloatRange create(float min, float max) { - return new FloatRange(min, max); - } - - public static DoubleRange create(double min, double max) { - return new DoubleRange(min, max); - } - - public static StringRange create(String min, String max) { - return new StringRange(min, max); - } - - public static final class ByteRange implements Range { - - @ConvertColumn(index = 1) - private Byte min = Byte.MIN_VALUE; - - @ConvertColumn(index = 2) - private Byte max = Byte.MAX_VALUE; - - public ByteRange() { - } - - public ByteRange(Byte min, Byte max) { - if (min != null) this.min = min; - if (max != null) this.max = max; - } - - @Override - public Byte getMin() { - return min; - } - - @Override - public Byte getMax() { - return max; - } - - public void setMin(Byte min) { - if (min != null) this.min = min; - } - - public void setMax(Byte max) { - if (max != null) this.max = max; - } - - @Override - public boolean test(Byte t) { - if (max < min && max <= 0) return t >= min; - return t >= min && t <= max; - } - - @Override - public String toString() { - return "{min:" + min + ", max:" + max + "}"; - } - - } - - public static final class ShortRange implements Range { - - @ConvertColumn(index = 1) - private Short min = Short.MIN_VALUE; - - @ConvertColumn(index = 2) - private Short max = Short.MAX_VALUE; - - public ShortRange() { - } - - public ShortRange(Short min, Short max) { - if (min != null) this.min = min; - if (max != null) this.max = max; - } - - @Override - public Short getMin() { - return min; - } - - @Override - public Short getMax() { - return max; - } - - public void setMin(Short min) { - if (min != null) this.min = min; - } - - public void setMax(Short max) { - if (max != null) this.max = max; - } - - @Override - public boolean test(Short t) { - if (max < min && max <= 0) return t >= min; - return t >= min && t <= max; - } - - @Override - public String toString() { - return "{min:" + min + ", max:" + max + "}"; - } - } - - public static final class IntRange implements Range { - - @ConvertColumn(index = 1) - private Integer min = Integer.MIN_VALUE; - - @ConvertColumn(index = 2) - private Integer max = Integer.MAX_VALUE; - - public IntRange() { - } - - public IntRange(Integer min, Integer max) { - if (min != null) this.min = min; - if (max != null) this.max = max; - } - - @Override - public Integer getMin() { - return min; - } - - @Override - public Integer getMax() { - return max; - } - - public void setMin(Integer min) { - if (min != null) this.min = min; - } - - public void setMax(Integer max) { - if (max != null) this.max = max; - } - - @Override - public boolean test(Integer t) { - if (max < min && max <= 0) return t >= min; - return t >= min && t <= max; - } - - @Override - public String toString() { - return "{min:" + min + ", max:" + max + "}"; - } - } - - public static final class LongRange implements Range { - - @ConvertColumn(index = 1) - private Long min = Long.MIN_VALUE; - - @ConvertColumn(index = 2) - private Long max = Long.MAX_VALUE; - - public LongRange() { - } - - public LongRange(Long min, Long max) { - if (min != null) this.min = min; - if (max != null) this.max = max; - } - - public static LongRange todayRange() { - long min = Utility.midnight(); - return new LongRange(min, min + 24 * 60 * 60 * 1000 - 1); - } - - public static LongRange yesterdayRange() { - long min = Utility.midnight(System.currentTimeMillis() - 24 * 60 * 60 * 1000); - return new LongRange(min, min + 24 * 60 * 60 * 1000 - 1); - } - - @Override - public Long getMin() { - return min; - } - - @Override - public Long getMax() { - return max; - } - - public void setMin(Long min) { - if (min != null) this.min = min; - } - - public void setMax(Long max) { - if (max != null) this.max = max; - } - - @Override - public boolean test(Long t) { - if (max < min && max <= 0) return t >= min; - return t >= min && t <= max; - } - - @Override - public String toString() { - return "{min:" + min + ", max:" + max + "}"; - } - } - - public static final class FloatRange implements Range { - - @ConvertColumn(index = 1) - private Float min = Float.MIN_VALUE; - - @ConvertColumn(index = 2) - private Float max = Float.MAX_VALUE; - - public FloatRange() { - } - - public FloatRange(Float min, Float max) { - if (min != null) this.min = min; - if (max != null) this.max = max; - } - - @Override - public Float getMin() { - return min; - } - - @Override - public Float getMax() { - return max; - } - - public void setMin(Float min) { - if (min != null) this.min = min; - } - - public void setMax(Float max) { - if (max != null) this.max = max; - } - - @Override - public boolean test(Float t) { - if (max < min && max <= 0) return t >= min; - return t >= min && t <= max; - } - - @Override - public String toString() { - return "{min:" + min + ", max:" + max + "}"; - } - } - - public static final class DoubleRange implements Range { - - @ConvertColumn(index = 1) - private Double min = Double.MIN_VALUE; - - @ConvertColumn(index = 2) - private Double max = Double.MAX_VALUE; - - public DoubleRange() { - } - - public DoubleRange(Double min, Double max) { - if (min != null) this.min = min; - if (max != null) this.max = max; - } - - @Override - public Double getMin() { - return min; - } - - @Override - public Double getMax() { - return max; - } - - public void setMin(Double min) { - if (min != null) this.min = min; - } - - public void setMax(Double max) { - if (max != null) this.max = max; - } - - @Override - public boolean test(Double t) { - if (max < min && max <= 0) return t >= min; - return t >= min && t <= max; - } - - @Override - public String toString() { - return "{min:" + min + ", max:" + max + "}"; - } - } - - public static final class StringRange implements Range { - - @ConvertColumn(index = 1) - private String min = ""; - - @ConvertColumn(index = 2) - private String max = ""; - - public StringRange() { - } - - public StringRange(String min, String max) { - this.min = min; - this.max = max; - } - - @Override - public String getMin() { - return min; - } - - @Override - public String getMax() { - return max; - } - - public void setMin(String min) { - if (min != null) this.min = min; - } - - public void setMax(String max) { - if (max != null) this.max = max; - } - - @Override - public boolean test(String t) { - return t.compareTo(min) >= 0 && t.compareTo(max) <= 0; - } - - @Override - public String toString() { - return "{min:'" + min + "', max:'" + max + "'}"; - } - } -} +/* + * 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.source; + +import java.util.function.*; +import org.redkale.convert.ConvertColumn; +import org.redkale.util.Utility; + +/** + * + * 鍙栧艰寖鍥达紝鍖呭惈涓よ竟鐨勫 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Comparable鐨勫瓙绫诲瀷 + */ +public interface Range extends java.io.Serializable, Predicate { + + public E getMin(); + + public E getMax(); + + public static ByteRange create(byte min, byte max) { + return new ByteRange(min, max); + } + + public static ShortRange create(short min, short max) { + return new ShortRange(min, max); + } + + public static IntRange create(int min, int max) { + return new IntRange(min, max); + } + + public static LongRange create(long min, long max) { + return new LongRange(min, max); + } + + public static FloatRange create(float min, float max) { + return new FloatRange(min, max); + } + + public static DoubleRange create(double min, double max) { + return new DoubleRange(min, max); + } + + public static StringRange create(String min, String max) { + return new StringRange(min, max); + } + + public static final class ByteRange implements Range { + + @ConvertColumn(index = 1) + private Byte min = Byte.MIN_VALUE; + + @ConvertColumn(index = 2) + private Byte max = Byte.MAX_VALUE; + + public ByteRange() { + } + + public ByteRange(Byte min, Byte max) { + if (min != null) this.min = min; + if (max != null) this.max = max; + } + + @Override + public Byte getMin() { + return min; + } + + @Override + public Byte getMax() { + return max; + } + + public void setMin(Byte min) { + if (min != null) this.min = min; + } + + public void setMax(Byte max) { + if (max != null) this.max = max; + } + + @Override + public boolean test(Byte t) { + if (max < min && max <= 0) return t >= min; + return t >= min && t <= max; + } + + @Override + public String toString() { + return "{min:" + min + ", max:" + max + "}"; + } + + } + + public static final class ShortRange implements Range { + + @ConvertColumn(index = 1) + private Short min = Short.MIN_VALUE; + + @ConvertColumn(index = 2) + private Short max = Short.MAX_VALUE; + + public ShortRange() { + } + + public ShortRange(Short min, Short max) { + if (min != null) this.min = min; + if (max != null) this.max = max; + } + + @Override + public Short getMin() { + return min; + } + + @Override + public Short getMax() { + return max; + } + + public void setMin(Short min) { + if (min != null) this.min = min; + } + + public void setMax(Short max) { + if (max != null) this.max = max; + } + + @Override + public boolean test(Short t) { + if (max < min && max <= 0) return t >= min; + return t >= min && t <= max; + } + + @Override + public String toString() { + return "{min:" + min + ", max:" + max + "}"; + } + } + + public static final class IntRange implements Range { + + @ConvertColumn(index = 1) + private Integer min = Integer.MIN_VALUE; + + @ConvertColumn(index = 2) + private Integer max = Integer.MAX_VALUE; + + public IntRange() { + } + + public IntRange(Integer min, Integer max) { + if (min != null) this.min = min; + if (max != null) this.max = max; + } + + @Override + public Integer getMin() { + return min; + } + + @Override + public Integer getMax() { + return max; + } + + public void setMin(Integer min) { + if (min != null) this.min = min; + } + + public void setMax(Integer max) { + if (max != null) this.max = max; + } + + @Override + public boolean test(Integer t) { + if (max < min && max <= 0) return t >= min; + return t >= min && t <= max; + } + + @Override + public String toString() { + return "{min:" + min + ", max:" + max + "}"; + } + } + + public static final class LongRange implements Range { + + @ConvertColumn(index = 1) + private Long min = Long.MIN_VALUE; + + @ConvertColumn(index = 2) + private Long max = Long.MAX_VALUE; + + public LongRange() { + } + + public LongRange(Long min, Long max) { + if (min != null) this.min = min; + if (max != null) this.max = max; + } + + public static LongRange todayRange() { + long min = Utility.midnight(); + return new LongRange(min, min + 24 * 60 * 60 * 1000 - 1); + } + + public static LongRange yesterdayRange() { + long min = Utility.midnight(System.currentTimeMillis() - 24 * 60 * 60 * 1000); + return new LongRange(min, min + 24 * 60 * 60 * 1000 - 1); + } + + @Override + public Long getMin() { + return min; + } + + @Override + public Long getMax() { + return max; + } + + public void setMin(Long min) { + if (min != null) this.min = min; + } + + public void setMax(Long max) { + if (max != null) this.max = max; + } + + @Override + public boolean test(Long t) { + if (max < min && max <= 0) return t >= min; + return t >= min && t <= max; + } + + @Override + public String toString() { + return "{min:" + min + ", max:" + max + "}"; + } + } + + public static final class FloatRange implements Range { + + @ConvertColumn(index = 1) + private Float min = Float.MIN_VALUE; + + @ConvertColumn(index = 2) + private Float max = Float.MAX_VALUE; + + public FloatRange() { + } + + public FloatRange(Float min, Float max) { + if (min != null) this.min = min; + if (max != null) this.max = max; + } + + @Override + public Float getMin() { + return min; + } + + @Override + public Float getMax() { + return max; + } + + public void setMin(Float min) { + if (min != null) this.min = min; + } + + public void setMax(Float max) { + if (max != null) this.max = max; + } + + @Override + public boolean test(Float t) { + if (max < min && max <= 0) return t >= min; + return t >= min && t <= max; + } + + @Override + public String toString() { + return "{min:" + min + ", max:" + max + "}"; + } + } + + public static final class DoubleRange implements Range { + + @ConvertColumn(index = 1) + private Double min = Double.MIN_VALUE; + + @ConvertColumn(index = 2) + private Double max = Double.MAX_VALUE; + + public DoubleRange() { + } + + public DoubleRange(Double min, Double max) { + if (min != null) this.min = min; + if (max != null) this.max = max; + } + + @Override + public Double getMin() { + return min; + } + + @Override + public Double getMax() { + return max; + } + + public void setMin(Double min) { + if (min != null) this.min = min; + } + + public void setMax(Double max) { + if (max != null) this.max = max; + } + + @Override + public boolean test(Double t) { + if (max < min && max <= 0) return t >= min; + return t >= min && t <= max; + } + + @Override + public String toString() { + return "{min:" + min + ", max:" + max + "}"; + } + } + + public static final class StringRange implements Range { + + @ConvertColumn(index = 1) + private String min = ""; + + @ConvertColumn(index = 2) + private String max = ""; + + public StringRange() { + } + + public StringRange(String min, String max) { + this.min = min; + this.max = max; + } + + @Override + public String getMin() { + return min; + } + + @Override + public String getMax() { + return max; + } + + public void setMin(String min) { + if (min != null) this.min = min; + } + + public void setMax(String max) { + if (max != null) this.max = max; + } + + @Override + public boolean test(String t) { + return t.compareTo(min) >= 0 && t.compareTo(max) <= 0; + } + + @Override + public String toString() { + return "{min:'" + min + "', max:'" + max + "'}"; + } + } +} diff --git a/src/main/java/org/redkale/source/SearchBean.java b/src/main/java/org/redkale/source/SearchBean.java index da09d38f1..6b7301302 100644 --- a/src/main/java/org/redkale/source/SearchBean.java +++ b/src/main/java/org/redkale/source/SearchBean.java @@ -1,400 +1,400 @@ -/* - * 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.source; - -import java.util.*; -import org.redkale.convert.*; -import org.redkale.convert.json.JsonConvert; - -/** - * SearchFilterBean鐢ㄤ簬鎼滅储鏉′欢锛 鎵鏈夌殑FilterBean閮藉繀椤诲彲浠ヨ浆鎹㈡垚FilterNode
- * - * 涓嶈鏍囪涓@javax.persistence.Transient 鐨勫瓧娈靛潎瑙嗕负杩囨护鏉′欢
- * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * - * @since 2.4.0 - */ -@ConvertImpl(SearchBean.SearchSimpleBean.class) -public interface SearchBean extends java.io.Serializable { - - public static final String SEARCH_FILTER_NAME = "#search"; - - public static SearchSimpleBean create() { - return new SearchSimpleBean(); - } - - public static SearchSimpleBean create(String keyword, String... fields) { - return new SearchSimpleBean(keyword, fields); - } - - /** - * 闇瑕佹悳绱㈢殑index闆嗗悎锛屾棤鍊煎垯浣跨敤褰撳墠entity绫 - * - * @return Class[] - */ - public Class[] searchClasses(); - - /** - * 鎼滅储瀛楁闆嗗悎锛 蹇呴』瀛楁鍊 - * - * @return String[] - */ - public String[] searchFields(); - - /** - * 鎼滅储鍏抽敭瀛楋紝 蹇呴』瀛楁鍊 - * - * @return String - */ - public String searchKeyword(); - - /** - * 鎼滅储鍒嗚瘝鍣紝鍙互涓虹┖ - * - * @return String - */ - public String searchAnalyzer(); - - /** - * 鎵╁睍鐨勪俊鎭 - * - * @return Map - */ - default Map extras() { - return null; - } - - /** - * 楂樹寒鏄剧ず - * - * @return SearchHighlightBean - */ - public SearchHighlightBean highlight(); - - @ConvertImpl(SearchBean.SearchSimpleHighlightBean.class) - public static interface SearchHighlightBean { - - public static SearchSimpleHighlightBean create() { - return new SearchSimpleHighlightBean(); - } - - public String preTag(); - - public String postTag(); - - public String boundaryLocale(); - - public int fragmentSize(); - - default int fragmentCount() { - return 1; - } - - default Map extras() { - return null; - } - } - - public static class SearchSimpleBean implements SearchBean { - - @ConvertColumn(index = 1) - @FilterColumn(ignore = true) - private Class[] classes; - - @ConvertColumn(index = 2) - @FilterColumn(ignore = true) - private String[] fields; - - @ConvertColumn(index = 3) - @FilterColumn(ignore = true) - private String keyword; - - @ConvertColumn(index = 4) - @FilterColumn(ignore = true) - private String analyzer; - - @ConvertColumn(index = 5) - @FilterColumn(ignore = true) - private SearchHighlightBean highlight; - - @ConvertColumn(index = 6) - @FilterColumn(ignore = true) - private Map extras; - - public SearchSimpleBean() { - } - - public SearchSimpleBean(String keyword, String... fields) { - this.keyword = keyword; - this.fields = fields; - if (fields == null || fields.length < 1) throw new IllegalArgumentException("fields is empty"); - } - - public SearchSimpleBean keyword(String keyword) { - this.keyword = keyword; - return this; - } - - public SearchSimpleBean analyzer(String analyzer) { - this.analyzer = analyzer; - return this; - } - - public SearchSimpleBean fields(String... fields) { - if (fields == null || fields.length < 1) throw new IllegalArgumentException("fields is empty"); - this.fields = fields; - return this; - } - - public SearchSimpleBean classes(Class[] classes) { - this.classes = classes; - return this; - } - - public SearchSimpleBean highlight(SearchHighlightBean highlight) { - this.highlight = highlight; - return this; - } - - public SearchSimpleBean extras(Map map) { - this.extras = map; - return this; - } - - public SearchSimpleBean extras(String key, Object value) { - if (this.extras == null) this.extras = new LinkedHashMap<>(); - this.extras.put(key, value); - return this; - } - - @Override - public String searchKeyword() { - return keyword; - } - - @Override - public Class[] searchClasses() { - return classes; - } - - @Override - public String[] searchFields() { - return fields; - } - - @Override - public Map extras() { - return extras; - } - - @Override - public String searchAnalyzer() { - return analyzer; - } - - @Override - public SearchHighlightBean highlight() { - return highlight; - } - - public Class[] getClasses() { - return classes; - } - - public void setClasses(Class[] classes) { - this.classes = classes; - } - - public String[] getFields() { - return fields; - } - - public void setFields(String[] fields) { - this.fields = fields; - } - - public String getKeyword() { - return keyword; - } - - public void setKeyword(String keyword) { - this.keyword = keyword; - } - - public String getAnalyzer() { - return analyzer; - } - - public void setAnalyzer(String analyzer) { - this.analyzer = analyzer; - } - - public SearchHighlightBean getHighlight() { - return highlight; - } - - public void setHighlight(SearchHighlightBean highlight) { - this.highlight = highlight; - } - - public Map getExtras() { - return extras; - } - - public void setExtras(Map extras) { - this.extras = extras; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - - } - - public static class SearchSimpleHighlightBean implements SearchHighlightBean { - - @ConvertColumn(index = 1) - private String preTag; - - @ConvertColumn(index = 2) - private String postTag; - - @ConvertColumn(index = 3) - private String boundaryLocale; - - @ConvertColumn(index = 4) - private int fragmentSize = 100; - - @ConvertColumn(index = 5) - private int fragmentCount = 1; - - @ConvertColumn(index = 6) - @FilterColumn(ignore = true) - private Map extras; - - public SearchSimpleHighlightBean tag(String preTag, String postTag) { - this.preTag = preTag; - this.postTag = postTag; - return this; - } - - public SearchSimpleHighlightBean boundaryLocale(String boundaryLocale) { - this.boundaryLocale = boundaryLocale; - return this; - } - - public SearchSimpleHighlightBean fragmentSize(int fragmentSize) { - this.fragmentSize = fragmentSize; - return this; - } - - public SearchSimpleHighlightBean fragmentCount(int fragmentCount) { - this.fragmentCount = fragmentCount; - return this; - } - - public SearchSimpleHighlightBean extras(Map map) { - this.extras = map; - return this; - } - - public SearchSimpleHighlightBean extras(String key, Object value) { - if (this.extras == null) this.extras = new LinkedHashMap<>(); - this.extras.put(key, value); - return this; - } - - @Override - public Map extras() { - return extras; - } - - @Override - public String preTag() { - return preTag; - } - - @Override - public String postTag() { - return postTag; - } - - @Override - public String boundaryLocale() { - return boundaryLocale; - } - - @Override - public int fragmentSize() { - return fragmentSize; - } - - @Override - public int fragmentCount() { - return fragmentCount; - } - - public String getPreTag() { - return preTag; - } - - public void setPreTag(String preTag) { - this.preTag = preTag; - } - - public String getPostTag() { - return postTag; - } - - public void setPostTag(String postTag) { - this.postTag = postTag; - } - - public String getBoundaryLocale() { - return boundaryLocale; - } - - public void setBoundaryLocale(String boundaryLocale) { - this.boundaryLocale = boundaryLocale; - } - - public int getFragmentSize() { - return fragmentSize; - } - - public void setFragmentSize(int fragmentSize) { - this.fragmentSize = fragmentSize; - } - - public int getFragmentCount() { - return fragmentCount; - } - - public void setFragmentCount(int fragmentCount) { - this.fragmentCount = fragmentCount; - } - - public Map getExtras() { - return extras; - } - - public void setExtras(Map extras) { - this.extras = extras; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - - } - -} +/* + * 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.source; + +import java.util.*; +import org.redkale.convert.*; +import org.redkale.convert.json.JsonConvert; + +/** + * SearchFilterBean鐢ㄤ簬鎼滅储鏉′欢锛 鎵鏈夌殑FilterBean閮藉繀椤诲彲浠ヨ浆鎹㈡垚FilterNode
+ * + * 涓嶈鏍囪涓@javax.persistence.Transient 鐨勫瓧娈靛潎瑙嗕负杩囨护鏉′欢
+ * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.4.0 + */ +@ConvertImpl(SearchBean.SearchSimpleBean.class) +public interface SearchBean extends java.io.Serializable { + + public static final String SEARCH_FILTER_NAME = "#search"; + + public static SearchSimpleBean create() { + return new SearchSimpleBean(); + } + + public static SearchSimpleBean create(String keyword, String... fields) { + return new SearchSimpleBean(keyword, fields); + } + + /** + * 闇瑕佹悳绱㈢殑index闆嗗悎锛屾棤鍊煎垯浣跨敤褰撳墠entity绫 + * + * @return Class[] + */ + public Class[] searchClasses(); + + /** + * 鎼滅储瀛楁闆嗗悎锛 蹇呴』瀛楁鍊 + * + * @return String[] + */ + public String[] searchFields(); + + /** + * 鎼滅储鍏抽敭瀛楋紝 蹇呴』瀛楁鍊 + * + * @return String + */ + public String searchKeyword(); + + /** + * 鎼滅储鍒嗚瘝鍣紝鍙互涓虹┖ + * + * @return String + */ + public String searchAnalyzer(); + + /** + * 鎵╁睍鐨勪俊鎭 + * + * @return Map + */ + default Map extras() { + return null; + } + + /** + * 楂樹寒鏄剧ず + * + * @return SearchHighlightBean + */ + public SearchHighlightBean highlight(); + + @ConvertImpl(SearchBean.SearchSimpleHighlightBean.class) + public static interface SearchHighlightBean { + + public static SearchSimpleHighlightBean create() { + return new SearchSimpleHighlightBean(); + } + + public String preTag(); + + public String postTag(); + + public String boundaryLocale(); + + public int fragmentSize(); + + default int fragmentCount() { + return 1; + } + + default Map extras() { + return null; + } + } + + public static class SearchSimpleBean implements SearchBean { + + @ConvertColumn(index = 1) + @FilterColumn(ignore = true) + private Class[] classes; + + @ConvertColumn(index = 2) + @FilterColumn(ignore = true) + private String[] fields; + + @ConvertColumn(index = 3) + @FilterColumn(ignore = true) + private String keyword; + + @ConvertColumn(index = 4) + @FilterColumn(ignore = true) + private String analyzer; + + @ConvertColumn(index = 5) + @FilterColumn(ignore = true) + private SearchHighlightBean highlight; + + @ConvertColumn(index = 6) + @FilterColumn(ignore = true) + private Map extras; + + public SearchSimpleBean() { + } + + public SearchSimpleBean(String keyword, String... fields) { + this.keyword = keyword; + this.fields = fields; + if (fields == null || fields.length < 1) throw new IllegalArgumentException("fields is empty"); + } + + public SearchSimpleBean keyword(String keyword) { + this.keyword = keyword; + return this; + } + + public SearchSimpleBean analyzer(String analyzer) { + this.analyzer = analyzer; + return this; + } + + public SearchSimpleBean fields(String... fields) { + if (fields == null || fields.length < 1) throw new IllegalArgumentException("fields is empty"); + this.fields = fields; + return this; + } + + public SearchSimpleBean classes(Class[] classes) { + this.classes = classes; + return this; + } + + public SearchSimpleBean highlight(SearchHighlightBean highlight) { + this.highlight = highlight; + return this; + } + + public SearchSimpleBean extras(Map map) { + this.extras = map; + return this; + } + + public SearchSimpleBean extras(String key, Object value) { + if (this.extras == null) this.extras = new LinkedHashMap<>(); + this.extras.put(key, value); + return this; + } + + @Override + public String searchKeyword() { + return keyword; + } + + @Override + public Class[] searchClasses() { + return classes; + } + + @Override + public String[] searchFields() { + return fields; + } + + @Override + public Map extras() { + return extras; + } + + @Override + public String searchAnalyzer() { + return analyzer; + } + + @Override + public SearchHighlightBean highlight() { + return highlight; + } + + public Class[] getClasses() { + return classes; + } + + public void setClasses(Class[] classes) { + this.classes = classes; + } + + public String[] getFields() { + return fields; + } + + public void setFields(String[] fields) { + this.fields = fields; + } + + public String getKeyword() { + return keyword; + } + + public void setKeyword(String keyword) { + this.keyword = keyword; + } + + public String getAnalyzer() { + return analyzer; + } + + public void setAnalyzer(String analyzer) { + this.analyzer = analyzer; + } + + public SearchHighlightBean getHighlight() { + return highlight; + } + + public void setHighlight(SearchHighlightBean highlight) { + this.highlight = highlight; + } + + public Map getExtras() { + return extras; + } + + public void setExtras(Map extras) { + this.extras = extras; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + + } + + public static class SearchSimpleHighlightBean implements SearchHighlightBean { + + @ConvertColumn(index = 1) + private String preTag; + + @ConvertColumn(index = 2) + private String postTag; + + @ConvertColumn(index = 3) + private String boundaryLocale; + + @ConvertColumn(index = 4) + private int fragmentSize = 100; + + @ConvertColumn(index = 5) + private int fragmentCount = 1; + + @ConvertColumn(index = 6) + @FilterColumn(ignore = true) + private Map extras; + + public SearchSimpleHighlightBean tag(String preTag, String postTag) { + this.preTag = preTag; + this.postTag = postTag; + return this; + } + + public SearchSimpleHighlightBean boundaryLocale(String boundaryLocale) { + this.boundaryLocale = boundaryLocale; + return this; + } + + public SearchSimpleHighlightBean fragmentSize(int fragmentSize) { + this.fragmentSize = fragmentSize; + return this; + } + + public SearchSimpleHighlightBean fragmentCount(int fragmentCount) { + this.fragmentCount = fragmentCount; + return this; + } + + public SearchSimpleHighlightBean extras(Map map) { + this.extras = map; + return this; + } + + public SearchSimpleHighlightBean extras(String key, Object value) { + if (this.extras == null) this.extras = new LinkedHashMap<>(); + this.extras.put(key, value); + return this; + } + + @Override + public Map extras() { + return extras; + } + + @Override + public String preTag() { + return preTag; + } + + @Override + public String postTag() { + return postTag; + } + + @Override + public String boundaryLocale() { + return boundaryLocale; + } + + @Override + public int fragmentSize() { + return fragmentSize; + } + + @Override + public int fragmentCount() { + return fragmentCount; + } + + public String getPreTag() { + return preTag; + } + + public void setPreTag(String preTag) { + this.preTag = preTag; + } + + public String getPostTag() { + return postTag; + } + + public void setPostTag(String postTag) { + this.postTag = postTag; + } + + public String getBoundaryLocale() { + return boundaryLocale; + } + + public void setBoundaryLocale(String boundaryLocale) { + this.boundaryLocale = boundaryLocale; + } + + public int getFragmentSize() { + return fragmentSize; + } + + public void setFragmentSize(int fragmentSize) { + this.fragmentSize = fragmentSize; + } + + public int getFragmentCount() { + return fragmentCount; + } + + public void setFragmentCount(int fragmentCount) { + this.fragmentCount = fragmentCount; + } + + public Map getExtras() { + return extras; + } + + public void setExtras(Map extras) { + this.extras = extras; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + + } + +} diff --git a/src/main/java/org/redkale/source/SearchColumn.java b/src/main/java/org/redkale/source/SearchColumn.java index 5c93e5e13..d6670865b 100644 --- a/src/main/java/org/redkale/source/SearchColumn.java +++ b/src/main/java/org/redkale/source/SearchColumn.java @@ -1,87 +1,87 @@ -/* - * 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.source; - -import java.lang.annotation.Target; -import java.lang.annotation.Retention; -import static java.lang.annotation.ElementType.*; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * - * 鎼滅储寮曟搸鐨勬暟鎹瓻ntity渚濋檮鍦╯etter銆乬etter鏂规硶銆佸瓧娈佃繘琛岀畝鍗曠殑閰嶇疆
- * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @since 2.4.0 - */ -@Target({FIELD}) -@Retention(RUNTIME) -public @interface SearchColumn { - - //楂樹寒鏄剧ず鍙傛暟 - public static class HighLights { - - public static final String HIGHLIGHT_NAME_ID = "#[id]"; - - public static final String HIGHLIGHT_NAME_INDEX = "#[index]"; - - } - - /** - * 鏄惁鍏ㄦ枃鎼滅储 - * - * @return boolean - */ - boolean text() default false; - - /** - * 楂樹寒瀵瑰簲鐨凜olumn.name瀛楁鍚嶏紝琚爣璁扮殑瀛楁涓鸿櫄鎷熷瓧娈碉紝涓嶄細鏄犲皠琛ㄤ腑鐨勫瓧娈
- * 琚爣璁扮殑瀛楁蹇呴』鏄疭tring绫诲瀷
- * 鏈夊兼椂锛宨gnore蹇呴』涓簍rue - * - * @return String - */ - String highlight() default ""; - - /** - * 瑙f瀽/瀛樺偍鏃舵槸鍚﹀睆钄借瀛楁 - * - * @return boolean - */ - boolean ignore() default false; - - /** - * 璁剧疆绱㈠紩鍙傛暟 - * - * @return String - */ - String options() default ""; - - /** - * 鍐呭鏄惁html鏍煎紡 - * - * @return boolean - */ - boolean html() default false; - - /** - * 璁剧疆绱㈠紩鍒嗚瘝鍣 - * - * @return String - */ - String analyzer() default ""; - - /** - * 璁剧疆鎼滅储绱㈠紩鍒嗚瘝鍣 - * - * @return String - */ - String searchAnalyzer() default ""; - -} +/* + * 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.source; + +import java.lang.annotation.Target; +import java.lang.annotation.Retention; +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * + * 鎼滅储寮曟搸鐨勬暟鎹瓻ntity渚濋檮鍦╯etter銆乬etter鏂规硶銆佸瓧娈佃繘琛岀畝鍗曠殑閰嶇疆
+ * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @since 2.4.0 + */ +@Target({FIELD}) +@Retention(RUNTIME) +public @interface SearchColumn { + + //楂樹寒鏄剧ず鍙傛暟 + public static class HighLights { + + public static final String HIGHLIGHT_NAME_ID = "#[id]"; + + public static final String HIGHLIGHT_NAME_INDEX = "#[index]"; + + } + + /** + * 鏄惁鍏ㄦ枃鎼滅储 + * + * @return boolean + */ + boolean text() default false; + + /** + * 楂樹寒瀵瑰簲鐨凜olumn.name瀛楁鍚嶏紝琚爣璁扮殑瀛楁涓鸿櫄鎷熷瓧娈碉紝涓嶄細鏄犲皠琛ㄤ腑鐨勫瓧娈
+ * 琚爣璁扮殑瀛楁蹇呴』鏄疭tring绫诲瀷
+ * 鏈夊兼椂锛宨gnore蹇呴』涓簍rue + * + * @return String + */ + String highlight() default ""; + + /** + * 瑙f瀽/瀛樺偍鏃舵槸鍚﹀睆钄借瀛楁 + * + * @return boolean + */ + boolean ignore() default false; + + /** + * 璁剧疆绱㈠紩鍙傛暟 + * + * @return String + */ + String options() default ""; + + /** + * 鍐呭鏄惁html鏍煎紡 + * + * @return boolean + */ + boolean html() default false; + + /** + * 璁剧疆绱㈠紩鍒嗚瘝鍣 + * + * @return String + */ + String analyzer() default ""; + + /** + * 璁剧疆鎼滅储绱㈠紩鍒嗚瘝鍣 + * + * @return String + */ + String searchAnalyzer() default ""; + +} diff --git a/src/main/java/org/redkale/source/SearchSource.java b/src/main/java/org/redkale/source/SearchSource.java index d6b178101..f32b7d15e 100644 --- a/src/main/java/org/redkale/source/SearchSource.java +++ b/src/main/java/org/redkale/source/SearchSource.java @@ -1,26 +1,26 @@ -/* - * 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.source; - -import java.util.concurrent.CompletableFuture; - -/** - * - * 鎼滅储寮曟搸鐨勬暟鎹簮锛 鎺ュ彛涓嶥ataSource鍩烘湰涓鑷淬
- * 杩斿洖绫诲瀷涓篊ompletableFuture鐨勬帴鍙d负寮傛鎺ュ彛 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @since 2.4.0 - */ -public interface SearchSource extends DataSource { - - public int updateMapping(final Class clazz); - - public CompletableFuture updateMappingAsync(final Class clazz); -} +/* + * 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.source; + +import java.util.concurrent.CompletableFuture; + +/** + * + * 鎼滅储寮曟搸鐨勬暟鎹簮锛 鎺ュ彛涓嶥ataSource鍩烘湰涓鑷淬
+ * 杩斿洖绫诲瀷涓篊ompletableFuture鐨勬帴鍙d负寮傛鎺ュ彛 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @since 2.4.0 + */ +public interface SearchSource extends DataSource { + + public int updateMapping(final Class clazz); + + public CompletableFuture updateMappingAsync(final Class clazz); +} diff --git a/src/main/java/org/redkale/source/SourceConvert.java b/src/main/java/org/redkale/source/SourceConvert.java index 60ef324d7..3c7a4b7ab 100644 --- a/src/main/java/org/redkale/source/SourceConvert.java +++ b/src/main/java/org/redkale/source/SourceConvert.java @@ -1,28 +1,28 @@ -/* - * 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.source; - -import java.lang.annotation.*; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * 鐢ㄤ簬瀹氬埗Source鎿嶄綔JSON瀛楁鐨勮浆鎹㈢瓥鐣ャ
- * 鍙兘渚濋檮鍦‥ntity绫荤殑闈欐佹棤鍙傛暟鏂规硶涓, 涓旇繑鍥炲煎繀椤绘槸JsonConvert銆
- * 娉ㄦ剰: 濡傛灉涓涓被鏈変袱涓潤鎬佹柟娉曟爣璁颁负@SourceConvert锛 妗嗘灦鍙細璇嗗埆绗竴涓 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@Inherited -@Documented -@Target({METHOD}) -@Retention(RUNTIME) -public @interface SourceConvert { - -} +/* + * 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.source; + +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * 鐢ㄤ簬瀹氬埗Source鎿嶄綔JSON瀛楁鐨勮浆鎹㈢瓥鐣ャ
+ * 鍙兘渚濋檮鍦‥ntity绫荤殑闈欐佹棤鍙傛暟鏂规硶涓, 涓旇繑鍥炲煎繀椤绘槸JsonConvert銆
+ * 娉ㄦ剰: 濡傛灉涓涓被鏈変袱涓潤鎬佹柟娉曟爣璁颁负@SourceConvert锛 妗嗘灦鍙細璇嗗埆绗竴涓 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@Inherited +@Documented +@Target({METHOD}) +@Retention(RUNTIME) +public @interface SourceConvert { + +} diff --git a/src/main/java/org/redkale/source/VirtualEntity.java b/src/main/java/org/redkale/source/VirtualEntity.java index b27ca642d..344b0748c 100644 --- a/src/main/java/org/redkale/source/VirtualEntity.java +++ b/src/main/java/org/redkale/source/VirtualEntity.java @@ -1,53 +1,53 @@ -/* - * 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.source; - -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; -import java.lang.annotation.*; -import java.util.*; -import java.util.concurrent.CompletableFuture; -import java.util.function.*; - -/** - * VirtualEntity琛ㄧず铏氭嫙鐨勬暟鎹疄浣撶被锛 閫氬父Entity閮戒細鏄犲皠鍒版暟鎹簱涓殑鏌愪釜琛紝鑰屾爣璁颁负@VirtualEntity鐨凟ntity绫诲彧瀛樺湪EntityCache涓 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@Documented -@Target(TYPE) -@Retention(RUNTIME) -public @interface VirtualEntity { - - /** - * DataSource鏄惁鐩存帴杩斿洖瀵硅薄鐨勭湡瀹炲紩鐢紝 鑰屼笉鏄痗opy涓浠 - * - * @return boolean - */ - boolean direct() default false; - - /** - * 鍒濆鍖栨椂鏁版嵁鐨勫姞杞藉櫒 - * - * @return Class - */ - Class>> loader() default DefaultFunctionLoader.class; - - /** - * 榛樿鍏ㄩ噺鍔犺浇鍣 - * - */ - public static class DefaultFunctionLoader implements BiFunction> { - - @Override - public CompletableFuture apply(DataSource source, EntityInfo info) { - return null; - } - } -} +/* + * 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.source; + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import java.lang.annotation.*; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.function.*; + +/** + * VirtualEntity琛ㄧず铏氭嫙鐨勬暟鎹疄浣撶被锛 閫氬父Entity閮戒細鏄犲皠鍒版暟鎹簱涓殑鏌愪釜琛紝鑰屾爣璁颁负@VirtualEntity鐨凟ntity绫诲彧瀛樺湪EntityCache涓 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@Documented +@Target(TYPE) +@Retention(RUNTIME) +public @interface VirtualEntity { + + /** + * DataSource鏄惁鐩存帴杩斿洖瀵硅薄鐨勭湡瀹炲紩鐢紝 鑰屼笉鏄痗opy涓浠 + * + * @return boolean + */ + boolean direct() default false; + + /** + * 鍒濆鍖栨椂鏁版嵁鐨勫姞杞藉櫒 + * + * @return Class + */ + Class>> loader() default DefaultFunctionLoader.class; + + /** + * 榛樿鍏ㄩ噺鍔犺浇鍣 + * + */ + public static class DefaultFunctionLoader implements BiFunction> { + + @Override + public CompletableFuture apply(DataSource source, EntityInfo info) { + return null; + } + } +} diff --git a/src/main/java/org/redkale/source/package-info.java b/src/main/java/org/redkale/source/package-info.java index 0fdd99524..47fa2d01a 100644 --- a/src/main/java/org/redkale/source/package-info.java +++ b/src/main/java/org/redkale/source/package-info.java @@ -1,4 +1,4 @@ -/** - * 鏁版嵁婧(鏁版嵁搴撱佺紦瀛)鎿嶄綔鍖 - */ -package org.redkale.source; +/** + * 鏁版嵁婧(鏁版嵁搴撱佺紦瀛)鎿嶄綔鍖 + */ +package org.redkale.source; diff --git a/src/main/java/org/redkale/util/AnyValue.java b/src/main/java/org/redkale/util/AnyValue.java index 794b05293..343c811c9 100644 --- a/src/main/java/org/redkale/util/AnyValue.java +++ b/src/main/java/org/redkale/util/AnyValue.java @@ -1,778 +1,778 @@ -/* - * 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.util; - -import java.io.*; -import java.nio.charset.*; -import java.util.*; -import java.util.function.*; -import org.redkale.convert.ConvertDisabled; - -/** - * 璇ョ被鎻愪緵绫讳技JSONObject鐨勬暟鎹粨鏋勶紝涓昏鐢ㄤ簬璇诲彇xml閰嶇疆鏂囦欢鍜宧ttp-header瀛樺偍 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@SuppressWarnings("unchecked") -public abstract class AnyValue { - - /** - * xml鐨勬枃鏈妭鐐筺ame - */ - public static final String XML_TEXT_NODE_NAME = ""; - - /** - * 鍙鍐欑殑AnyValue榛樿瀹炵幇绫 - * - * @author zhangjx - */ - @SuppressWarnings("unchecked") - public static final class DefaultAnyValue extends AnyValue { - - /** - * 鍖哄垎name澶у皬鍐欑殑姣旇緝绛栫暐 - * - */ - public static final BiPredicate EQUALS = (name1, name2) -> name1.equals(name2); - - /** - * 涓嶅尯鍒唍ame澶у皬鍐欑殑姣旇緝绛栫暐 - */ - public static final BiPredicate EQUALSIGNORE = (name1, name2) -> name1.equalsIgnoreCase(name2); - - private boolean ignoreCase; - - private BiPredicate predicate; - - private Entry[] stringEntrys = new Entry[0]; - - private Entry[] anyEntrys = new Entry[0]; - - /** - * 鍒涘缓绌虹殑DefaultAnyValue瀵硅薄 - * - * @return DefaultAnyValue瀵硅薄 - */ - public static final DefaultAnyValue create() { - return new DefaultAnyValue(); - } - - /** - * 鍒涘缓鍚玭ame-value鍊肩殑DefaultAnyValue瀵硅薄 - * - * @param name name - * @param value value鍊 - * - * @return DefaultAnyValue瀵硅薄 - */ - public static final DefaultAnyValue create(String name, Number value) { - DefaultAnyValue conf = new DefaultAnyValue(); - conf.addValue(name, value); - return conf; - } - - /** - * 鍒涘缓鍚玭ame-value鍊肩殑DefaultAnyValue瀵硅薄 - * - * @param name name - * @param value value鍊 - * - * @return DefaultAnyValue瀵硅薄 - */ - public static final DefaultAnyValue create(String name, String value) { - DefaultAnyValue conf = new DefaultAnyValue(); - conf.addValue(name, value); - return conf; - } - - /** - * 鍒涘缓鍚玭ame-value鍊肩殑DefaultAnyValue瀵硅薄 - * - * @param name name - * @param value value鍊 - * - * @return DefaultAnyValue瀵硅薄 - */ - public static final DefaultAnyValue create(String name, AnyValue value) { - DefaultAnyValue conf = new DefaultAnyValue(); - conf.addValue(name, value); - return conf; - } - - /** - * 鍒涘缓涓涓尯鍒嗗ぇ灏忓啓姣旇緝绛栫暐鐨凞efaultAnyValue瀵硅薄 - * - */ - public DefaultAnyValue() { - this(false); - } - - /** - * 鍒涘缓DefaultAnyValue瀵硅薄 - * - * @param ignoreCase name鏄惁涓嶅尯鍒嗗ぇ灏忓啓 - */ - public DefaultAnyValue(boolean ignoreCase) { - this.ignoreCase = ignoreCase; - this.predicate = ignoreCase ? EQUALSIGNORE : EQUALS; - } - - /** - * 鍒涘缓鍏变韩姝ゅ唴瀹圭殑DefaultAnyValue瀵硅薄 - * - * @return DefaultAnyValue瀵硅薄 - */ - public DefaultAnyValue duplicate() { - DefaultAnyValue rs = new DefaultAnyValue(this.ignoreCase); - rs.stringEntrys = this.stringEntrys; - rs.anyEntrys = this.anyEntrys; - return rs; - } - - //鍘婚噸 - public DefaultAnyValue addAllStringSet(final AnyValue av) { - if (av == null) return this; - final Entry[] strings = av.getStringEntrys(); - if (strings == null) return this; - for (Entry en : strings) { - if (getValue(en.name) == null) this.addValue(en.name, en.value); - } - return this; - } - - public DefaultAnyValue addAll(final AnyValue av) { - if (av == null) return this; - if (av instanceof DefaultAnyValue) { - final DefaultAnyValue adv = (DefaultAnyValue) av; - if (adv.stringEntrys != null) { - for (Entry en : adv.stringEntrys) { - this.addValue(en.name, en.value); - } - } - if (adv.anyEntrys != null) { - for (Entry en : adv.anyEntrys) { - this.addValue(en.name, en.value); - } - } - } else { - final Entry[] strings = av.getStringEntrys(); - if (strings != null) { - for (Entry en : strings) { - this.addValue(en.name, en.value); - } - } - final Entry[] anys = av.getAnyEntrys(); - if (anys != null) { - for (Entry en : anys) { - this.addValue(en.name, en.value); - } - } - } - return this; - } - - public DefaultAnyValue setAll(final AnyValue av) { - if (av == null) return this; - if (av instanceof DefaultAnyValue) { - final DefaultAnyValue adv = (DefaultAnyValue) av; - if (adv.stringEntrys != null) { - for (Entry en : adv.stringEntrys) { - this.setValue(en.name, en.value); - } - } - if (adv.anyEntrys != null) { - for (Entry en : adv.anyEntrys) { - this.setValue(en.name, en.value); - } - } - } else { - final Entry[] strings = av.getStringEntrys(); - if (strings != null) { - for (Entry en : strings) { - this.setValue(en.name, en.value); - } - } - final Entry[] anys = av.getAnyEntrys(); - if (anys != null) { - for (Entry en : anys) { - this.setValue(en.name, en.value); - } - } - } - return this; - } - - @Override - public void forEach(BiConsumer stringConsumer) { - forEach(stringConsumer, null); - } - - @Override - public void forEach(BiConsumer stringConsumer, BiConsumer anyConsumer) { - if (stringConsumer != null) { - for (Entry en : stringEntrys) { - stringConsumer.accept(en.name, en.value); - } - } - if (anyConsumer != null) { - for (Entry en : (Entry[]) anyEntrys) { - anyConsumer.accept(en.name, en.value); - } - } - } - - @Override - public Entry[] getStringEntrys() { - return stringEntrys; - } - - public void setStringEntrys(Entry[] stringEntrys) { - this.stringEntrys = stringEntrys; - } - - @Override - public Entry[] getAnyEntrys() { - return (Entry[]) (Entry[]) anyEntrys; - } - - public void setAnyEntrys(Entry[] anyEntrys) { - this.anyEntrys = anyEntrys; - } - - public boolean isIgnoreCase() { - return ignoreCase; - } - - public void setIgnoreCase(boolean ignoreCase) { - this.ignoreCase = ignoreCase; - if (this.predicate == null) { - this.predicate = ignoreCase ? EQUALSIGNORE : EQUALS; - } - } - - @Override - @ConvertDisabled - public String[] getNames() { - Set set = new LinkedHashSet<>(); - for (Entry en : this.stringEntrys) { - set.add(en.name); - } - for (Entry en : this.anyEntrys) { - set.add(en.name); - } - return set.toArray(new String[set.size()]); - } - - @Override - public String[] getValues(String... names) { - return Entry.getStringValues(this.predicate, this.stringEntrys, names); - } - - @Override - public AnyValue[] getAnyValues(String... names) { - return Entry.getAnyValueValues(this.predicate, this.anyEntrys, names); - } - - @Override - public String[] getValues(String name) { - return Entry.getStringValues(this.predicate, this.stringEntrys, name); - } - - @Override - public AnyValue[] getAnyValues(String name) { - return Entry.getAnyValueValues(this.predicate, this.anyEntrys, name); - } - - @Override - public String toString() { - return toString(0); - } - - public DefaultAnyValue clear() { - if (this.stringEntrys != null && this.stringEntrys.length > 0) this.stringEntrys = new Entry[0]; - if (this.anyEntrys != null && this.anyEntrys.length > 0) this.anyEntrys = new Entry[0]; - return this; - } - - public DefaultAnyValue setValue(String name, String value) { - if (name == null) return this; - if (getValue(name) == null) { - this.addValue(name, value); - } else { - for (Entry en : this.stringEntrys) { - if (predicate.test(en.name, name)) { - en.value = value; - return this; - } - } - } - return this; - } - - public DefaultAnyValue setValue(String name, AnyValue value) { - if (name == null) return this; - if (getValue(name) == null) { - this.addValue(name, value); - } else { - for (Entry en : this.anyEntrys) { - if (predicate.test(en.name, name)) { - en.value = (DefaultAnyValue) value; - return this; - } - } - } - return this; - } - - public DefaultAnyValue put(String name, boolean value) { - return addValue(name, String.valueOf(value)); - } - - public DefaultAnyValue put(String name, Number value) { - return addValue(name, String.valueOf(value)); - } - - public DefaultAnyValue put(String name, String value) { - this.stringEntrys = Utility.append(this.stringEntrys, new Entry(name, value)); - return this; - } - - public DefaultAnyValue addValue(String name, boolean value) { - return addValue(name, String.valueOf(value)); - } - - public DefaultAnyValue addValue(String name, Number value) { - return addValue(name, String.valueOf(value)); - } - - public DefaultAnyValue addValue(String name, String value) { - this.stringEntrys = Utility.append(this.stringEntrys, new Entry(name, value)); - return this; - } - - public DefaultAnyValue addValue(String name, AnyValue value) { - if (name == null || value == null) return this; - this.anyEntrys = Utility.append(this.anyEntrys, new Entry(name, value)); - return this; - } - - public DefaultAnyValue removeValue(String name, AnyValue value) { - if (name == null || value == null || this.anyEntrys == null) return this; - this.anyEntrys = Utility.remove(this.anyEntrys, (t) -> name.equals(((Entry) t).name) && ((Entry) t).getValue().equals(value)); - return this; - } - - public DefaultAnyValue removeValue(String name, String value) { - if (name == null || value == null || this.stringEntrys == null) return this; - this.stringEntrys = Utility.remove(this.stringEntrys, (t) -> name.equals(((Entry) t).name) && ((Entry) t).getValue().equals(value)); - return this; - } - - @Override - public AnyValue getAnyValue(String name) { - for (Entry en : this.anyEntrys) { - if (predicate.test(en.name, name)) { - return en.value; - } - } - return null; - } - - @Override - public String get(String name) { - return getValue(name); - } - - @Override - public String getValue(String name) { - for (Entry en : this.stringEntrys) { - if (predicate.test(en.name, name)) { - return en.value; - } - } - return null; - } - - } - - public static final class Entry { - - public final String name; - - T value; - - @ConstructorParameters({"name", "value"}) - public Entry(String name0, T value0) { - this.name = name0; - this.value = value0; - } - - public String getName() { - return name; - } - - public T getValue() { - return value; - } - - static String[] getStringValues(BiPredicate comparison, Entry[] entitys, String name) { - int len = 0; - for (Entry en : entitys) { - if (comparison.test(en.name, name)) { - ++len; - } - } - if (len == 0) return new String[len]; - String[] rs = new String[len]; - int i = 0; - for (Entry en : entitys) { - if (comparison.test(en.name, name)) { - rs[i++] = en.value; - } - } - return rs; - } - - static AnyValue[] getAnyValueValues(BiPredicate comparison, Entry[] entitys, String name) { - int len = 0; - for (Entry en : entitys) { - if (comparison.test(en.name, name)) { - ++len; - } - } - if (len == 0) return new AnyValue[len]; - AnyValue[] rs = new AnyValue[len]; - int i = 0; - for (Entry en : entitys) { - if (comparison.test(en.name, name)) { - rs[i++] = en.value; - } - } - return rs; - } - - static String[] getStringValues(BiPredicate comparison, Entry[] entitys, String... names) { - int len = 0; - for (Entry en : entitys) { - for (String name : names) { - if (comparison.test(en.name, name)) { - ++len; - break; - } - } - } - if (len == 0) return new String[len]; - String[] rs = new String[len]; - int i = 0; - for (Entry en : entitys) { - for (String name : names) { - if (comparison.test(en.name, name)) { - rs[i++] = en.value; - break; - } - } - } - return rs; - } - - static AnyValue[] getAnyValueValues(BiPredicate comparison, Entry[] entitys, String... names) { - int len = 0; - for (Entry en : entitys) { - for (String name : names) { - if (comparison.test(en.name, name)) { - ++len; - break; - } - } - } - if (len == 0) return new AnyValue[len]; - AnyValue[] rs = new AnyValue[len]; - int i = 0; - for (Entry en : entitys) { - for (String name : names) { - if (comparison.test(en.name, name)) { - rs[i++] = en.value; - break; - } - } - } - return rs; - } - } - - public static DefaultAnyValue create() { - return new DefaultAnyValue(); - } - - public static AnyValue loadFromXml(String text) throws IOException { - return new XmlReader(text).read(); - } - - public static AnyValue loadFromXml(InputStream in) throws IOException { - return loadFromXml(in, StandardCharsets.UTF_8); - } - - public static AnyValue loadFromXml(InputStream in, Charset charset) throws IOException { - return new XmlReader(Utility.read(in, charset)).read(); - } - - public static AnyValue loadFromXml(String text, BiFunction attrFunc) throws IOException { - return new XmlReader(text).attrFunc(attrFunc).read(); - } - - public static AnyValue loadFromXml(InputStream in, BiFunction attrFunc) throws IOException { - return loadFromXml(in, StandardCharsets.UTF_8, attrFunc); - } - - public static AnyValue loadFromXml(InputStream in, Charset charset, BiFunction attrFunc) throws IOException { - return new XmlReader(Utility.read(in, charset)).attrFunc(attrFunc).read(); - } - - public String toString(int indent) { //indent: 缂╄繘闀垮害 - if (indent < 0) indent = 0; - char[] chars = new char[indent]; - Arrays.fill(chars, ' '); - final String space = new String(chars); - StringBuilder sb = new StringBuilder(); - sb.append("{\r\n"); - for (Entry en : getStringEntrys()) { - sb.append(space).append(" '").append(en.name).append("': '").append(en.value).append("',\r\n"); - } - for (Entry en : getAnyEntrys()) { - sb.append(space).append(" '").append(en.name).append("': '").append(en.value.toString(indent + 4)).append("',\r\n"); - } - sb.append(space).append('}'); - return sb.toString(); - } - - public abstract void forEach(BiConsumer stringConsumer); - - public abstract void forEach(BiConsumer stringConsumer, BiConsumer anyConsumer); - - public abstract Entry[] getStringEntrys(); - - public abstract Entry[] getAnyEntrys(); - - public abstract String[] getNames(); - - public abstract String[] getValues(String name); - - public abstract String[] getValues(String... names); - - public abstract AnyValue[] getAnyValues(String name); - - public abstract AnyValue[] getAnyValues(String... names); - - public abstract AnyValue getAnyValue(String name); - - public abstract String getValue(String name); - - public abstract String get(String name); - - public boolean getBoolValue(String name) { - return Boolean.parseBoolean(getValue(name)); - } - - public boolean getBoolValue(String name, boolean defaultValue) { - String value = getValue(name); - return value == null || value.length() == 0 ? defaultValue : Boolean.parseBoolean(value); - } - - public byte getByteValue(String name) { - return Byte.parseByte(getValue(name)); - } - - public byte getByteValue(String name, byte defaultValue) { - String value = getValue(name); - if (value == null || value.length() == 0) return defaultValue; - try { - return Byte.decode(value); - } catch (NumberFormatException e) { - return defaultValue; - } - } - - public byte getByteValue(int radix, String name, byte defaultValue) { - String value = getValue(name); - if (value == null || value.length() == 0) return defaultValue; - try { - return (radix == 10 ? Byte.decode(value) : Byte.parseByte(value, radix)); - } catch (NumberFormatException e) { - return defaultValue; - } - } - - public char getCharValue(String name) { - return getValue(name).charAt(0); - } - - public char getCharValue(String name, char defaultValue) { - String value = getValue(name); - return value == null || value.length() == 0 ? defaultValue : value.charAt(0); - } - - public short getShortValue(String name) { - return Short.decode(getValue(name)); - } - - public short getShortValue(String name, short defaultValue) { - String value = getValue(name); - if (value == null || value.length() == 0) return defaultValue; - try { - return Short.decode(value); - } catch (NumberFormatException e) { - return defaultValue; - } - } - - public short getShortValue(int radix, String name, short defaultValue) { - String value = getValue(name); - if (value == null || value.length() == 0) return defaultValue; - try { - return (radix == 10 ? Short.decode(value) : Short.parseShort(value, radix)); - } catch (NumberFormatException e) { - return defaultValue; - } - } - - public int getIntValue(String name) { - return Integer.decode(getValue(name)); - } - - public int getIntValue(String name, int defaultValue) { - String value = getValue(name); - if (value == null || value.length() == 0) return defaultValue; - try { - return Integer.decode(value); - } catch (NumberFormatException e) { - return defaultValue; - } - } - - public int getIntValue(int radix, String name, int defaultValue) { - String value = getValue(name); - if (value == null || value.length() == 0) return defaultValue; - try { - return (radix == 10 ? Integer.decode(value) : Integer.parseInt(value, radix)); - } catch (NumberFormatException e) { - return defaultValue; - } - } - - public long getLongValue(String name) { - return Long.decode(getValue(name)); - } - - public long getLongValue(String name, long defaultValue) { - String value = getValue(name); - if (value == null || value.length() == 0) return defaultValue; - try { - return Long.decode(value); - } catch (NumberFormatException e) { - return defaultValue; - } - } - - public long getLongValue(int radix, String name, long defaultValue) { - String value = getValue(name); - if (value == null || value.length() == 0) return defaultValue; - try { - return (radix == 10 ? Long.decode(value) : Long.parseLong(value, radix)); - } catch (NumberFormatException e) { - return defaultValue; - } - } - - public float getFloatValue(String name) { - return Float.parseFloat(getValue(name)); - } - - public float getFloatValue(String name, float defaultValue) { - String value = getValue(name); - if (value == null || value.length() == 0) return defaultValue; - try { - return Float.parseFloat(value); - } catch (NumberFormatException e) { - return defaultValue; - } - } - - public double getDoubleValue(String name) { - return Double.parseDouble(getValue(name)); - } - - public double getDoubleValue(String name, double defaultValue) { - String value = getValue(name); - if (value == null || value.length() == 0) return defaultValue; - try { - return Double.parseDouble(value); - } catch (NumberFormatException e) { - return defaultValue; - } - } - - public String getValue(String name, String defaultValue) { - String value = getValue(name); - return value == null ? defaultValue : value; - } - - public String getOrDefault(String name, String defaultValue) { - String value = getValue(name); - return value == null ? defaultValue : value; - } - - @Override - public boolean equals(Object other) { - if (!(other instanceof AnyValue)) return false; - AnyValue conf = (AnyValue) other; - if (!equals(this.getStringEntrys(), conf.getStringEntrys())) return false; - return equals(this.getAnyEntrys(), conf.getAnyEntrys()); - } - - private static boolean equals(Entry[] entry1, Entry[] entry2) { - if ((entry1 == null || entry1.length == 0) && (entry2 == null || entry2.length == 0)) return true; - if (entry1.length != entry2.length) return false; - for (int i = 0; i < entry1.length; i++) { - if (!entry1[i].name.equals(entry2[i].name)) return false; - if (!entry1[i].getValue().equals(entry2[i].getValue())) return false; - } - return true; - } - - @Override - public int hashCode() { - int hash = 7; - hash = 19 * hash + Arrays.deepHashCode(this.getStringEntrys()); - hash = 19 * hash + Arrays.deepHashCode(this.getAnyEntrys()); - return hash; - } - - public String toXML(String rootName) { - return toXMLString(new StringBuilder("\r\n\r\n"), rootName, this, 0).toString(); - } - - protected static StringBuilder toXMLString(StringBuilder sb, String nodeName, AnyValue conf, int indent) { //indent: 缂╄繘闀垮害 - if (indent < 0) indent = 0; - char[] chars = new char[indent]; - Arrays.fill(chars, ' '); - final String space = new String(chars); - Entry[] anys = conf.getAnyEntrys(); - sb.append(space).append('<').append(nodeName); - for (Entry en : conf.getStringEntrys()) { - sb.append(' ').append(en.name).append("=\"").append(en.value).append("\""); - } - if (anys == null || anys.length == 0) return sb.append("/>\r\n\r\n"); - sb.append(">\r\n\r\n"); - for (Entry en : conf.getAnyEntrys()) { - toXMLString(sb, en.name, en.getValue(), indent + 4); - } - return sb.append(space).append("\r\n\r\n"); - } - -} +/* + * 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.util; + +import java.io.*; +import java.nio.charset.*; +import java.util.*; +import java.util.function.*; +import org.redkale.convert.ConvertDisabled; + +/** + * 璇ョ被鎻愪緵绫讳技JSONObject鐨勬暟鎹粨鏋勶紝涓昏鐢ㄤ簬璇诲彇xml閰嶇疆鏂囦欢鍜宧ttp-header瀛樺偍 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@SuppressWarnings("unchecked") +public abstract class AnyValue { + + /** + * xml鐨勬枃鏈妭鐐筺ame + */ + public static final String XML_TEXT_NODE_NAME = ""; + + /** + * 鍙鍐欑殑AnyValue榛樿瀹炵幇绫 + * + * @author zhangjx + */ + @SuppressWarnings("unchecked") + public static final class DefaultAnyValue extends AnyValue { + + /** + * 鍖哄垎name澶у皬鍐欑殑姣旇緝绛栫暐 + * + */ + public static final BiPredicate EQUALS = (name1, name2) -> name1.equals(name2); + + /** + * 涓嶅尯鍒唍ame澶у皬鍐欑殑姣旇緝绛栫暐 + */ + public static final BiPredicate EQUALSIGNORE = (name1, name2) -> name1.equalsIgnoreCase(name2); + + private boolean ignoreCase; + + private BiPredicate predicate; + + private Entry[] stringEntrys = new Entry[0]; + + private Entry[] anyEntrys = new Entry[0]; + + /** + * 鍒涘缓绌虹殑DefaultAnyValue瀵硅薄 + * + * @return DefaultAnyValue瀵硅薄 + */ + public static final DefaultAnyValue create() { + return new DefaultAnyValue(); + } + + /** + * 鍒涘缓鍚玭ame-value鍊肩殑DefaultAnyValue瀵硅薄 + * + * @param name name + * @param value value鍊 + * + * @return DefaultAnyValue瀵硅薄 + */ + public static final DefaultAnyValue create(String name, Number value) { + DefaultAnyValue conf = new DefaultAnyValue(); + conf.addValue(name, value); + return conf; + } + + /** + * 鍒涘缓鍚玭ame-value鍊肩殑DefaultAnyValue瀵硅薄 + * + * @param name name + * @param value value鍊 + * + * @return DefaultAnyValue瀵硅薄 + */ + public static final DefaultAnyValue create(String name, String value) { + DefaultAnyValue conf = new DefaultAnyValue(); + conf.addValue(name, value); + return conf; + } + + /** + * 鍒涘缓鍚玭ame-value鍊肩殑DefaultAnyValue瀵硅薄 + * + * @param name name + * @param value value鍊 + * + * @return DefaultAnyValue瀵硅薄 + */ + public static final DefaultAnyValue create(String name, AnyValue value) { + DefaultAnyValue conf = new DefaultAnyValue(); + conf.addValue(name, value); + return conf; + } + + /** + * 鍒涘缓涓涓尯鍒嗗ぇ灏忓啓姣旇緝绛栫暐鐨凞efaultAnyValue瀵硅薄 + * + */ + public DefaultAnyValue() { + this(false); + } + + /** + * 鍒涘缓DefaultAnyValue瀵硅薄 + * + * @param ignoreCase name鏄惁涓嶅尯鍒嗗ぇ灏忓啓 + */ + public DefaultAnyValue(boolean ignoreCase) { + this.ignoreCase = ignoreCase; + this.predicate = ignoreCase ? EQUALSIGNORE : EQUALS; + } + + /** + * 鍒涘缓鍏变韩姝ゅ唴瀹圭殑DefaultAnyValue瀵硅薄 + * + * @return DefaultAnyValue瀵硅薄 + */ + public DefaultAnyValue duplicate() { + DefaultAnyValue rs = new DefaultAnyValue(this.ignoreCase); + rs.stringEntrys = this.stringEntrys; + rs.anyEntrys = this.anyEntrys; + return rs; + } + + //鍘婚噸 + public DefaultAnyValue addAllStringSet(final AnyValue av) { + if (av == null) return this; + final Entry[] strings = av.getStringEntrys(); + if (strings == null) return this; + for (Entry en : strings) { + if (getValue(en.name) == null) this.addValue(en.name, en.value); + } + return this; + } + + public DefaultAnyValue addAll(final AnyValue av) { + if (av == null) return this; + if (av instanceof DefaultAnyValue) { + final DefaultAnyValue adv = (DefaultAnyValue) av; + if (adv.stringEntrys != null) { + for (Entry en : adv.stringEntrys) { + this.addValue(en.name, en.value); + } + } + if (adv.anyEntrys != null) { + for (Entry en : adv.anyEntrys) { + this.addValue(en.name, en.value); + } + } + } else { + final Entry[] strings = av.getStringEntrys(); + if (strings != null) { + for (Entry en : strings) { + this.addValue(en.name, en.value); + } + } + final Entry[] anys = av.getAnyEntrys(); + if (anys != null) { + for (Entry en : anys) { + this.addValue(en.name, en.value); + } + } + } + return this; + } + + public DefaultAnyValue setAll(final AnyValue av) { + if (av == null) return this; + if (av instanceof DefaultAnyValue) { + final DefaultAnyValue adv = (DefaultAnyValue) av; + if (adv.stringEntrys != null) { + for (Entry en : adv.stringEntrys) { + this.setValue(en.name, en.value); + } + } + if (adv.anyEntrys != null) { + for (Entry en : adv.anyEntrys) { + this.setValue(en.name, en.value); + } + } + } else { + final Entry[] strings = av.getStringEntrys(); + if (strings != null) { + for (Entry en : strings) { + this.setValue(en.name, en.value); + } + } + final Entry[] anys = av.getAnyEntrys(); + if (anys != null) { + for (Entry en : anys) { + this.setValue(en.name, en.value); + } + } + } + return this; + } + + @Override + public void forEach(BiConsumer stringConsumer) { + forEach(stringConsumer, null); + } + + @Override + public void forEach(BiConsumer stringConsumer, BiConsumer anyConsumer) { + if (stringConsumer != null) { + for (Entry en : stringEntrys) { + stringConsumer.accept(en.name, en.value); + } + } + if (anyConsumer != null) { + for (Entry en : (Entry[]) anyEntrys) { + anyConsumer.accept(en.name, en.value); + } + } + } + + @Override + public Entry[] getStringEntrys() { + return stringEntrys; + } + + public void setStringEntrys(Entry[] stringEntrys) { + this.stringEntrys = stringEntrys; + } + + @Override + public Entry[] getAnyEntrys() { + return (Entry[]) (Entry[]) anyEntrys; + } + + public void setAnyEntrys(Entry[] anyEntrys) { + this.anyEntrys = anyEntrys; + } + + public boolean isIgnoreCase() { + return ignoreCase; + } + + public void setIgnoreCase(boolean ignoreCase) { + this.ignoreCase = ignoreCase; + if (this.predicate == null) { + this.predicate = ignoreCase ? EQUALSIGNORE : EQUALS; + } + } + + @Override + @ConvertDisabled + public String[] getNames() { + Set set = new LinkedHashSet<>(); + for (Entry en : this.stringEntrys) { + set.add(en.name); + } + for (Entry en : this.anyEntrys) { + set.add(en.name); + } + return set.toArray(new String[set.size()]); + } + + @Override + public String[] getValues(String... names) { + return Entry.getStringValues(this.predicate, this.stringEntrys, names); + } + + @Override + public AnyValue[] getAnyValues(String... names) { + return Entry.getAnyValueValues(this.predicate, this.anyEntrys, names); + } + + @Override + public String[] getValues(String name) { + return Entry.getStringValues(this.predicate, this.stringEntrys, name); + } + + @Override + public AnyValue[] getAnyValues(String name) { + return Entry.getAnyValueValues(this.predicate, this.anyEntrys, name); + } + + @Override + public String toString() { + return toString(0); + } + + public DefaultAnyValue clear() { + if (this.stringEntrys != null && this.stringEntrys.length > 0) this.stringEntrys = new Entry[0]; + if (this.anyEntrys != null && this.anyEntrys.length > 0) this.anyEntrys = new Entry[0]; + return this; + } + + public DefaultAnyValue setValue(String name, String value) { + if (name == null) return this; + if (getValue(name) == null) { + this.addValue(name, value); + } else { + for (Entry en : this.stringEntrys) { + if (predicate.test(en.name, name)) { + en.value = value; + return this; + } + } + } + return this; + } + + public DefaultAnyValue setValue(String name, AnyValue value) { + if (name == null) return this; + if (getValue(name) == null) { + this.addValue(name, value); + } else { + for (Entry en : this.anyEntrys) { + if (predicate.test(en.name, name)) { + en.value = (DefaultAnyValue) value; + return this; + } + } + } + return this; + } + + public DefaultAnyValue put(String name, boolean value) { + return addValue(name, String.valueOf(value)); + } + + public DefaultAnyValue put(String name, Number value) { + return addValue(name, String.valueOf(value)); + } + + public DefaultAnyValue put(String name, String value) { + this.stringEntrys = Utility.append(this.stringEntrys, new Entry(name, value)); + return this; + } + + public DefaultAnyValue addValue(String name, boolean value) { + return addValue(name, String.valueOf(value)); + } + + public DefaultAnyValue addValue(String name, Number value) { + return addValue(name, String.valueOf(value)); + } + + public DefaultAnyValue addValue(String name, String value) { + this.stringEntrys = Utility.append(this.stringEntrys, new Entry(name, value)); + return this; + } + + public DefaultAnyValue addValue(String name, AnyValue value) { + if (name == null || value == null) return this; + this.anyEntrys = Utility.append(this.anyEntrys, new Entry(name, value)); + return this; + } + + public DefaultAnyValue removeValue(String name, AnyValue value) { + if (name == null || value == null || this.anyEntrys == null) return this; + this.anyEntrys = Utility.remove(this.anyEntrys, (t) -> name.equals(((Entry) t).name) && ((Entry) t).getValue().equals(value)); + return this; + } + + public DefaultAnyValue removeValue(String name, String value) { + if (name == null || value == null || this.stringEntrys == null) return this; + this.stringEntrys = Utility.remove(this.stringEntrys, (t) -> name.equals(((Entry) t).name) && ((Entry) t).getValue().equals(value)); + return this; + } + + @Override + public AnyValue getAnyValue(String name) { + for (Entry en : this.anyEntrys) { + if (predicate.test(en.name, name)) { + return en.value; + } + } + return null; + } + + @Override + public String get(String name) { + return getValue(name); + } + + @Override + public String getValue(String name) { + for (Entry en : this.stringEntrys) { + if (predicate.test(en.name, name)) { + return en.value; + } + } + return null; + } + + } + + public static final class Entry { + + public final String name; + + T value; + + @ConstructorParameters({"name", "value"}) + public Entry(String name0, T value0) { + this.name = name0; + this.value = value0; + } + + public String getName() { + return name; + } + + public T getValue() { + return value; + } + + static String[] getStringValues(BiPredicate comparison, Entry[] entitys, String name) { + int len = 0; + for (Entry en : entitys) { + if (comparison.test(en.name, name)) { + ++len; + } + } + if (len == 0) return new String[len]; + String[] rs = new String[len]; + int i = 0; + for (Entry en : entitys) { + if (comparison.test(en.name, name)) { + rs[i++] = en.value; + } + } + return rs; + } + + static AnyValue[] getAnyValueValues(BiPredicate comparison, Entry[] entitys, String name) { + int len = 0; + for (Entry en : entitys) { + if (comparison.test(en.name, name)) { + ++len; + } + } + if (len == 0) return new AnyValue[len]; + AnyValue[] rs = new AnyValue[len]; + int i = 0; + for (Entry en : entitys) { + if (comparison.test(en.name, name)) { + rs[i++] = en.value; + } + } + return rs; + } + + static String[] getStringValues(BiPredicate comparison, Entry[] entitys, String... names) { + int len = 0; + for (Entry en : entitys) { + for (String name : names) { + if (comparison.test(en.name, name)) { + ++len; + break; + } + } + } + if (len == 0) return new String[len]; + String[] rs = new String[len]; + int i = 0; + for (Entry en : entitys) { + for (String name : names) { + if (comparison.test(en.name, name)) { + rs[i++] = en.value; + break; + } + } + } + return rs; + } + + static AnyValue[] getAnyValueValues(BiPredicate comparison, Entry[] entitys, String... names) { + int len = 0; + for (Entry en : entitys) { + for (String name : names) { + if (comparison.test(en.name, name)) { + ++len; + break; + } + } + } + if (len == 0) return new AnyValue[len]; + AnyValue[] rs = new AnyValue[len]; + int i = 0; + for (Entry en : entitys) { + for (String name : names) { + if (comparison.test(en.name, name)) { + rs[i++] = en.value; + break; + } + } + } + return rs; + } + } + + public static DefaultAnyValue create() { + return new DefaultAnyValue(); + } + + public static AnyValue loadFromXml(String text) throws IOException { + return new XmlReader(text).read(); + } + + public static AnyValue loadFromXml(InputStream in) throws IOException { + return loadFromXml(in, StandardCharsets.UTF_8); + } + + public static AnyValue loadFromXml(InputStream in, Charset charset) throws IOException { + return new XmlReader(Utility.read(in, charset)).read(); + } + + public static AnyValue loadFromXml(String text, BiFunction attrFunc) throws IOException { + return new XmlReader(text).attrFunc(attrFunc).read(); + } + + public static AnyValue loadFromXml(InputStream in, BiFunction attrFunc) throws IOException { + return loadFromXml(in, StandardCharsets.UTF_8, attrFunc); + } + + public static AnyValue loadFromXml(InputStream in, Charset charset, BiFunction attrFunc) throws IOException { + return new XmlReader(Utility.read(in, charset)).attrFunc(attrFunc).read(); + } + + public String toString(int indent) { //indent: 缂╄繘闀垮害 + if (indent < 0) indent = 0; + char[] chars = new char[indent]; + Arrays.fill(chars, ' '); + final String space = new String(chars); + StringBuilder sb = new StringBuilder(); + sb.append("{\r\n"); + for (Entry en : getStringEntrys()) { + sb.append(space).append(" '").append(en.name).append("': '").append(en.value).append("',\r\n"); + } + for (Entry en : getAnyEntrys()) { + sb.append(space).append(" '").append(en.name).append("': '").append(en.value.toString(indent + 4)).append("',\r\n"); + } + sb.append(space).append('}'); + return sb.toString(); + } + + public abstract void forEach(BiConsumer stringConsumer); + + public abstract void forEach(BiConsumer stringConsumer, BiConsumer anyConsumer); + + public abstract Entry[] getStringEntrys(); + + public abstract Entry[] getAnyEntrys(); + + public abstract String[] getNames(); + + public abstract String[] getValues(String name); + + public abstract String[] getValues(String... names); + + public abstract AnyValue[] getAnyValues(String name); + + public abstract AnyValue[] getAnyValues(String... names); + + public abstract AnyValue getAnyValue(String name); + + public abstract String getValue(String name); + + public abstract String get(String name); + + public boolean getBoolValue(String name) { + return Boolean.parseBoolean(getValue(name)); + } + + public boolean getBoolValue(String name, boolean defaultValue) { + String value = getValue(name); + return value == null || value.length() == 0 ? defaultValue : Boolean.parseBoolean(value); + } + + public byte getByteValue(String name) { + return Byte.parseByte(getValue(name)); + } + + public byte getByteValue(String name, byte defaultValue) { + String value = getValue(name); + if (value == null || value.length() == 0) return defaultValue; + try { + return Byte.decode(value); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + public byte getByteValue(int radix, String name, byte defaultValue) { + String value = getValue(name); + if (value == null || value.length() == 0) return defaultValue; + try { + return (radix == 10 ? Byte.decode(value) : Byte.parseByte(value, radix)); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + public char getCharValue(String name) { + return getValue(name).charAt(0); + } + + public char getCharValue(String name, char defaultValue) { + String value = getValue(name); + return value == null || value.length() == 0 ? defaultValue : value.charAt(0); + } + + public short getShortValue(String name) { + return Short.decode(getValue(name)); + } + + public short getShortValue(String name, short defaultValue) { + String value = getValue(name); + if (value == null || value.length() == 0) return defaultValue; + try { + return Short.decode(value); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + public short getShortValue(int radix, String name, short defaultValue) { + String value = getValue(name); + if (value == null || value.length() == 0) return defaultValue; + try { + return (radix == 10 ? Short.decode(value) : Short.parseShort(value, radix)); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + public int getIntValue(String name) { + return Integer.decode(getValue(name)); + } + + public int getIntValue(String name, int defaultValue) { + String value = getValue(name); + if (value == null || value.length() == 0) return defaultValue; + try { + return Integer.decode(value); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + public int getIntValue(int radix, String name, int defaultValue) { + String value = getValue(name); + if (value == null || value.length() == 0) return defaultValue; + try { + return (radix == 10 ? Integer.decode(value) : Integer.parseInt(value, radix)); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + public long getLongValue(String name) { + return Long.decode(getValue(name)); + } + + public long getLongValue(String name, long defaultValue) { + String value = getValue(name); + if (value == null || value.length() == 0) return defaultValue; + try { + return Long.decode(value); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + public long getLongValue(int radix, String name, long defaultValue) { + String value = getValue(name); + if (value == null || value.length() == 0) return defaultValue; + try { + return (radix == 10 ? Long.decode(value) : Long.parseLong(value, radix)); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + public float getFloatValue(String name) { + return Float.parseFloat(getValue(name)); + } + + public float getFloatValue(String name, float defaultValue) { + String value = getValue(name); + if (value == null || value.length() == 0) return defaultValue; + try { + return Float.parseFloat(value); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + public double getDoubleValue(String name) { + return Double.parseDouble(getValue(name)); + } + + public double getDoubleValue(String name, double defaultValue) { + String value = getValue(name); + if (value == null || value.length() == 0) return defaultValue; + try { + return Double.parseDouble(value); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + public String getValue(String name, String defaultValue) { + String value = getValue(name); + return value == null ? defaultValue : value; + } + + public String getOrDefault(String name, String defaultValue) { + String value = getValue(name); + return value == null ? defaultValue : value; + } + + @Override + public boolean equals(Object other) { + if (!(other instanceof AnyValue)) return false; + AnyValue conf = (AnyValue) other; + if (!equals(this.getStringEntrys(), conf.getStringEntrys())) return false; + return equals(this.getAnyEntrys(), conf.getAnyEntrys()); + } + + private static boolean equals(Entry[] entry1, Entry[] entry2) { + if ((entry1 == null || entry1.length == 0) && (entry2 == null || entry2.length == 0)) return true; + if (entry1.length != entry2.length) return false; + for (int i = 0; i < entry1.length; i++) { + if (!entry1[i].name.equals(entry2[i].name)) return false; + if (!entry1[i].getValue().equals(entry2[i].getValue())) return false; + } + return true; + } + + @Override + public int hashCode() { + int hash = 7; + hash = 19 * hash + Arrays.deepHashCode(this.getStringEntrys()); + hash = 19 * hash + Arrays.deepHashCode(this.getAnyEntrys()); + return hash; + } + + public String toXML(String rootName) { + return toXMLString(new StringBuilder("\r\n\r\n"), rootName, this, 0).toString(); + } + + protected static StringBuilder toXMLString(StringBuilder sb, String nodeName, AnyValue conf, int indent) { //indent: 缂╄繘闀垮害 + if (indent < 0) indent = 0; + char[] chars = new char[indent]; + Arrays.fill(chars, ' '); + final String space = new String(chars); + Entry[] anys = conf.getAnyEntrys(); + sb.append(space).append('<').append(nodeName); + for (Entry en : conf.getStringEntrys()) { + sb.append(' ').append(en.name).append("=\"").append(en.value).append("\""); + } + if (anys == null || anys.length == 0) return sb.append("/>\r\n\r\n"); + sb.append(">\r\n\r\n"); + for (Entry en : conf.getAnyEntrys()) { + toXMLString(sb, en.name, en.getValue(), indent + 4); + } + return sb.append(space).append("\r\n\r\n"); + } + +} diff --git a/src/main/java/org/redkale/util/Attribute.java b/src/main/java/org/redkale/util/Attribute.java index f4a4bc193..4070e7965 100644 --- a/src/main/java/org/redkale/util/Attribute.java +++ b/src/main/java/org/redkale/util/Attribute.java @@ -1,1115 +1,1115 @@ -/* - * 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.util; - -import java.lang.reflect.TypeVariable; -import java.util.*; -import java.util.function.*; -import org.redkale.asm.*; -import static org.redkale.asm.ClassWriter.COMPUTE_FRAMES; -import static org.redkale.asm.Opcodes.*; - -/** - * 璇ョ被瀹炵幇鍔ㄦ佹槧灏勪竴涓狫avaBean绫讳腑鎴愬憳瀵瑰簲鐨刧etter銆乻etter鏂规硶锛 浠f浛浣庢晥鐨勫弽灏勫疄鐜版柟寮忋 - *

- *  public class Record {
- *
- *      private String name;
- *
- *      public String getName() {
- *          return name;
- *      }
- *
- *      public void setName(String name) {
- *          this.name = name;
- *      }
- *  }
- * 
- * 鑾峰彇name鐨 Attribute 锛 - *
- *  Attribute<Record, String> nameAction = Attribute.create(Record.class.getDeclaredField("name"));
- * 
- * 绛変环浜: - *
- *  Attribute<Record, String> nameAction = new Attribute<Record, String>() {
- *
- *      private java.lang.reflect.Type _gtype = String.class;
- *
- *      private java.lang.Object _attach;
- *
- *      @Override
- *      public String field() {
- *          return "name";
- *      }
- *
- *      @Override
- *      public String get(Record obj) {
- *          return obj.getName();
- *      }
- *
- *      @Override
- *      public void set(Record obj, String value) {
- *          obj.setName(value);
- *      }
- *
- *      @Override
- *      public Class type() {
- *          return String.class;
- *      }
- *
- *      @Override
- *      public java.lang.reflect.Type genericType() {
- *          return _gtype;
- *      }
- *
- *      @Override
- *      public Object attach() {
- *          return _attach;
- *      }
- *
- *      @Override
- *      public Class declaringClass() {
- *          return Record.class;
- *      }
- *  };
- * 
- *

- * 鏄犲皠Field鏃讹紝field蹇呴』婊¤冻浠ヤ笅鏉′欢涔嬩竴锛
- * 1銆乫ield灞炴ф槸public涓旈潪final
- * 2銆佽嚦灏戝瓨鍦ㄥ搴旂殑getter銆乻etter鏂规硶涓殑涓涓
- * 褰撲笉瀛樺湪getter鏂规硶鏃讹紝get鎿嶄綔鍥哄畾杩斿洖null
- * 褰撲笉瀛樺湪setter鏂规硶鏃讹紝set鎿嶄綔涓虹┖鏂规硶
- *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param 瀛楁渚濋檮鐨勭被 - * @param 瀛楁鐨勬暟鎹被鍨 - */ -@SuppressWarnings("unchecked") -public interface Attribute { - - /** - * 杩斿洖瀛楁鐨勬暟鎹被鍨 - * - * @return 瀛楁鐨勬暟鎹被鍨 - */ - public Class type(); - - /** - * 杩斿洖瀛楁鐨勬暟鎹硾鍨 - * - * @return 瀛楁鐨勬暟鎹硾鍨 - */ - default java.lang.reflect.Type genericType() { - return type(); - } - - /** - * 杩斿洖瀛楁渚濋檮鐨勭被鍚 - * - * @return 渚濋檮鐨勭被鍚 - */ - public Class declaringClass(); - - /** - * 杩斿洖瀛楁鍚 - * - * @return 瀛楁鍚 - */ - public String field(); - - /** - * 鑾峰彇鎸囧畾瀵硅薄鐨勮瀛楁鐨勫 - * - * @param obj 鎸囧畾瀵硅薄 - * - * @return 瀛楁鐨勫 - */ - public F get(T obj); - - /** - * 缁欐寚瀹氬璞$殑璇ュ瓧娈佃祴鍊 - * - * @param obj 鎸囧畾瀵硅薄 - * @param value 瀛楁鏂板 - */ - public void set(T obj, F value); - - /** - * 闄勫姞瀵硅薄 - * - * @param 娉涘瀷 - * - * @return 闄勫姞瀵硅薄 - */ - default E attach() { - return null; - } - - /** - * 鏍规嵁涓涓狥ield鐢熸垚 Attribute 瀵硅薄銆 - * - * @param 渚濋檮绫荤殑绫诲瀷 - * @param 瀛楁绫诲瀷 - * @param field 瀛楁锛屽鏋滆瀛楁涓嶅瓨鍦ㄥ垯鎶涘紓甯 - * - * @return Attribute瀵硅薄 - */ - @SuppressWarnings("unchecked") - public static Attribute create(final java.lang.reflect.Field field) { - return create((Class) field.getDeclaringClass(), field.getName(), (Class) null, field, (java.lang.reflect.Method) null, (java.lang.reflect.Method) null, null); - } - - /** - * 鏍规嵁涓涓狥ield鐢熸垚 Attribute 瀵硅薄銆 - * - * @param 渚濋檮绫荤殑绫诲瀷 - * @param 瀛楁绫诲瀷 - * @param field 瀛楁锛屽鏋滆瀛楁涓嶅瓨鍦ㄥ垯鎶涘紓甯 - * @param attach 闄勫姞瀵硅薄 - * - * @return Attribute瀵硅薄 - */ - @SuppressWarnings("unchecked") - public static Attribute create(final java.lang.reflect.Field field, Object attach) { - return create((Class) field.getDeclaringClass(), field.getName(), (Class) null, field, (java.lang.reflect.Method) null, (java.lang.reflect.Method) null, attach); - } - - /** - * 鏍规嵁涓涓狥ield鍜宖ield鐨勫埆鍚嶇敓鎴 Attribute 瀵硅薄銆 - * - * @param 渚濋檮绫荤殑绫诲瀷 - * @param 瀛楁绫诲瀷 - * @param fieldalias 鍒悕 - * @param field 瀛楁锛屽鏋滆瀛楁涓嶅瓨鍦ㄥ垯鎶涘紓甯 - * - * @return Attribute瀵硅薄 - */ - @SuppressWarnings("unchecked") - public static Attribute create(String fieldalias, final java.lang.reflect.Field field) { - return create((Class) field.getDeclaringClass(), fieldalias, (Class) null, field, (java.lang.reflect.Method) null, (java.lang.reflect.Method) null, null); - } - - /** - * 鏍规嵁涓涓狥ield鍜宖ield鐨勫埆鍚嶇敓鎴 Attribute 瀵硅薄銆 - * - * @param 渚濋檮绫荤殑绫诲瀷 - * @param 瀛楁绫诲瀷 - * @param fieldalias 鍒悕 - * @param field 瀛楁锛屽鏋滆瀛楁涓嶅瓨鍦ㄥ垯鎶涘紓甯 - * @param attach 闄勫姞瀵硅薄 - * - * @return Attribute瀵硅薄 - */ - @SuppressWarnings("unchecked") - public static Attribute create(String fieldalias, final java.lang.reflect.Field field, Object attach) { - return create((Class) field.getDeclaringClass(), fieldalias, (Class) null, field, (java.lang.reflect.Method) null, (java.lang.reflect.Method) null, attach); - } - - /** - * 鏍规嵁涓涓狢lass鍜宖ield鐪熷疄鍚嶇О鐢熸垚 Attribute 瀵硅薄銆 - * - * @param 渚濋檮绫荤殑绫诲瀷 - * @param 瀛楁绫诲瀷 - * @param clazz 鎸囧畾渚濋檮鐨勭被 - * @param fieldname 瀛楁鍚嶏紝濡傛灉璇ュ瓧娈典笉瀛樺湪鍒欐姏寮傚父 - * - * @return Attribute瀵硅薄 - */ - public static Attribute create(Class clazz, final String fieldname) { - try { - return create(clazz, fieldname, (Class) null, clazz.getDeclaredField(fieldname), (java.lang.reflect.Method) null, (java.lang.reflect.Method) null, null); - } catch (NoSuchFieldException | SecurityException ex) { - throw new RuntimeException(ex); - } - } - - /** - * 鏍规嵁涓涓狢lass鍜宖ield鐪熷疄鍚嶇О鐢熸垚 Attribute 瀵硅薄銆 - * - * @param 渚濋檮绫荤殑绫诲瀷 - * @param 瀛楁绫诲瀷 - * @param clazz 鎸囧畾渚濋檮鐨勭被 - * @param fieldname 瀛楁鍚嶏紝濡傛灉璇ュ瓧娈典笉瀛樺湪鍒欐姏寮傚父 - * @param attach 闄勫姞瀵硅薄 - * - * @return Attribute瀵硅薄 - */ - public static Attribute create(Class clazz, final String fieldname, Object attach) { - try { - return create(clazz, fieldname, (Class) null, clazz.getDeclaredField(fieldname), (java.lang.reflect.Method) null, (java.lang.reflect.Method) null, attach); - } catch (NoSuchFieldException | SecurityException ex) { - throw new RuntimeException(ex); - } - } - - /** - * 鏍规嵁涓涓狢lass鍜孎ield鐢熸垚 Attribute 瀵硅薄銆 - * - * @param 渚濋檮绫荤殑绫诲瀷 - * @param 瀛楁绫诲瀷 - * @param clazz 鎸囧畾渚濋檮鐨勭被 - * @param field 瀛楁锛屽鏋滆瀛楁涓嶅瓨鍦ㄥ垯鎶涘紓甯 - * - * @return Attribute瀵硅薄 - */ - public static Attribute create(Class clazz, final java.lang.reflect.Field field) { - return create(clazz, field.getName(), (Class) null, field, (java.lang.reflect.Method) null, (java.lang.reflect.Method) null, null); - } - - /** - * 鏍规嵁涓涓狢lass鍜孎ield鐢熸垚 Attribute 瀵硅薄銆 - * - * @param 渚濋檮绫荤殑绫诲瀷 - * @param 瀛楁绫诲瀷 - * @param subclass 鎸囧畾渚濋檮鐨勫瓙绫 - * @param clazz 鎸囧畾渚濋檮鐨勭被 - * @param field 瀛楁锛屽鏋滆瀛楁涓嶅瓨鍦ㄥ垯鎶涘紓甯 - * - * @return Attribute瀵硅薄 - */ - public static Attribute create(Class subclass, Class clazz, final java.lang.reflect.Field field) { - return create(subclass, clazz, field.getName(), (Class) null, field, (java.lang.reflect.Method) null, (java.lang.reflect.Method) null, null); - } - - /** - * 鏍规嵁涓涓狢lass鍜孎ield鐢熸垚 Attribute 瀵硅薄銆 - * - * @param 渚濋檮绫荤殑绫诲瀷 - * @param 瀛楁绫诲瀷 - * @param clazz 鎸囧畾渚濋檮鐨勭被 - * @param field 瀛楁锛屽鏋滆瀛楁涓嶅瓨鍦ㄥ垯鎶涘紓甯 - * @param attach 闄勫姞瀵硅薄 - * - * @return Attribute瀵硅薄 - */ - public static Attribute create(Class clazz, final java.lang.reflect.Field field, Object attach) { - return create(clazz, field.getName(), (Class) null, field, (java.lang.reflect.Method) null, (java.lang.reflect.Method) null, attach); - } - - /** - * 鏍规嵁涓涓狢lass鍜孎ield鐢熸垚 Attribute 瀵硅薄銆 - * - * @param 渚濋檮绫荤殑绫诲瀷 - * @param 瀛楁绫诲瀷 - * @param subclass 鎸囧畾渚濋檮鐨勫瓙绫 - * @param clazz 鎸囧畾渚濋檮鐨勭被 - * @param field 瀛楁锛屽鏋滆瀛楁涓嶅瓨鍦ㄥ垯鎶涘紓甯 - * @param attach 闄勫姞瀵硅薄 - * - * @return Attribute瀵硅薄 - */ - public static Attribute create(Class subclass, Class clazz, final java.lang.reflect.Field field, Object attach) { - return create(subclass, clazz, field.getName(), (Class) null, field, (java.lang.reflect.Method) null, (java.lang.reflect.Method) null, attach); - } - - /** - * 鏍规嵁涓涓狢lass銆乫ield鍒悕鍜孎ield鐢熸垚 Attribute 瀵硅薄銆 - * - * @param 渚濋檮绫荤殑绫诲瀷 - * @param 瀛楁绫诲瀷 - * @param clazz 鎸囧畾渚濋檮鐨勭被 - * @param fieldalias 瀛楁鍒悕 - * @param field 瀛楁锛屽鏋滆瀛楁涓嶅瓨鍦ㄥ垯鎶涘紓甯 - * - * @return Attribute瀵硅薄 - */ - public static Attribute create(Class clazz, final String fieldalias, final java.lang.reflect.Field field) { - return create(clazz, fieldalias, (Class) null, field, (java.lang.reflect.Method) null, (java.lang.reflect.Method) null, null); - } - - /** - * 鏍规嵁涓涓狢lass銆乫ield鍒悕鍜孎ield鐢熸垚 Attribute 瀵硅薄銆 - * - * @param 渚濋檮绫荤殑绫诲瀷 - * @param 瀛楁绫诲瀷 - * @param clazz 鎸囧畾渚濋檮鐨勭被 - * @param fieldalias 瀛楁鍒悕 - * @param field 瀛楁锛屽鏋滆瀛楁涓嶅瓨鍦ㄥ垯鎶涘紓甯 - * @param attach 闄勫姞瀵硅薄 - * - * @return Attribute瀵硅薄 - */ - public static Attribute create(Class clazz, final String fieldalias, final java.lang.reflect.Field field, Object attach) { - return create(clazz, fieldalias, (Class) null, field, (java.lang.reflect.Method) null, (java.lang.reflect.Method) null, attach); - } - - /** - * 鏍规嵁涓涓猤etter鍜宻etter鏂规硶鐢熸垚 Attribute 瀵硅薄銆 tgetter銆乻etter涓嶈兘鍚屾椂涓簄ull - * - * @param 渚濋檮绫荤殑绫诲瀷 - * @param 瀛楁绫诲瀷 - * @param getter getter鏂规硶 - * @param setter setter鏂规硶 - * - * @return Attribute瀵硅薄 - */ - @SuppressWarnings("unchecked") - public static Attribute create(final java.lang.reflect.Method getter, final java.lang.reflect.Method setter) { - return create((Class) (getter == null ? setter.getDeclaringClass() : getter.getDeclaringClass()), (String) null, (Class) null, (java.lang.reflect.Field) null, getter, setter, null); - } - - /** - * 鏍规嵁涓涓猤etter鍜宻etter鏂规硶鐢熸垚 Attribute 瀵硅薄銆 tgetter銆乻etter涓嶈兘鍚屾椂涓簄ull - * - * @param 渚濋檮绫荤殑绫诲瀷 - * @param 瀛楁绫诲瀷 - * @param getter getter鏂规硶 - * @param setter setter鏂规硶 - * @param attach 闄勫姞瀵硅薄 - * - * @return Attribute瀵硅薄 - */ - @SuppressWarnings("unchecked") - public static Attribute create(final java.lang.reflect.Method getter, final java.lang.reflect.Method setter, Object attach) { - return create((Class) (getter == null ? setter.getDeclaringClass() : getter.getDeclaringClass()), (String) null, (Class) null, (java.lang.reflect.Field) null, getter, setter, attach); - } - - /** - * 鏍规嵁Class銆乬etter鍜宻etter鏂规硶鐢熸垚 Attribute 瀵硅薄銆 tgetter銆乻etter涓嶈兘鍚屾椂涓簄ull - * - * @param 渚濋檮绫荤殑绫诲瀷 - * @param 瀛楁绫诲瀷 - * @param clazz 鎸囧畾渚濋檮鐨勭被 - * @param getter getter鏂规硶 - * @param setter setter鏂规硶 - * - * @return Attribute瀵硅薄 - */ - public static Attribute create(Class clazz, final java.lang.reflect.Method getter, final java.lang.reflect.Method setter) { - return create(clazz, (String) null, (Class) null, (java.lang.reflect.Field) null, getter, setter, null); - } - - /** - * 鏍规嵁Class銆乬etter鍜宻etter鏂规硶鐢熸垚 Attribute 瀵硅薄銆 tgetter銆乻etter涓嶈兘鍚屾椂涓簄ull - * - * @param 渚濋檮绫荤殑绫诲瀷 - * @param 瀛楁绫诲瀷 - * @param clazz 鎸囧畾渚濋檮鐨勭被 - * @param getter getter鏂规硶 - * @param setter setter鏂规硶 - * @param attach 闄勫姞瀵硅薄 - * - * @return Attribute瀵硅薄 - */ - public static Attribute create(Class clazz, final java.lang.reflect.Method getter, final java.lang.reflect.Method setter, Object attach) { - return create(clazz, (String) null, (Class) null, (java.lang.reflect.Field) null, getter, setter, attach); - } - - /** - * 鏍规嵁Class鐢熸垚getter銆乻etter鏂规硶閮藉瓨鍦ㄧ殑瀛楁瀵瑰簲鐨 Attribute 瀵硅薄鏁扮粍銆 - * - * @param 渚濋檮绫荤殑绫诲瀷 - * @param clazz 鎸囧畾渚濋檮鐨勭被 - * - * @return Attribute瀵硅薄鏁扮粍 - */ - public static Attribute[] create(Class clazz) { - List> list = new ArrayList<>(); - RedkaleClassLoader.putReflectionPublicFields(clazz.getName()); - for (java.lang.reflect.Field field : clazz.getFields()) { - if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) continue; - if (java.lang.reflect.Modifier.isFinal(field.getModifiers())) continue; - list.add(create(clazz, field)); - } - RedkaleClassLoader.putReflectionDeclaredMethods(clazz.getName()); - for (java.lang.reflect.Method setter : clazz.getDeclaredMethods()) { - if (java.lang.reflect.Modifier.isStatic(setter.getModifiers())) continue; - if (!setter.getName().startsWith("set")) continue; - if (setter.getReturnType() != void.class) continue; - if (setter.getParameterCount() != 1) continue; - Class t = setter.getParameterTypes()[0]; - String prefix = t == boolean.class || t == Boolean.class ? "is" : "get"; - java.lang.reflect.Method getter = null; - try { - getter = clazz.getMethod(setter.getName().replaceFirst("set", prefix)); - } catch (Exception e) { - continue; - } - list.add(create(clazz, getter, setter)); - } - return list.toArray(new Attribute[list.size()]); - } - - /** - * 鏍规嵁Class鐢熸垚getter鏂规硶瀵瑰簲鐨 Attribute 瀵硅薄鏁扮粍銆 - * - * @param 渚濋檮绫荤殑绫诲瀷 - * @param clazz 鎸囧畾渚濋檮鐨勭被 - * - * @return Attribute瀵硅薄鏁扮粍 - */ - public static Attribute[] createGetters(Class clazz) { - List> list = new ArrayList<>(); - RedkaleClassLoader.putReflectionPublicFields(clazz.getName()); - for (java.lang.reflect.Field field : clazz.getFields()) { - if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) continue; - if (java.lang.reflect.Modifier.isFinal(field.getModifiers())) continue; - list.add(create(clazz, field)); - } - RedkaleClassLoader.putReflectionDeclaredMethods(clazz.getName()); - for (java.lang.reflect.Method method : clazz.getDeclaredMethods()) { - if (java.lang.reflect.Modifier.isStatic(method.getModifiers())) continue; - if (method.getReturnType() == void.class) continue; - if (method.getParameterCount() != 0) continue; - if (method.getName().equals("getClass")) continue; - if (method.getName().startsWith("get") || method.getName().startsWith("is") - || Utility.isRecordGetter(clazz, method)) { - list.add(create(clazz, method, null)); - } - } - return list.toArray(new Attribute[list.size()]); - } - - /** - * 鏍规嵁Class鐢熸垚setter鏂规硶瀵瑰簲鐨 Attribute 瀵硅薄鏁扮粍銆 - * - * @param 渚濋檮绫荤殑绫诲瀷 - * @param clazz 鎸囧畾渚濋檮鐨勭被 - * - * @return Attribute瀵硅薄鏁扮粍 - */ - public static Attribute[] createSetters(Class clazz) { - List> list = new ArrayList<>(); - RedkaleClassLoader.putReflectionPublicFields(clazz.getName()); - for (java.lang.reflect.Field field : clazz.getFields()) { - if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) continue; - if (java.lang.reflect.Modifier.isFinal(field.getModifiers())) continue; - list.add(create(clazz, field)); - } - RedkaleClassLoader.putReflectionDeclaredMethods(clazz.getName()); - for (java.lang.reflect.Method method : clazz.getDeclaredMethods()) { - if (java.lang.reflect.Modifier.isStatic(method.getModifiers())) continue; - if (!method.getName().startsWith("set")) continue; - if (method.getParameterCount() != 1) continue; - list.add(create(clazz, (java.lang.reflect.Method) null, method)); - } - return list.toArray(new Attribute[list.size()]); - } - - /** - * 鏍规嵁Class銆佸瓧娈靛埆鍚嶃乬etter鍜宻etter鏂规硶鐢熸垚 Attribute 瀵硅薄銆 tgetter銆乻etter涓嶈兘鍚屾椂涓簄ull - * - * @param 渚濋檮绫荤殑绫诲瀷 - * @param 瀛楁绫诲瀷 - * @param clazz 鎸囧畾渚濋檮鐨勭被 - * @param fieldalias 瀛楁鍒悕 - * @param getter getter鏂规硶 - * @param setter setter鏂规硶 - * - * @return Attribute瀵硅薄 - */ - public static Attribute create(Class clazz, final String fieldalias, final java.lang.reflect.Method getter, final java.lang.reflect.Method setter) { - return create(clazz, fieldalias, (Class) null, (java.lang.reflect.Field) null, getter, setter, null); - } - - /** - * 鏍规嵁Class銆佸瓧娈靛埆鍚嶃乬etter鍜宻etter鏂规硶鐢熸垚 Attribute 瀵硅薄銆 tgetter銆乻etter涓嶈兘鍚屾椂涓簄ull - * - * @param 渚濋檮绫荤殑绫诲瀷 - * @param 瀛楁绫诲瀷 - * @param clazz 鎸囧畾渚濋檮鐨勭被 - * @param fieldalias 瀛楁鍒悕 - * @param getter getter鏂规硶 - * @param setter setter鏂规硶 - * @param attach 闄勫姞瀵硅薄 - * - * @return Attribute瀵硅薄 - */ - public static Attribute create(Class clazz, final String fieldalias, final java.lang.reflect.Method getter, final java.lang.reflect.Method setter, Object attach) { - return create(clazz, fieldalias, (Class) null, (java.lang.reflect.Field) null, getter, setter, attach); - } - - /** - * 鏍规嵁Class銆佸瓧娈靛埆鍚嶃丗ield銆乬etter鍜宻etter鏂规硶鐢熸垚 Attribute 瀵硅薄銆 Field銆乼getter銆乻etter涓嶈兘鍚屾椂涓簄ull - * - * @param 渚濋檮绫荤殑绫诲瀷 - * @param 瀛楁绫诲瀷 - * @param clazz 鎸囧畾渚濋檮鐨勭被 - * @param fieldalias 瀛楁鍒悕 - * @param field 瀛楁 - * @param getter getter鏂规硶 - * @param setter setter鏂规硶 - * - * @return Attribute瀵硅薄 - */ - public static Attribute create(final Class clazz, String fieldalias, final java.lang.reflect.Field field, java.lang.reflect.Method getter, java.lang.reflect.Method setter) { - return create(clazz, fieldalias, (Class) null, field, getter, setter, null); - } - - /** - * 鏍规嵁Class銆佸瓧娈靛埆鍚嶃丗ield銆乬etter鍜宻etter鏂规硶鐢熸垚 Attribute 瀵硅薄銆 Field銆乼getter銆乻etter涓嶈兘鍚屾椂涓簄ull - * - * @param 渚濋檮绫荤殑绫诲瀷 - * @param 瀛楁绫诲瀷 - * @param clazz 鎸囧畾渚濋檮鐨勭被 - * @param fieldalias 瀛楁鍒悕 - * @param field 瀛楁 - * @param getter getter鏂规硶 - * @param setter setter鏂规硶 - * @param attach 闄勫姞瀵硅薄 - * - * @return Attribute瀵硅薄 - */ - public static Attribute create(final Class clazz, String fieldalias, final java.lang.reflect.Field field, java.lang.reflect.Method getter, java.lang.reflect.Method setter, Object attach) { - return create(clazz, fieldalias, (Class) null, field, getter, setter, attach); - } - - /** - * 鏍规嵁Class銆佸瓧娈靛埆鍚嶃佸瓧娈电被鍨嬬敓鎴愯櫄鏋勭殑 Attribute 瀵硅薄,get銆乻et鏂规硶涓虹┖鏂规硶銆 - * - * @param 渚濋檮绫荤殑绫诲瀷 - * @param 瀛楁绫诲瀷 - * @param clazz 鎸囧畾渚濋檮鐨勭被 - * @param fieldalias 瀛楁鍒悕 - * @param fieldtype 瀛楁鐨勭被 - * - * @return Attribute瀵硅薄 - */ - public static Attribute create(final Class clazz, String fieldalias, final Class fieldtype) { - return create(clazz, fieldalias, fieldtype, (java.lang.reflect.Type) null, (Function) null, (BiConsumer) null, null); - } - - /** - * 鏍规嵁Class銆佸瓧娈靛埆鍚嶃佸瓧娈电被鍨嬬敓鎴愯櫄鏋勭殑 Attribute 瀵硅薄,get銆乻et鏂规硶涓虹┖鏂规硶銆 - * - * @param 渚濋檮绫荤殑绫诲瀷 - * @param 瀛楁绫诲瀷 - * @param clazz 鎸囧畾渚濋檮鐨勭被 - * @param fieldalias 瀛楁鍒悕 - * @param fieldtype 瀛楁鐨勭被 - * @param attach 闄勫姞瀵硅薄 - * - * @return Attribute瀵硅薄 - */ - public static Attribute create(final Class clazz, String fieldalias, final Class fieldtype, Object attach) { - return create(clazz, fieldalias, fieldtype, (java.lang.reflect.Type) null, (Function) null, (BiConsumer) null, attach); - } - - /** - * 鏍规嵁Class銆佸瓧娈靛埆鍚嶃佸瓧娈电被鍨嬨丗ield銆乬etter鍜宻etter鏂规硶鐢熸垚 Attribute 瀵硅薄銆 fieldalias/fieldtype銆丗ield銆乼getter銆乻etter涓嶈兘鍚屾椂涓簄ull. - * - * @param 渚濋檮绫荤殑绫诲瀷 - * @param 瀛楁绫诲瀷 - * @param clazz 鎸囧畾渚濋檮鐨勭被 - * @param fieldalias 瀛楁鍒悕 - * @param fieldtype 瀛楁绫诲瀷 - * @param field 瀛楁 - * @param getter getter鏂规硶 - * @param setter setter鏂规硶 - * - * @return Attribute瀵硅薄 - */ - @SuppressWarnings("unchecked") - public static Attribute create(final Class clazz, String fieldalias, final Class fieldtype, final java.lang.reflect.Field field, java.lang.reflect.Method getter, java.lang.reflect.Method setter) { - return create(clazz, fieldalias, fieldtype, field, getter, setter, null); - } - - /** - * 鏍规嵁Class銆佸瓧娈靛埆鍚嶃佸瓧娈电被鍨嬨丗ield銆乬etter鍜宻etter鏂规硶鐢熸垚 Attribute 瀵硅薄銆 fieldalias/fieldtype銆丗ield銆乼getter銆乻etter涓嶈兘鍚屾椂涓簄ull. - * - * @param 渚濋檮绫荤殑绫诲瀷 - * @param 瀛楁绫诲瀷 - * @param clazz 鎸囧畾渚濋檮鐨勭被 - * @param fieldalias 瀛楁鍒悕 - * @param fieldtype 瀛楁绫诲瀷 - * @param field 瀛楁 - * @param getter getter鏂规硶 - * @param setter setter鏂规硶 - * @param attach 闄勫姞瀵硅薄 - * - * @return Attribute瀵硅薄 - */ - @SuppressWarnings("unchecked") - public static Attribute create(final Class clazz, String fieldalias, final Class fieldtype, final java.lang.reflect.Field field, java.lang.reflect.Method getter, java.lang.reflect.Method setter, Object attach) { - return create(null, clazz, fieldalias, fieldtype, field, getter, setter, attach); - } - - /** - * 鏍规嵁Class銆佸瓧娈靛埆鍚嶃佸瓧娈电被鍨嬨丗ield銆乬etter鍜宻etter鏂规硶鐢熸垚 Attribute 瀵硅薄銆 fieldalias/fieldtype銆丗ield銆乼getter銆乻etter涓嶈兘鍚屾椂涓簄ull. - * - * @param 渚濋檮绫荤殑绫诲瀷 - * @param 瀛楁绫诲瀷 - * @param subclass 鎸囧畾渚濋檮鐨勫瓙绫 - * @param clazz 鎸囧畾渚濋檮鐨勭被 - * @param fieldalias 瀛楁鍒悕 - * @param fieldtype 瀛楁绫诲瀷 - * @param field 瀛楁 - * @param getter getter鏂规硶 - * @param setter setter鏂规硶 - * @param attach 闄勫姞瀵硅薄 - * - * @return Attribute瀵硅薄 - */ - @SuppressWarnings("unchecked") - public static Attribute create(java.lang.reflect.Type subclass, final Class clazz, String fieldalias, final Class fieldtype, final java.lang.reflect.Field field, java.lang.reflect.Method getter, java.lang.reflect.Method setter, Object attach) { - if (subclass == null) subclass = clazz; - if (fieldalias != null && fieldalias.isEmpty()) fieldalias = null; - int mod = field == null ? java.lang.reflect.Modifier.STATIC : field.getModifiers(); - if (field != null && !java.lang.reflect.Modifier.isStatic(mod) && !java.lang.reflect.Modifier.isPublic(mod)) { - Class t = field.getType(); - char[] fs = field.getName().toCharArray(); - fs[0] = Character.toUpperCase(fs[0]); - String mn = new String(fs); - if (getter == null) { - String prefix = t == boolean.class || t == Boolean.class ? "is" : "get"; - try { - getter = clazz.getMethod(prefix + mn); - } catch (Exception ex) { - try { - java.lang.reflect.Method m = clazz.getMethod(field.getName()); - if (Utility.isRecordGetter(clazz, m) && field.getType() == m.getReturnType()) getter = m; - } catch (Exception ex2) { - } - } - } - if (setter == null) { - try { - setter = clazz.getMethod("set" + mn, field.getType()); - } catch (Exception ex) { - } - } - } - final java.lang.reflect.Field tfield = field == null ? null : (!java.lang.reflect.Modifier.isPublic(mod) || java.lang.reflect.Modifier.isStatic(mod) ? null : field); - final java.lang.reflect.Method tgetter = getter; - final java.lang.reflect.Method tsetter = setter; - String fieldkey = fieldalias; - if (fieldalias == null) { - if (field != null) { - fieldalias = field.getName(); - fieldkey = fieldalias; - } else { - String s = null; - if (getter != null) { - s = Utility.isRecordGetter(getter) ? getter.getName() : getter.getName().substring(getter.getName().startsWith("is") ? 2 : 3); - fieldkey = getter.getName(); - } else if (setter != null) { - s = setter.getName().substring(3); - fieldkey = setter.getName(); - } - if (s != null) { - char[] d = s.toCharArray(); - if (d.length < 2 || Character.isLowerCase(d[1])) { - d[0] = Character.toLowerCase(d[0]); - } - fieldalias = new String(d); - fieldkey = fieldalias; - } - } - } - if (getter != null) { //闃叉fieldname/getter/setter鍚嶅瓧鐩稿悓,鎵浠ュ姞涓1/2/3 - if (setter == null) { - fieldkey = (fieldalias == null ? "" : ("0_" + fieldalias + "_")) + "1_" + getter.getName(); - } else { - fieldkey = (fieldalias == null ? "" : ("0_" + fieldalias + "_")) + "3_" + getter.getName() + "_" + setter.getName(); - } - } else if (setter != null) { - fieldkey = (fieldalias == null ? "" : ("0_" + fieldalias + "_")) + "2_" + setter.getName(); - } - if (fieldalias == null && fieldtype == null && tgetter == null && tsetter == null && tfield == null) { - throw new RuntimeException("[" + clazz + "]have no public field or setter or getter"); - } - final String fieldname = fieldalias; - Class column = fieldtype; - java.lang.reflect.Type generictype = fieldtype; - if (tfield != null) { // public tfield - column = tfield.getType(); - generictype = tfield.getGenericType(); - } else if (tgetter != null) { - column = tgetter.getReturnType(); - generictype = tgetter.getGenericReturnType(); - } else if (tsetter != null) { - column = tsetter.getParameterTypes()[0]; - generictype = tsetter.getGenericParameterTypes()[0]; - } else if (fieldtype == null) { - throw new RuntimeException("[" + clazz + "]have no public field or setter or getter"); - } else if (column == null) { - throw new RuntimeException("[" + clazz + "]have no field type"); - } - boolean checkCast = false; - if (generictype instanceof java.lang.reflect.TypeVariable) { - checkCast = true; - generictype = TypeToken.getGenericType(generictype, subclass); - if (generictype instanceof Class) column = (Class) generictype; - } - StringBuilder newsubname = new StringBuilder(); - for (char ch : subclass.toString().replace("class ", "").toCharArray()) { //RetResult涓嶳etResult>鏄笉涓鏍风殑 - if (ch >= '0' && ch <= '9') { - newsubname.append(ch); - } else if (ch >= 'a' && ch <= 'z') { - newsubname.append(ch); - } else if (ch >= 'A' && ch <= 'Z') { - newsubname.append(ch); - } else { - newsubname.append('_'); - } - } - String tostr = "Dyn" + Attribute.class.getSimpleName() + "_" + fieldname + "_" + column.getSimpleName(); - if (fieldkey.contains("1_")) { - tostr += "_getter"; - } else if (fieldkey.contains("2_")) { - tostr += "_setter"; - } else if (fieldkey.contains("3_")) { - tostr += "_getter_setter"; - } - final Class pcolumn = column; - if (column.isPrimitive()) column = java.lang.reflect.Array.get(java.lang.reflect.Array.newInstance(column, 1), 0).getClass(); - final String supDynName = Attribute.class.getName().replace('.', '/'); - final String interName = TypeToken.typeToClass(subclass).getName().replace('.', '/'); - final String columnName = column.getName().replace('.', '/'); - final String interDesc = Type.getDescriptor(TypeToken.typeToClass(subclass)); - final String columnDesc = Type.getDescriptor(column); - final ClassLoader loader = Thread.currentThread().getContextClassLoader(); - Class realclz = TypeToken.typeToClass(subclass); - String pkgname = ""; - String clzname = newsubname.toString(); - if (realclz != null) { - pkgname = realclz.getName(); - int pos = pkgname.lastIndexOf('.'); - if (pos > 0) pkgname = pkgname.substring(0, pos + 1); - pkgname = pkgname.replace('.', '/'); - } - final String newDynName = "org/redkaledyn/attribute/" + pkgname + "_Dyn" + Attribute.class.getSimpleName() - + "__" + clzname + "__" + fieldkey.substring(fieldkey.indexOf('.') + 1); - try { - Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); - Attribute rs = (Attribute) (clz == null ? loader.loadClass(newDynName.replace('/', '.')) : clz).getDeclaredConstructor().newInstance(); - java.lang.reflect.Field _gtype = rs.getClass().getDeclaredField("_gtype"); - _gtype.setAccessible(true); - _gtype.set(rs, generictype); - java.lang.reflect.Field _attach = rs.getClass().getDeclaredField("_attach"); - _attach.setAccessible(true); - _attach.set(rs, attach); - return rs; - } catch (Throwable ex) { - } - //--------------------------------------------------- - final ClassWriter cw = new ClassWriter(COMPUTE_FRAMES); - MethodVisitor mv; - - cw.visit(V11, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, "Ljava/lang/Object;L" + supDynName + "<" + interDesc + columnDesc + ">;", "java/lang/Object", new String[]{supDynName}); - { //_gtype - FieldVisitor fv = cw.visitField(ACC_PRIVATE, "_gtype", "Ljava/lang/reflect/Type;", null, null); - fv.visitEnd(); - } - { //_attach - FieldVisitor fv = cw.visitField(ACC_PRIVATE, "_attach", "Ljava/lang/Object;", null, null); - fv.visitEnd(); - } - { //鏋勯犳柟娉 - mv = cw.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(); - } - - { //field 鏂规硶 - mv = cw.visitMethod(ACC_PUBLIC, "field", "()Ljava/lang/String;", null, null); - mv.visitLdcInsn(fieldname); - mv.visitInsn(ARETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - { //type 鏂规硶 - mv = cw.visitMethod(ACC_PUBLIC, "type", "()Ljava/lang/Class;", null, null); - if (pcolumn == boolean.class) { - mv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "TYPE", "Ljava/lang/Class;"); - } else if (pcolumn == byte.class) { - mv.visitFieldInsn(GETSTATIC, "java/lang/Byte", "TYPE", "Ljava/lang/Class;"); - } else if (pcolumn == char.class) { - mv.visitFieldInsn(GETSTATIC, "java/lang/Character", "TYPE", "Ljava/lang/Class;"); - } else if (pcolumn == short.class) { - mv.visitFieldInsn(GETSTATIC, "java/lang/Short", "TYPE", "Ljava/lang/Class;"); - } else if (pcolumn == int.class) { - mv.visitFieldInsn(GETSTATIC, "java/lang/Integer", "TYPE", "Ljava/lang/Class;"); - } else if (pcolumn == float.class) { - mv.visitFieldInsn(GETSTATIC, "java/lang/Float", "TYPE", "Ljava/lang/Class;"); - } else if (pcolumn == long.class) { - mv.visitFieldInsn(GETSTATIC, "java/lang/Long", "TYPE", "Ljava/lang/Class;"); - } else if (pcolumn == double.class) { - mv.visitFieldInsn(GETSTATIC, "java/lang/Double", "TYPE", "Ljava/lang/Class;"); - } else { - mv.visitLdcInsn(Type.getType(pcolumn)); - } - mv.visitInsn(ARETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - { //genericType - mv = cw.visitMethod(ACC_PUBLIC, "genericType", "()Ljava/lang/reflect/Type;", null, null); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, "_gtype", "Ljava/lang/reflect/Type;"); - mv.visitInsn(ARETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - { //attach - mv = cw.visitMethod(ACC_PUBLIC, "attach", "()Ljava/lang/Object;", "()TE;", null); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, "_attach", "Ljava/lang/Object;"); - mv.visitInsn(ARETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - { //declaringClass 鏂规硶 - mv = cw.visitMethod(ACC_PUBLIC, "declaringClass", "()Ljava/lang/Class;", null, null); - mv.visitLdcInsn(Type.getType(TypeToken.typeToClass(subclass))); - mv.visitInsn(ARETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - { //get 鏂规硶 - mv = cw.visitMethod(ACC_PUBLIC, "get", "(" + interDesc + ")" + columnDesc, null, null); - int m = 1; - if (tgetter == null) { - if (tfield == null) { - mv.visitInsn(ACONST_NULL); - } else { //public tfield - mv.visitVarInsn(ALOAD, 1); - mv.visitFieldInsn(GETFIELD, interName, tfield.getName(), Type.getDescriptor(pcolumn)); - if (pcolumn != column) { - mv.visitMethodInsn(INVOKESTATIC, columnName, "valueOf", "(" + Type.getDescriptor(pcolumn) + ")" + columnDesc, false); - m = 2; - } else { - if (checkCast) mv.visitTypeInsn(CHECKCAST, columnName); - } - } - } else { - mv.visitVarInsn(ALOAD, 1); - mv.visitMethodInsn(INVOKEVIRTUAL, interName, tgetter.getName(), Type.getMethodDescriptor(tgetter), false); - if (pcolumn != column) { - mv.visitMethodInsn(INVOKESTATIC, columnName, "valueOf", "(" + Type.getDescriptor(pcolumn) + ")" + columnDesc, false); - m = 2; - } else { - if (checkCast) mv.visitTypeInsn(CHECKCAST, columnName); - } - } - mv.visitInsn(ARETURN); - mv.visitMaxs(m, 2); - mv.visitEnd(); - } - { //set 鏂规硶 - mv = cw.visitMethod(ACC_PUBLIC, "set", "(" + interDesc + columnDesc + ")V", null, null); - int m = 2; - if (tsetter == null) { - if (tfield == null || java.lang.reflect.Modifier.isFinal(tfield.getModifiers())) { - m = 0; - } else { //public tfield - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(ALOAD, 2); - if (pcolumn != column) { - try { - java.lang.reflect.Method pm = column.getMethod(pcolumn.getSimpleName() + "Value"); - mv.visitMethodInsn(INVOKEVIRTUAL, columnName, pm.getName(), Type.getMethodDescriptor(pm), false); - m = 3; - } catch (Exception ex) { - throw new RuntimeException(ex); //涓嶅彲鑳戒細鍙戠敓 - } - } - if (!tfield.getType().isPrimitive() && tfield.getGenericType() instanceof TypeVariable) { - mv.visitFieldInsn(PUTFIELD, interName, tfield.getName(), "Ljava/lang/Object;"); - } else { - mv.visitFieldInsn(PUTFIELD, interName, tfield.getName(), Type.getDescriptor(pcolumn)); - } - } - } else { - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(ALOAD, 2); - if (pcolumn != column) { - try { - java.lang.reflect.Method pm = column.getMethod(pcolumn.getSimpleName() + "Value"); - mv.visitMethodInsn(INVOKEVIRTUAL, columnName, pm.getName(), Type.getMethodDescriptor(pm), false); - m = 3; - } catch (Exception ex) { - throw new RuntimeException(ex); //涓嶅彲鑳戒細鍙戠敓 - } - } - mv.visitMethodInsn(INVOKEVIRTUAL, interName, tsetter.getName(), Type.getMethodDescriptor(tsetter), false); - } - mv.visitInsn(RETURN); - mv.visitMaxs(m, 3); - mv.visitEnd(); - } - { //铏氭嫙get - mv = cw.visitMethod(ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, "get", "(Ljava/lang/Object;)Ljava/lang/Object;", null, null); - mv.visitVarInsn(ALOAD, 0); - mv.visitVarInsn(ALOAD, 1); - mv.visitTypeInsn(CHECKCAST, interName); - mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "get", "(" + interDesc + ")" + columnDesc, false); - mv.visitInsn(ARETURN); - mv.visitMaxs(2, 2); - mv.visitEnd(); - } - {//铏氭嫙set - mv = cw.visitMethod(ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, "set", "(Ljava/lang/Object;Ljava/lang/Object;)V", null, null); - mv.visitVarInsn(ALOAD, 0); - mv.visitVarInsn(ALOAD, 1); - mv.visitTypeInsn(CHECKCAST, interName); - mv.visitVarInsn(ALOAD, 2); - mv.visitTypeInsn(CHECKCAST, columnName); - mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "set", "(" + interDesc + columnDesc + ")V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(3, 3); - mv.visitEnd(); - } - { //toString鍑芥暟 - mv = cw.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null); - //mv.setDebug(true); - mv.visitLdcInsn(tostr); - mv.visitInsn(ARETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - cw.visitEnd(); - - byte[] bytes = cw.toByteArray(); - Class newClazz = (Class) new ClassLoader(loader) { - public final Class loadClass(String name, byte[] b) { - return defineClass(name, b, 0, b.length); - } - }.loadClass(newDynName.replace('/', '.'), bytes); - RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, newClazz); - RedkaleClassLoader.putReflectionDeclaredConstructors(newClazz, newDynName.replace('/', '.')); - try { - Attribute rs = newClazz.getDeclaredConstructor().newInstance(); - java.lang.reflect.Field _gtype = rs.getClass().getDeclaredField("_gtype"); - _gtype.setAccessible(true); - _gtype.set(rs, generictype); - RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), _gtype); - java.lang.reflect.Field _attach = rs.getClass().getDeclaredField("_attach"); - _attach.setAccessible(true); - _attach.set(rs, attach); - RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), _attach); - return rs; - } catch (Exception ex) { - throw new RuntimeException(ex); - } - } - - /** - * 鏍规嵁Class銆佸瓧娈靛悕銆佸瓧娈电被鍨嬨乬etter鍜宻etter鏂规硶鐢熸垚 Attribute 瀵硅薄銆 clazz銆乫ieldname銆乫ieldtype閮戒笉鑳戒负null - * - * @param 渚濋檮绫荤殑绫诲瀷 - * @param 瀛楁绫诲瀷 - * @param clazz 鎸囧畾渚濋檮鐨勭被 - * @param fieldname 瀛楁鍚 - * @param fieldtype 瀛楁绫诲瀷 - * @param getter getter鏂规硶 - * @param setter setter鏂规硶 - * - * @return Attribute瀵硅薄 - */ - public static Attribute create(final Class clazz, final String fieldname, final Class fieldtype, final Function getter, final BiConsumer setter) { - return create(clazz, fieldname, fieldtype, fieldtype, getter, setter); - } - - /** - * 鏍规嵁Class銆佸瓧娈靛悕銆佸瓧娈电被鍨嬨乬etter鍜宻etter鏂规硶鐢熸垚 Attribute 瀵硅薄銆 clazz銆乫ieldname銆乫ieldtype閮戒笉鑳戒负null - * - * @param 渚濋檮绫荤殑绫诲瀷 - * @param 瀛楁绫诲瀷 - * @param clazz 鎸囧畾渚濋檮鐨勭被 - * @param fieldname 瀛楁鍚 - * @param fieldtype 瀛楁绫诲瀷 - * @param getter getter鏂规硶 - * @param setter setter鏂规硶 - * @param attach 闄勫姞瀵硅薄 - * - * @return Attribute瀵硅薄 - */ - public static Attribute create(final Class clazz, final String fieldname, final Class fieldtype, final Function getter, final BiConsumer setter, Object attach) { - return create(clazz, fieldname, fieldtype, fieldtype, getter, setter, attach); - } - - /** - * 鏍规嵁Class銆佸瓧娈靛悕銆佸瓧娈电被鍨嬨乬etter鍜宻etter鏂规硶鐢熸垚 Attribute 瀵硅薄銆 clazz銆乫ieldname銆乫ieldtype閮戒笉鑳戒负null - * - * @param 渚濋檮绫荤殑绫诲瀷 - * @param 瀛楁绫诲瀷 - * @param clazz 鎸囧畾渚濋檮鐨勭被 - * @param fieldname 瀛楁鍚 - * @param fieldtype 瀛楁绫诲瀷 - * @param fieldGenericType 瀛楁娉涘瀷 - * @param getter getter鏂规硶 - * @param setter setter鏂规硶 - * - * @return Attribute瀵硅薄 - */ - public static Attribute create(final Class clazz, final String fieldname, final Class fieldtype, - final java.lang.reflect.Type fieldGenericType, final Function getter, final BiConsumer setter) { - return create(clazz, fieldname, fieldtype, fieldGenericType, getter, setter, null); - } - - /** - * 鏍规嵁Class銆佸瓧娈靛悕銆佸瓧娈电被鍨嬨乬etter鍜宻etter鏂规硶鐢熸垚 Attribute 瀵硅薄銆 clazz銆乫ieldname銆乫ieldtype閮戒笉鑳戒负null - * - * @param 渚濋檮绫荤殑绫诲瀷 - * @param 瀛楁绫诲瀷 - * @param clazz 鎸囧畾渚濋檮鐨勭被 - * @param fieldname 瀛楁鍚 - * @param fieldtype 瀛楁绫诲瀷 - * @param fieldGenericType 瀛楁娉涘瀷 - * @param getter getter鏂规硶 - * @param setter setter鏂规硶 - * @param attach 闄勫姞瀵硅薄 - * - * @return Attribute瀵硅薄 - */ - public static Attribute create(final Class clazz, final String fieldname, final Class fieldtype, - final java.lang.reflect.Type fieldGenericType, final Function getter, final BiConsumer setter, final Object attach) { - Objects.requireNonNull(clazz); - Objects.requireNonNull(fieldname); - Objects.requireNonNull(fieldtype); - String str = Attribute.class.getSimpleName() + "_" + fieldname + "_" + fieldtype.getSimpleName(); - if (getter != null) str += "_getter"; - if (setter != null) str += "_setter"; - final String tostr = str; - return new Attribute() { - @Override - public Class type() { - return fieldtype; - } - - @Override - public java.lang.reflect.Type genericType() { - return fieldGenericType; - } - - @Override - public E attach() { - return (E) attach; - } - - @Override - public Class declaringClass() { - return clazz; - } - - @Override - public String field() { - return fieldname; - } - - @Override - public F get(T obj) { - return getter == null ? null : getter.apply(obj); - } - - @Override - public void set(T obj, F value) { - if (setter != null) setter.accept(obj, value); - } - - @Override - public String toString() { - return tostr; - } - }; - } -} +/* + * 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.util; + +import java.lang.reflect.TypeVariable; +import java.util.*; +import java.util.function.*; +import org.redkale.asm.*; +import static org.redkale.asm.ClassWriter.COMPUTE_FRAMES; +import static org.redkale.asm.Opcodes.*; + +/** + * 璇ョ被瀹炵幇鍔ㄦ佹槧灏勪竴涓狫avaBean绫讳腑鎴愬憳瀵瑰簲鐨刧etter銆乻etter鏂规硶锛 浠f浛浣庢晥鐨勫弽灏勫疄鐜版柟寮忋 + *

+ *  public class Record {
+ *
+ *      private String name;
+ *
+ *      public String getName() {
+ *          return name;
+ *      }
+ *
+ *      public void setName(String name) {
+ *          this.name = name;
+ *      }
+ *  }
+ * 
+ * 鑾峰彇name鐨 Attribute 锛 + *
+ *  Attribute<Record, String> nameAction = Attribute.create(Record.class.getDeclaredField("name"));
+ * 
+ * 绛変环浜: + *
+ *  Attribute<Record, String> nameAction = new Attribute<Record, String>() {
+ *
+ *      private java.lang.reflect.Type _gtype = String.class;
+ *
+ *      private java.lang.Object _attach;
+ *
+ *      @Override
+ *      public String field() {
+ *          return "name";
+ *      }
+ *
+ *      @Override
+ *      public String get(Record obj) {
+ *          return obj.getName();
+ *      }
+ *
+ *      @Override
+ *      public void set(Record obj, String value) {
+ *          obj.setName(value);
+ *      }
+ *
+ *      @Override
+ *      public Class type() {
+ *          return String.class;
+ *      }
+ *
+ *      @Override
+ *      public java.lang.reflect.Type genericType() {
+ *          return _gtype;
+ *      }
+ *
+ *      @Override
+ *      public Object attach() {
+ *          return _attach;
+ *      }
+ *
+ *      @Override
+ *      public Class declaringClass() {
+ *          return Record.class;
+ *      }
+ *  };
+ * 
+ *

+ * 鏄犲皠Field鏃讹紝field蹇呴』婊¤冻浠ヤ笅鏉′欢涔嬩竴锛
+ * 1銆乫ield灞炴ф槸public涓旈潪final
+ * 2銆佽嚦灏戝瓨鍦ㄥ搴旂殑getter銆乻etter鏂规硶涓殑涓涓
+ * 褰撲笉瀛樺湪getter鏂规硶鏃讹紝get鎿嶄綔鍥哄畾杩斿洖null
+ * 褰撲笉瀛樺湪setter鏂规硶鏃讹紝set鎿嶄綔涓虹┖鏂规硶
+ *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param 瀛楁渚濋檮鐨勭被 + * @param 瀛楁鐨勬暟鎹被鍨 + */ +@SuppressWarnings("unchecked") +public interface Attribute { + + /** + * 杩斿洖瀛楁鐨勬暟鎹被鍨 + * + * @return 瀛楁鐨勬暟鎹被鍨 + */ + public Class type(); + + /** + * 杩斿洖瀛楁鐨勬暟鎹硾鍨 + * + * @return 瀛楁鐨勬暟鎹硾鍨 + */ + default java.lang.reflect.Type genericType() { + return type(); + } + + /** + * 杩斿洖瀛楁渚濋檮鐨勭被鍚 + * + * @return 渚濋檮鐨勭被鍚 + */ + public Class declaringClass(); + + /** + * 杩斿洖瀛楁鍚 + * + * @return 瀛楁鍚 + */ + public String field(); + + /** + * 鑾峰彇鎸囧畾瀵硅薄鐨勮瀛楁鐨勫 + * + * @param obj 鎸囧畾瀵硅薄 + * + * @return 瀛楁鐨勫 + */ + public F get(T obj); + + /** + * 缁欐寚瀹氬璞$殑璇ュ瓧娈佃祴鍊 + * + * @param obj 鎸囧畾瀵硅薄 + * @param value 瀛楁鏂板 + */ + public void set(T obj, F value); + + /** + * 闄勫姞瀵硅薄 + * + * @param 娉涘瀷 + * + * @return 闄勫姞瀵硅薄 + */ + default E attach() { + return null; + } + + /** + * 鏍规嵁涓涓狥ield鐢熸垚 Attribute 瀵硅薄銆 + * + * @param 渚濋檮绫荤殑绫诲瀷 + * @param 瀛楁绫诲瀷 + * @param field 瀛楁锛屽鏋滆瀛楁涓嶅瓨鍦ㄥ垯鎶涘紓甯 + * + * @return Attribute瀵硅薄 + */ + @SuppressWarnings("unchecked") + public static Attribute create(final java.lang.reflect.Field field) { + return create((Class) field.getDeclaringClass(), field.getName(), (Class) null, field, (java.lang.reflect.Method) null, (java.lang.reflect.Method) null, null); + } + + /** + * 鏍规嵁涓涓狥ield鐢熸垚 Attribute 瀵硅薄銆 + * + * @param 渚濋檮绫荤殑绫诲瀷 + * @param 瀛楁绫诲瀷 + * @param field 瀛楁锛屽鏋滆瀛楁涓嶅瓨鍦ㄥ垯鎶涘紓甯 + * @param attach 闄勫姞瀵硅薄 + * + * @return Attribute瀵硅薄 + */ + @SuppressWarnings("unchecked") + public static Attribute create(final java.lang.reflect.Field field, Object attach) { + return create((Class) field.getDeclaringClass(), field.getName(), (Class) null, field, (java.lang.reflect.Method) null, (java.lang.reflect.Method) null, attach); + } + + /** + * 鏍规嵁涓涓狥ield鍜宖ield鐨勫埆鍚嶇敓鎴 Attribute 瀵硅薄銆 + * + * @param 渚濋檮绫荤殑绫诲瀷 + * @param 瀛楁绫诲瀷 + * @param fieldalias 鍒悕 + * @param field 瀛楁锛屽鏋滆瀛楁涓嶅瓨鍦ㄥ垯鎶涘紓甯 + * + * @return Attribute瀵硅薄 + */ + @SuppressWarnings("unchecked") + public static Attribute create(String fieldalias, final java.lang.reflect.Field field) { + return create((Class) field.getDeclaringClass(), fieldalias, (Class) null, field, (java.lang.reflect.Method) null, (java.lang.reflect.Method) null, null); + } + + /** + * 鏍规嵁涓涓狥ield鍜宖ield鐨勫埆鍚嶇敓鎴 Attribute 瀵硅薄銆 + * + * @param 渚濋檮绫荤殑绫诲瀷 + * @param 瀛楁绫诲瀷 + * @param fieldalias 鍒悕 + * @param field 瀛楁锛屽鏋滆瀛楁涓嶅瓨鍦ㄥ垯鎶涘紓甯 + * @param attach 闄勫姞瀵硅薄 + * + * @return Attribute瀵硅薄 + */ + @SuppressWarnings("unchecked") + public static Attribute create(String fieldalias, final java.lang.reflect.Field field, Object attach) { + return create((Class) field.getDeclaringClass(), fieldalias, (Class) null, field, (java.lang.reflect.Method) null, (java.lang.reflect.Method) null, attach); + } + + /** + * 鏍规嵁涓涓狢lass鍜宖ield鐪熷疄鍚嶇О鐢熸垚 Attribute 瀵硅薄銆 + * + * @param 渚濋檮绫荤殑绫诲瀷 + * @param 瀛楁绫诲瀷 + * @param clazz 鎸囧畾渚濋檮鐨勭被 + * @param fieldname 瀛楁鍚嶏紝濡傛灉璇ュ瓧娈典笉瀛樺湪鍒欐姏寮傚父 + * + * @return Attribute瀵硅薄 + */ + public static Attribute create(Class clazz, final String fieldname) { + try { + return create(clazz, fieldname, (Class) null, clazz.getDeclaredField(fieldname), (java.lang.reflect.Method) null, (java.lang.reflect.Method) null, null); + } catch (NoSuchFieldException | SecurityException ex) { + throw new RuntimeException(ex); + } + } + + /** + * 鏍规嵁涓涓狢lass鍜宖ield鐪熷疄鍚嶇О鐢熸垚 Attribute 瀵硅薄銆 + * + * @param 渚濋檮绫荤殑绫诲瀷 + * @param 瀛楁绫诲瀷 + * @param clazz 鎸囧畾渚濋檮鐨勭被 + * @param fieldname 瀛楁鍚嶏紝濡傛灉璇ュ瓧娈典笉瀛樺湪鍒欐姏寮傚父 + * @param attach 闄勫姞瀵硅薄 + * + * @return Attribute瀵硅薄 + */ + public static Attribute create(Class clazz, final String fieldname, Object attach) { + try { + return create(clazz, fieldname, (Class) null, clazz.getDeclaredField(fieldname), (java.lang.reflect.Method) null, (java.lang.reflect.Method) null, attach); + } catch (NoSuchFieldException | SecurityException ex) { + throw new RuntimeException(ex); + } + } + + /** + * 鏍规嵁涓涓狢lass鍜孎ield鐢熸垚 Attribute 瀵硅薄銆 + * + * @param 渚濋檮绫荤殑绫诲瀷 + * @param 瀛楁绫诲瀷 + * @param clazz 鎸囧畾渚濋檮鐨勭被 + * @param field 瀛楁锛屽鏋滆瀛楁涓嶅瓨鍦ㄥ垯鎶涘紓甯 + * + * @return Attribute瀵硅薄 + */ + public static Attribute create(Class clazz, final java.lang.reflect.Field field) { + return create(clazz, field.getName(), (Class) null, field, (java.lang.reflect.Method) null, (java.lang.reflect.Method) null, null); + } + + /** + * 鏍规嵁涓涓狢lass鍜孎ield鐢熸垚 Attribute 瀵硅薄銆 + * + * @param 渚濋檮绫荤殑绫诲瀷 + * @param 瀛楁绫诲瀷 + * @param subclass 鎸囧畾渚濋檮鐨勫瓙绫 + * @param clazz 鎸囧畾渚濋檮鐨勭被 + * @param field 瀛楁锛屽鏋滆瀛楁涓嶅瓨鍦ㄥ垯鎶涘紓甯 + * + * @return Attribute瀵硅薄 + */ + public static Attribute create(Class subclass, Class clazz, final java.lang.reflect.Field field) { + return create(subclass, clazz, field.getName(), (Class) null, field, (java.lang.reflect.Method) null, (java.lang.reflect.Method) null, null); + } + + /** + * 鏍规嵁涓涓狢lass鍜孎ield鐢熸垚 Attribute 瀵硅薄銆 + * + * @param 渚濋檮绫荤殑绫诲瀷 + * @param 瀛楁绫诲瀷 + * @param clazz 鎸囧畾渚濋檮鐨勭被 + * @param field 瀛楁锛屽鏋滆瀛楁涓嶅瓨鍦ㄥ垯鎶涘紓甯 + * @param attach 闄勫姞瀵硅薄 + * + * @return Attribute瀵硅薄 + */ + public static Attribute create(Class clazz, final java.lang.reflect.Field field, Object attach) { + return create(clazz, field.getName(), (Class) null, field, (java.lang.reflect.Method) null, (java.lang.reflect.Method) null, attach); + } + + /** + * 鏍规嵁涓涓狢lass鍜孎ield鐢熸垚 Attribute 瀵硅薄銆 + * + * @param 渚濋檮绫荤殑绫诲瀷 + * @param 瀛楁绫诲瀷 + * @param subclass 鎸囧畾渚濋檮鐨勫瓙绫 + * @param clazz 鎸囧畾渚濋檮鐨勭被 + * @param field 瀛楁锛屽鏋滆瀛楁涓嶅瓨鍦ㄥ垯鎶涘紓甯 + * @param attach 闄勫姞瀵硅薄 + * + * @return Attribute瀵硅薄 + */ + public static Attribute create(Class subclass, Class clazz, final java.lang.reflect.Field field, Object attach) { + return create(subclass, clazz, field.getName(), (Class) null, field, (java.lang.reflect.Method) null, (java.lang.reflect.Method) null, attach); + } + + /** + * 鏍规嵁涓涓狢lass銆乫ield鍒悕鍜孎ield鐢熸垚 Attribute 瀵硅薄銆 + * + * @param 渚濋檮绫荤殑绫诲瀷 + * @param 瀛楁绫诲瀷 + * @param clazz 鎸囧畾渚濋檮鐨勭被 + * @param fieldalias 瀛楁鍒悕 + * @param field 瀛楁锛屽鏋滆瀛楁涓嶅瓨鍦ㄥ垯鎶涘紓甯 + * + * @return Attribute瀵硅薄 + */ + public static Attribute create(Class clazz, final String fieldalias, final java.lang.reflect.Field field) { + return create(clazz, fieldalias, (Class) null, field, (java.lang.reflect.Method) null, (java.lang.reflect.Method) null, null); + } + + /** + * 鏍规嵁涓涓狢lass銆乫ield鍒悕鍜孎ield鐢熸垚 Attribute 瀵硅薄銆 + * + * @param 渚濋檮绫荤殑绫诲瀷 + * @param 瀛楁绫诲瀷 + * @param clazz 鎸囧畾渚濋檮鐨勭被 + * @param fieldalias 瀛楁鍒悕 + * @param field 瀛楁锛屽鏋滆瀛楁涓嶅瓨鍦ㄥ垯鎶涘紓甯 + * @param attach 闄勫姞瀵硅薄 + * + * @return Attribute瀵硅薄 + */ + public static Attribute create(Class clazz, final String fieldalias, final java.lang.reflect.Field field, Object attach) { + return create(clazz, fieldalias, (Class) null, field, (java.lang.reflect.Method) null, (java.lang.reflect.Method) null, attach); + } + + /** + * 鏍规嵁涓涓猤etter鍜宻etter鏂规硶鐢熸垚 Attribute 瀵硅薄銆 tgetter銆乻etter涓嶈兘鍚屾椂涓簄ull + * + * @param 渚濋檮绫荤殑绫诲瀷 + * @param 瀛楁绫诲瀷 + * @param getter getter鏂规硶 + * @param setter setter鏂规硶 + * + * @return Attribute瀵硅薄 + */ + @SuppressWarnings("unchecked") + public static Attribute create(final java.lang.reflect.Method getter, final java.lang.reflect.Method setter) { + return create((Class) (getter == null ? setter.getDeclaringClass() : getter.getDeclaringClass()), (String) null, (Class) null, (java.lang.reflect.Field) null, getter, setter, null); + } + + /** + * 鏍规嵁涓涓猤etter鍜宻etter鏂规硶鐢熸垚 Attribute 瀵硅薄銆 tgetter銆乻etter涓嶈兘鍚屾椂涓簄ull + * + * @param 渚濋檮绫荤殑绫诲瀷 + * @param 瀛楁绫诲瀷 + * @param getter getter鏂规硶 + * @param setter setter鏂规硶 + * @param attach 闄勫姞瀵硅薄 + * + * @return Attribute瀵硅薄 + */ + @SuppressWarnings("unchecked") + public static Attribute create(final java.lang.reflect.Method getter, final java.lang.reflect.Method setter, Object attach) { + return create((Class) (getter == null ? setter.getDeclaringClass() : getter.getDeclaringClass()), (String) null, (Class) null, (java.lang.reflect.Field) null, getter, setter, attach); + } + + /** + * 鏍规嵁Class銆乬etter鍜宻etter鏂规硶鐢熸垚 Attribute 瀵硅薄銆 tgetter銆乻etter涓嶈兘鍚屾椂涓簄ull + * + * @param 渚濋檮绫荤殑绫诲瀷 + * @param 瀛楁绫诲瀷 + * @param clazz 鎸囧畾渚濋檮鐨勭被 + * @param getter getter鏂规硶 + * @param setter setter鏂规硶 + * + * @return Attribute瀵硅薄 + */ + public static Attribute create(Class clazz, final java.lang.reflect.Method getter, final java.lang.reflect.Method setter) { + return create(clazz, (String) null, (Class) null, (java.lang.reflect.Field) null, getter, setter, null); + } + + /** + * 鏍规嵁Class銆乬etter鍜宻etter鏂规硶鐢熸垚 Attribute 瀵硅薄銆 tgetter銆乻etter涓嶈兘鍚屾椂涓簄ull + * + * @param 渚濋檮绫荤殑绫诲瀷 + * @param 瀛楁绫诲瀷 + * @param clazz 鎸囧畾渚濋檮鐨勭被 + * @param getter getter鏂规硶 + * @param setter setter鏂规硶 + * @param attach 闄勫姞瀵硅薄 + * + * @return Attribute瀵硅薄 + */ + public static Attribute create(Class clazz, final java.lang.reflect.Method getter, final java.lang.reflect.Method setter, Object attach) { + return create(clazz, (String) null, (Class) null, (java.lang.reflect.Field) null, getter, setter, attach); + } + + /** + * 鏍规嵁Class鐢熸垚getter銆乻etter鏂规硶閮藉瓨鍦ㄧ殑瀛楁瀵瑰簲鐨 Attribute 瀵硅薄鏁扮粍銆 + * + * @param 渚濋檮绫荤殑绫诲瀷 + * @param clazz 鎸囧畾渚濋檮鐨勭被 + * + * @return Attribute瀵硅薄鏁扮粍 + */ + public static Attribute[] create(Class clazz) { + List> list = new ArrayList<>(); + RedkaleClassLoader.putReflectionPublicFields(clazz.getName()); + for (java.lang.reflect.Field field : clazz.getFields()) { + if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) continue; + if (java.lang.reflect.Modifier.isFinal(field.getModifiers())) continue; + list.add(create(clazz, field)); + } + RedkaleClassLoader.putReflectionDeclaredMethods(clazz.getName()); + for (java.lang.reflect.Method setter : clazz.getDeclaredMethods()) { + if (java.lang.reflect.Modifier.isStatic(setter.getModifiers())) continue; + if (!setter.getName().startsWith("set")) continue; + if (setter.getReturnType() != void.class) continue; + if (setter.getParameterCount() != 1) continue; + Class t = setter.getParameterTypes()[0]; + String prefix = t == boolean.class || t == Boolean.class ? "is" : "get"; + java.lang.reflect.Method getter = null; + try { + getter = clazz.getMethod(setter.getName().replaceFirst("set", prefix)); + } catch (Exception e) { + continue; + } + list.add(create(clazz, getter, setter)); + } + return list.toArray(new Attribute[list.size()]); + } + + /** + * 鏍规嵁Class鐢熸垚getter鏂规硶瀵瑰簲鐨 Attribute 瀵硅薄鏁扮粍銆 + * + * @param 渚濋檮绫荤殑绫诲瀷 + * @param clazz 鎸囧畾渚濋檮鐨勭被 + * + * @return Attribute瀵硅薄鏁扮粍 + */ + public static Attribute[] createGetters(Class clazz) { + List> list = new ArrayList<>(); + RedkaleClassLoader.putReflectionPublicFields(clazz.getName()); + for (java.lang.reflect.Field field : clazz.getFields()) { + if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) continue; + if (java.lang.reflect.Modifier.isFinal(field.getModifiers())) continue; + list.add(create(clazz, field)); + } + RedkaleClassLoader.putReflectionDeclaredMethods(clazz.getName()); + for (java.lang.reflect.Method method : clazz.getDeclaredMethods()) { + if (java.lang.reflect.Modifier.isStatic(method.getModifiers())) continue; + if (method.getReturnType() == void.class) continue; + if (method.getParameterCount() != 0) continue; + if (method.getName().equals("getClass")) continue; + if (method.getName().startsWith("get") || method.getName().startsWith("is") + || Utility.isRecordGetter(clazz, method)) { + list.add(create(clazz, method, null)); + } + } + return list.toArray(new Attribute[list.size()]); + } + + /** + * 鏍规嵁Class鐢熸垚setter鏂规硶瀵瑰簲鐨 Attribute 瀵硅薄鏁扮粍銆 + * + * @param 渚濋檮绫荤殑绫诲瀷 + * @param clazz 鎸囧畾渚濋檮鐨勭被 + * + * @return Attribute瀵硅薄鏁扮粍 + */ + public static Attribute[] createSetters(Class clazz) { + List> list = new ArrayList<>(); + RedkaleClassLoader.putReflectionPublicFields(clazz.getName()); + for (java.lang.reflect.Field field : clazz.getFields()) { + if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) continue; + if (java.lang.reflect.Modifier.isFinal(field.getModifiers())) continue; + list.add(create(clazz, field)); + } + RedkaleClassLoader.putReflectionDeclaredMethods(clazz.getName()); + for (java.lang.reflect.Method method : clazz.getDeclaredMethods()) { + if (java.lang.reflect.Modifier.isStatic(method.getModifiers())) continue; + if (!method.getName().startsWith("set")) continue; + if (method.getParameterCount() != 1) continue; + list.add(create(clazz, (java.lang.reflect.Method) null, method)); + } + return list.toArray(new Attribute[list.size()]); + } + + /** + * 鏍规嵁Class銆佸瓧娈靛埆鍚嶃乬etter鍜宻etter鏂规硶鐢熸垚 Attribute 瀵硅薄銆 tgetter銆乻etter涓嶈兘鍚屾椂涓簄ull + * + * @param 渚濋檮绫荤殑绫诲瀷 + * @param 瀛楁绫诲瀷 + * @param clazz 鎸囧畾渚濋檮鐨勭被 + * @param fieldalias 瀛楁鍒悕 + * @param getter getter鏂规硶 + * @param setter setter鏂规硶 + * + * @return Attribute瀵硅薄 + */ + public static Attribute create(Class clazz, final String fieldalias, final java.lang.reflect.Method getter, final java.lang.reflect.Method setter) { + return create(clazz, fieldalias, (Class) null, (java.lang.reflect.Field) null, getter, setter, null); + } + + /** + * 鏍规嵁Class銆佸瓧娈靛埆鍚嶃乬etter鍜宻etter鏂规硶鐢熸垚 Attribute 瀵硅薄銆 tgetter銆乻etter涓嶈兘鍚屾椂涓簄ull + * + * @param 渚濋檮绫荤殑绫诲瀷 + * @param 瀛楁绫诲瀷 + * @param clazz 鎸囧畾渚濋檮鐨勭被 + * @param fieldalias 瀛楁鍒悕 + * @param getter getter鏂规硶 + * @param setter setter鏂规硶 + * @param attach 闄勫姞瀵硅薄 + * + * @return Attribute瀵硅薄 + */ + public static Attribute create(Class clazz, final String fieldalias, final java.lang.reflect.Method getter, final java.lang.reflect.Method setter, Object attach) { + return create(clazz, fieldalias, (Class) null, (java.lang.reflect.Field) null, getter, setter, attach); + } + + /** + * 鏍规嵁Class銆佸瓧娈靛埆鍚嶃丗ield銆乬etter鍜宻etter鏂规硶鐢熸垚 Attribute 瀵硅薄銆 Field銆乼getter銆乻etter涓嶈兘鍚屾椂涓簄ull + * + * @param 渚濋檮绫荤殑绫诲瀷 + * @param 瀛楁绫诲瀷 + * @param clazz 鎸囧畾渚濋檮鐨勭被 + * @param fieldalias 瀛楁鍒悕 + * @param field 瀛楁 + * @param getter getter鏂规硶 + * @param setter setter鏂规硶 + * + * @return Attribute瀵硅薄 + */ + public static Attribute create(final Class clazz, String fieldalias, final java.lang.reflect.Field field, java.lang.reflect.Method getter, java.lang.reflect.Method setter) { + return create(clazz, fieldalias, (Class) null, field, getter, setter, null); + } + + /** + * 鏍规嵁Class銆佸瓧娈靛埆鍚嶃丗ield銆乬etter鍜宻etter鏂规硶鐢熸垚 Attribute 瀵硅薄銆 Field銆乼getter銆乻etter涓嶈兘鍚屾椂涓簄ull + * + * @param 渚濋檮绫荤殑绫诲瀷 + * @param 瀛楁绫诲瀷 + * @param clazz 鎸囧畾渚濋檮鐨勭被 + * @param fieldalias 瀛楁鍒悕 + * @param field 瀛楁 + * @param getter getter鏂规硶 + * @param setter setter鏂规硶 + * @param attach 闄勫姞瀵硅薄 + * + * @return Attribute瀵硅薄 + */ + public static Attribute create(final Class clazz, String fieldalias, final java.lang.reflect.Field field, java.lang.reflect.Method getter, java.lang.reflect.Method setter, Object attach) { + return create(clazz, fieldalias, (Class) null, field, getter, setter, attach); + } + + /** + * 鏍规嵁Class銆佸瓧娈靛埆鍚嶃佸瓧娈电被鍨嬬敓鎴愯櫄鏋勭殑 Attribute 瀵硅薄,get銆乻et鏂规硶涓虹┖鏂规硶銆 + * + * @param 渚濋檮绫荤殑绫诲瀷 + * @param 瀛楁绫诲瀷 + * @param clazz 鎸囧畾渚濋檮鐨勭被 + * @param fieldalias 瀛楁鍒悕 + * @param fieldtype 瀛楁鐨勭被 + * + * @return Attribute瀵硅薄 + */ + public static Attribute create(final Class clazz, String fieldalias, final Class fieldtype) { + return create(clazz, fieldalias, fieldtype, (java.lang.reflect.Type) null, (Function) null, (BiConsumer) null, null); + } + + /** + * 鏍规嵁Class銆佸瓧娈靛埆鍚嶃佸瓧娈电被鍨嬬敓鎴愯櫄鏋勭殑 Attribute 瀵硅薄,get銆乻et鏂规硶涓虹┖鏂规硶銆 + * + * @param 渚濋檮绫荤殑绫诲瀷 + * @param 瀛楁绫诲瀷 + * @param clazz 鎸囧畾渚濋檮鐨勭被 + * @param fieldalias 瀛楁鍒悕 + * @param fieldtype 瀛楁鐨勭被 + * @param attach 闄勫姞瀵硅薄 + * + * @return Attribute瀵硅薄 + */ + public static Attribute create(final Class clazz, String fieldalias, final Class fieldtype, Object attach) { + return create(clazz, fieldalias, fieldtype, (java.lang.reflect.Type) null, (Function) null, (BiConsumer) null, attach); + } + + /** + * 鏍规嵁Class銆佸瓧娈靛埆鍚嶃佸瓧娈电被鍨嬨丗ield銆乬etter鍜宻etter鏂规硶鐢熸垚 Attribute 瀵硅薄銆 fieldalias/fieldtype銆丗ield銆乼getter銆乻etter涓嶈兘鍚屾椂涓簄ull. + * + * @param 渚濋檮绫荤殑绫诲瀷 + * @param 瀛楁绫诲瀷 + * @param clazz 鎸囧畾渚濋檮鐨勭被 + * @param fieldalias 瀛楁鍒悕 + * @param fieldtype 瀛楁绫诲瀷 + * @param field 瀛楁 + * @param getter getter鏂规硶 + * @param setter setter鏂规硶 + * + * @return Attribute瀵硅薄 + */ + @SuppressWarnings("unchecked") + public static Attribute create(final Class clazz, String fieldalias, final Class fieldtype, final java.lang.reflect.Field field, java.lang.reflect.Method getter, java.lang.reflect.Method setter) { + return create(clazz, fieldalias, fieldtype, field, getter, setter, null); + } + + /** + * 鏍规嵁Class銆佸瓧娈靛埆鍚嶃佸瓧娈电被鍨嬨丗ield銆乬etter鍜宻etter鏂规硶鐢熸垚 Attribute 瀵硅薄銆 fieldalias/fieldtype銆丗ield銆乼getter銆乻etter涓嶈兘鍚屾椂涓簄ull. + * + * @param 渚濋檮绫荤殑绫诲瀷 + * @param 瀛楁绫诲瀷 + * @param clazz 鎸囧畾渚濋檮鐨勭被 + * @param fieldalias 瀛楁鍒悕 + * @param fieldtype 瀛楁绫诲瀷 + * @param field 瀛楁 + * @param getter getter鏂规硶 + * @param setter setter鏂规硶 + * @param attach 闄勫姞瀵硅薄 + * + * @return Attribute瀵硅薄 + */ + @SuppressWarnings("unchecked") + public static Attribute create(final Class clazz, String fieldalias, final Class fieldtype, final java.lang.reflect.Field field, java.lang.reflect.Method getter, java.lang.reflect.Method setter, Object attach) { + return create(null, clazz, fieldalias, fieldtype, field, getter, setter, attach); + } + + /** + * 鏍规嵁Class銆佸瓧娈靛埆鍚嶃佸瓧娈电被鍨嬨丗ield銆乬etter鍜宻etter鏂规硶鐢熸垚 Attribute 瀵硅薄銆 fieldalias/fieldtype銆丗ield銆乼getter銆乻etter涓嶈兘鍚屾椂涓簄ull. + * + * @param 渚濋檮绫荤殑绫诲瀷 + * @param 瀛楁绫诲瀷 + * @param subclass 鎸囧畾渚濋檮鐨勫瓙绫 + * @param clazz 鎸囧畾渚濋檮鐨勭被 + * @param fieldalias 瀛楁鍒悕 + * @param fieldtype 瀛楁绫诲瀷 + * @param field 瀛楁 + * @param getter getter鏂规硶 + * @param setter setter鏂规硶 + * @param attach 闄勫姞瀵硅薄 + * + * @return Attribute瀵硅薄 + */ + @SuppressWarnings("unchecked") + public static Attribute create(java.lang.reflect.Type subclass, final Class clazz, String fieldalias, final Class fieldtype, final java.lang.reflect.Field field, java.lang.reflect.Method getter, java.lang.reflect.Method setter, Object attach) { + if (subclass == null) subclass = clazz; + if (fieldalias != null && fieldalias.isEmpty()) fieldalias = null; + int mod = field == null ? java.lang.reflect.Modifier.STATIC : field.getModifiers(); + if (field != null && !java.lang.reflect.Modifier.isStatic(mod) && !java.lang.reflect.Modifier.isPublic(mod)) { + Class t = field.getType(); + char[] fs = field.getName().toCharArray(); + fs[0] = Character.toUpperCase(fs[0]); + String mn = new String(fs); + if (getter == null) { + String prefix = t == boolean.class || t == Boolean.class ? "is" : "get"; + try { + getter = clazz.getMethod(prefix + mn); + } catch (Exception ex) { + try { + java.lang.reflect.Method m = clazz.getMethod(field.getName()); + if (Utility.isRecordGetter(clazz, m) && field.getType() == m.getReturnType()) getter = m; + } catch (Exception ex2) { + } + } + } + if (setter == null) { + try { + setter = clazz.getMethod("set" + mn, field.getType()); + } catch (Exception ex) { + } + } + } + final java.lang.reflect.Field tfield = field == null ? null : (!java.lang.reflect.Modifier.isPublic(mod) || java.lang.reflect.Modifier.isStatic(mod) ? null : field); + final java.lang.reflect.Method tgetter = getter; + final java.lang.reflect.Method tsetter = setter; + String fieldkey = fieldalias; + if (fieldalias == null) { + if (field != null) { + fieldalias = field.getName(); + fieldkey = fieldalias; + } else { + String s = null; + if (getter != null) { + s = Utility.isRecordGetter(getter) ? getter.getName() : getter.getName().substring(getter.getName().startsWith("is") ? 2 : 3); + fieldkey = getter.getName(); + } else if (setter != null) { + s = setter.getName().substring(3); + fieldkey = setter.getName(); + } + if (s != null) { + char[] d = s.toCharArray(); + if (d.length < 2 || Character.isLowerCase(d[1])) { + d[0] = Character.toLowerCase(d[0]); + } + fieldalias = new String(d); + fieldkey = fieldalias; + } + } + } + if (getter != null) { //闃叉fieldname/getter/setter鍚嶅瓧鐩稿悓,鎵浠ュ姞涓1/2/3 + if (setter == null) { + fieldkey = (fieldalias == null ? "" : ("0_" + fieldalias + "_")) + "1_" + getter.getName(); + } else { + fieldkey = (fieldalias == null ? "" : ("0_" + fieldalias + "_")) + "3_" + getter.getName() + "_" + setter.getName(); + } + } else if (setter != null) { + fieldkey = (fieldalias == null ? "" : ("0_" + fieldalias + "_")) + "2_" + setter.getName(); + } + if (fieldalias == null && fieldtype == null && tgetter == null && tsetter == null && tfield == null) { + throw new RuntimeException("[" + clazz + "]have no public field or setter or getter"); + } + final String fieldname = fieldalias; + Class column = fieldtype; + java.lang.reflect.Type generictype = fieldtype; + if (tfield != null) { // public tfield + column = tfield.getType(); + generictype = tfield.getGenericType(); + } else if (tgetter != null) { + column = tgetter.getReturnType(); + generictype = tgetter.getGenericReturnType(); + } else if (tsetter != null) { + column = tsetter.getParameterTypes()[0]; + generictype = tsetter.getGenericParameterTypes()[0]; + } else if (fieldtype == null) { + throw new RuntimeException("[" + clazz + "]have no public field or setter or getter"); + } else if (column == null) { + throw new RuntimeException("[" + clazz + "]have no field type"); + } + boolean checkCast = false; + if (generictype instanceof java.lang.reflect.TypeVariable) { + checkCast = true; + generictype = TypeToken.getGenericType(generictype, subclass); + if (generictype instanceof Class) column = (Class) generictype; + } + StringBuilder newsubname = new StringBuilder(); + for (char ch : subclass.toString().replace("class ", "").toCharArray()) { //RetResult涓嶳etResult>鏄笉涓鏍风殑 + if (ch >= '0' && ch <= '9') { + newsubname.append(ch); + } else if (ch >= 'a' && ch <= 'z') { + newsubname.append(ch); + } else if (ch >= 'A' && ch <= 'Z') { + newsubname.append(ch); + } else { + newsubname.append('_'); + } + } + String tostr = "Dyn" + Attribute.class.getSimpleName() + "_" + fieldname + "_" + column.getSimpleName(); + if (fieldkey.contains("1_")) { + tostr += "_getter"; + } else if (fieldkey.contains("2_")) { + tostr += "_setter"; + } else if (fieldkey.contains("3_")) { + tostr += "_getter_setter"; + } + final Class pcolumn = column; + if (column.isPrimitive()) column = java.lang.reflect.Array.get(java.lang.reflect.Array.newInstance(column, 1), 0).getClass(); + final String supDynName = Attribute.class.getName().replace('.', '/'); + final String interName = TypeToken.typeToClass(subclass).getName().replace('.', '/'); + final String columnName = column.getName().replace('.', '/'); + final String interDesc = Type.getDescriptor(TypeToken.typeToClass(subclass)); + final String columnDesc = Type.getDescriptor(column); + final ClassLoader loader = Thread.currentThread().getContextClassLoader(); + Class realclz = TypeToken.typeToClass(subclass); + String pkgname = ""; + String clzname = newsubname.toString(); + if (realclz != null) { + pkgname = realclz.getName(); + int pos = pkgname.lastIndexOf('.'); + if (pos > 0) pkgname = pkgname.substring(0, pos + 1); + pkgname = pkgname.replace('.', '/'); + } + final String newDynName = "org/redkaledyn/attribute/" + pkgname + "_Dyn" + Attribute.class.getSimpleName() + + "__" + clzname + "__" + fieldkey.substring(fieldkey.indexOf('.') + 1); + try { + Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); + Attribute rs = (Attribute) (clz == null ? loader.loadClass(newDynName.replace('/', '.')) : clz).getDeclaredConstructor().newInstance(); + java.lang.reflect.Field _gtype = rs.getClass().getDeclaredField("_gtype"); + _gtype.setAccessible(true); + _gtype.set(rs, generictype); + java.lang.reflect.Field _attach = rs.getClass().getDeclaredField("_attach"); + _attach.setAccessible(true); + _attach.set(rs, attach); + return rs; + } catch (Throwable ex) { + } + //--------------------------------------------------- + final ClassWriter cw = new ClassWriter(COMPUTE_FRAMES); + MethodVisitor mv; + + cw.visit(V11, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, "Ljava/lang/Object;L" + supDynName + "<" + interDesc + columnDesc + ">;", "java/lang/Object", new String[]{supDynName}); + { //_gtype + FieldVisitor fv = cw.visitField(ACC_PRIVATE, "_gtype", "Ljava/lang/reflect/Type;", null, null); + fv.visitEnd(); + } + { //_attach + FieldVisitor fv = cw.visitField(ACC_PRIVATE, "_attach", "Ljava/lang/Object;", null, null); + fv.visitEnd(); + } + { //鏋勯犳柟娉 + mv = cw.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(); + } + + { //field 鏂规硶 + mv = cw.visitMethod(ACC_PUBLIC, "field", "()Ljava/lang/String;", null, null); + mv.visitLdcInsn(fieldname); + mv.visitInsn(ARETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + { //type 鏂规硶 + mv = cw.visitMethod(ACC_PUBLIC, "type", "()Ljava/lang/Class;", null, null); + if (pcolumn == boolean.class) { + mv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "TYPE", "Ljava/lang/Class;"); + } else if (pcolumn == byte.class) { + mv.visitFieldInsn(GETSTATIC, "java/lang/Byte", "TYPE", "Ljava/lang/Class;"); + } else if (pcolumn == char.class) { + mv.visitFieldInsn(GETSTATIC, "java/lang/Character", "TYPE", "Ljava/lang/Class;"); + } else if (pcolumn == short.class) { + mv.visitFieldInsn(GETSTATIC, "java/lang/Short", "TYPE", "Ljava/lang/Class;"); + } else if (pcolumn == int.class) { + mv.visitFieldInsn(GETSTATIC, "java/lang/Integer", "TYPE", "Ljava/lang/Class;"); + } else if (pcolumn == float.class) { + mv.visitFieldInsn(GETSTATIC, "java/lang/Float", "TYPE", "Ljava/lang/Class;"); + } else if (pcolumn == long.class) { + mv.visitFieldInsn(GETSTATIC, "java/lang/Long", "TYPE", "Ljava/lang/Class;"); + } else if (pcolumn == double.class) { + mv.visitFieldInsn(GETSTATIC, "java/lang/Double", "TYPE", "Ljava/lang/Class;"); + } else { + mv.visitLdcInsn(Type.getType(pcolumn)); + } + mv.visitInsn(ARETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + { //genericType + mv = cw.visitMethod(ACC_PUBLIC, "genericType", "()Ljava/lang/reflect/Type;", null, null); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, "_gtype", "Ljava/lang/reflect/Type;"); + mv.visitInsn(ARETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + { //attach + mv = cw.visitMethod(ACC_PUBLIC, "attach", "()Ljava/lang/Object;", "()TE;", null); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, "_attach", "Ljava/lang/Object;"); + mv.visitInsn(ARETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + { //declaringClass 鏂规硶 + mv = cw.visitMethod(ACC_PUBLIC, "declaringClass", "()Ljava/lang/Class;", null, null); + mv.visitLdcInsn(Type.getType(TypeToken.typeToClass(subclass))); + mv.visitInsn(ARETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + { //get 鏂规硶 + mv = cw.visitMethod(ACC_PUBLIC, "get", "(" + interDesc + ")" + columnDesc, null, null); + int m = 1; + if (tgetter == null) { + if (tfield == null) { + mv.visitInsn(ACONST_NULL); + } else { //public tfield + mv.visitVarInsn(ALOAD, 1); + mv.visitFieldInsn(GETFIELD, interName, tfield.getName(), Type.getDescriptor(pcolumn)); + if (pcolumn != column) { + mv.visitMethodInsn(INVOKESTATIC, columnName, "valueOf", "(" + Type.getDescriptor(pcolumn) + ")" + columnDesc, false); + m = 2; + } else { + if (checkCast) mv.visitTypeInsn(CHECKCAST, columnName); + } + } + } else { + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, interName, tgetter.getName(), Type.getMethodDescriptor(tgetter), false); + if (pcolumn != column) { + mv.visitMethodInsn(INVOKESTATIC, columnName, "valueOf", "(" + Type.getDescriptor(pcolumn) + ")" + columnDesc, false); + m = 2; + } else { + if (checkCast) mv.visitTypeInsn(CHECKCAST, columnName); + } + } + mv.visitInsn(ARETURN); + mv.visitMaxs(m, 2); + mv.visitEnd(); + } + { //set 鏂规硶 + mv = cw.visitMethod(ACC_PUBLIC, "set", "(" + interDesc + columnDesc + ")V", null, null); + int m = 2; + if (tsetter == null) { + if (tfield == null || java.lang.reflect.Modifier.isFinal(tfield.getModifiers())) { + m = 0; + } else { //public tfield + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 2); + if (pcolumn != column) { + try { + java.lang.reflect.Method pm = column.getMethod(pcolumn.getSimpleName() + "Value"); + mv.visitMethodInsn(INVOKEVIRTUAL, columnName, pm.getName(), Type.getMethodDescriptor(pm), false); + m = 3; + } catch (Exception ex) { + throw new RuntimeException(ex); //涓嶅彲鑳戒細鍙戠敓 + } + } + if (!tfield.getType().isPrimitive() && tfield.getGenericType() instanceof TypeVariable) { + mv.visitFieldInsn(PUTFIELD, interName, tfield.getName(), "Ljava/lang/Object;"); + } else { + mv.visitFieldInsn(PUTFIELD, interName, tfield.getName(), Type.getDescriptor(pcolumn)); + } + } + } else { + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 2); + if (pcolumn != column) { + try { + java.lang.reflect.Method pm = column.getMethod(pcolumn.getSimpleName() + "Value"); + mv.visitMethodInsn(INVOKEVIRTUAL, columnName, pm.getName(), Type.getMethodDescriptor(pm), false); + m = 3; + } catch (Exception ex) { + throw new RuntimeException(ex); //涓嶅彲鑳戒細鍙戠敓 + } + } + mv.visitMethodInsn(INVOKEVIRTUAL, interName, tsetter.getName(), Type.getMethodDescriptor(tsetter), false); + } + mv.visitInsn(RETURN); + mv.visitMaxs(m, 3); + mv.visitEnd(); + } + { //铏氭嫙get + mv = cw.visitMethod(ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, "get", "(Ljava/lang/Object;)Ljava/lang/Object;", null, null); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 1); + mv.visitTypeInsn(CHECKCAST, interName); + mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "get", "(" + interDesc + ")" + columnDesc, false); + mv.visitInsn(ARETURN); + mv.visitMaxs(2, 2); + mv.visitEnd(); + } + {//铏氭嫙set + mv = cw.visitMethod(ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, "set", "(Ljava/lang/Object;Ljava/lang/Object;)V", null, null); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 1); + mv.visitTypeInsn(CHECKCAST, interName); + mv.visitVarInsn(ALOAD, 2); + mv.visitTypeInsn(CHECKCAST, columnName); + mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "set", "(" + interDesc + columnDesc + ")V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(3, 3); + mv.visitEnd(); + } + { //toString鍑芥暟 + mv = cw.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null); + //mv.setDebug(true); + mv.visitLdcInsn(tostr); + mv.visitInsn(ARETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + cw.visitEnd(); + + byte[] bytes = cw.toByteArray(); + Class newClazz = (Class) new ClassLoader(loader) { + public final Class loadClass(String name, byte[] b) { + return defineClass(name, b, 0, b.length); + } + }.loadClass(newDynName.replace('/', '.'), bytes); + RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, newClazz); + RedkaleClassLoader.putReflectionDeclaredConstructors(newClazz, newDynName.replace('/', '.')); + try { + Attribute rs = newClazz.getDeclaredConstructor().newInstance(); + java.lang.reflect.Field _gtype = rs.getClass().getDeclaredField("_gtype"); + _gtype.setAccessible(true); + _gtype.set(rs, generictype); + RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), _gtype); + java.lang.reflect.Field _attach = rs.getClass().getDeclaredField("_attach"); + _attach.setAccessible(true); + _attach.set(rs, attach); + RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), _attach); + return rs; + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + + /** + * 鏍规嵁Class銆佸瓧娈靛悕銆佸瓧娈电被鍨嬨乬etter鍜宻etter鏂规硶鐢熸垚 Attribute 瀵硅薄銆 clazz銆乫ieldname銆乫ieldtype閮戒笉鑳戒负null + * + * @param 渚濋檮绫荤殑绫诲瀷 + * @param 瀛楁绫诲瀷 + * @param clazz 鎸囧畾渚濋檮鐨勭被 + * @param fieldname 瀛楁鍚 + * @param fieldtype 瀛楁绫诲瀷 + * @param getter getter鏂规硶 + * @param setter setter鏂规硶 + * + * @return Attribute瀵硅薄 + */ + public static Attribute create(final Class clazz, final String fieldname, final Class fieldtype, final Function getter, final BiConsumer setter) { + return create(clazz, fieldname, fieldtype, fieldtype, getter, setter); + } + + /** + * 鏍规嵁Class銆佸瓧娈靛悕銆佸瓧娈电被鍨嬨乬etter鍜宻etter鏂规硶鐢熸垚 Attribute 瀵硅薄銆 clazz銆乫ieldname銆乫ieldtype閮戒笉鑳戒负null + * + * @param 渚濋檮绫荤殑绫诲瀷 + * @param 瀛楁绫诲瀷 + * @param clazz 鎸囧畾渚濋檮鐨勭被 + * @param fieldname 瀛楁鍚 + * @param fieldtype 瀛楁绫诲瀷 + * @param getter getter鏂规硶 + * @param setter setter鏂规硶 + * @param attach 闄勫姞瀵硅薄 + * + * @return Attribute瀵硅薄 + */ + public static Attribute create(final Class clazz, final String fieldname, final Class fieldtype, final Function getter, final BiConsumer setter, Object attach) { + return create(clazz, fieldname, fieldtype, fieldtype, getter, setter, attach); + } + + /** + * 鏍规嵁Class銆佸瓧娈靛悕銆佸瓧娈电被鍨嬨乬etter鍜宻etter鏂规硶鐢熸垚 Attribute 瀵硅薄銆 clazz銆乫ieldname銆乫ieldtype閮戒笉鑳戒负null + * + * @param 渚濋檮绫荤殑绫诲瀷 + * @param 瀛楁绫诲瀷 + * @param clazz 鎸囧畾渚濋檮鐨勭被 + * @param fieldname 瀛楁鍚 + * @param fieldtype 瀛楁绫诲瀷 + * @param fieldGenericType 瀛楁娉涘瀷 + * @param getter getter鏂规硶 + * @param setter setter鏂规硶 + * + * @return Attribute瀵硅薄 + */ + public static Attribute create(final Class clazz, final String fieldname, final Class fieldtype, + final java.lang.reflect.Type fieldGenericType, final Function getter, final BiConsumer setter) { + return create(clazz, fieldname, fieldtype, fieldGenericType, getter, setter, null); + } + + /** + * 鏍规嵁Class銆佸瓧娈靛悕銆佸瓧娈电被鍨嬨乬etter鍜宻etter鏂规硶鐢熸垚 Attribute 瀵硅薄銆 clazz銆乫ieldname銆乫ieldtype閮戒笉鑳戒负null + * + * @param 渚濋檮绫荤殑绫诲瀷 + * @param 瀛楁绫诲瀷 + * @param clazz 鎸囧畾渚濋檮鐨勭被 + * @param fieldname 瀛楁鍚 + * @param fieldtype 瀛楁绫诲瀷 + * @param fieldGenericType 瀛楁娉涘瀷 + * @param getter getter鏂规硶 + * @param setter setter鏂规硶 + * @param attach 闄勫姞瀵硅薄 + * + * @return Attribute瀵硅薄 + */ + public static Attribute create(final Class clazz, final String fieldname, final Class fieldtype, + final java.lang.reflect.Type fieldGenericType, final Function getter, final BiConsumer setter, final Object attach) { + Objects.requireNonNull(clazz); + Objects.requireNonNull(fieldname); + Objects.requireNonNull(fieldtype); + String str = Attribute.class.getSimpleName() + "_" + fieldname + "_" + fieldtype.getSimpleName(); + if (getter != null) str += "_getter"; + if (setter != null) str += "_setter"; + final String tostr = str; + return new Attribute() { + @Override + public Class type() { + return fieldtype; + } + + @Override + public java.lang.reflect.Type genericType() { + return fieldGenericType; + } + + @Override + public E attach() { + return (E) attach; + } + + @Override + public Class declaringClass() { + return clazz; + } + + @Override + public String field() { + return fieldname; + } + + @Override + public F get(T obj) { + return getter == null ? null : getter.apply(obj); + } + + @Override + public void set(T obj, F value) { + if (setter != null) setter.accept(obj, value); + } + + @Override + public String toString() { + return tostr; + } + }; + } +} diff --git a/src/main/java/org/redkale/util/AutoLoad.java b/src/main/java/org/redkale/util/AutoLoad.java index c42284976..ef0fadf4a 100644 --- a/src/main/java/org/redkale/util/AutoLoad.java +++ b/src/main/java/org/redkale/util/AutoLoad.java @@ -1,26 +1,26 @@ -/* - * 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.util; - -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; -import java.lang.annotation.*; - -/** - * 鑷姩鍔犺浇銆 浣跨敤鍦烘櫙锛 - * 1銆佽鏍囪涓@AutoLoad(false)鐨凷ervice绫讳笉浼氳鑷姩鍔犺浇, 褰撹渚濊禆鏃舵墠浼氳鍔犺浇 - * 2銆佽鏍囪涓@AutoLoad(false)鐨凷ervlet绫讳笉浼氳鑷姩鍔犺浇 - * - *

璇︽儏瑙: https://redkale.org - * @author zhangjx - */ -@Documented -@Target({TYPE}) -@Retention(RUNTIME) -public @interface AutoLoad { - - boolean value() default true; -} +/* + * 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.util; + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import java.lang.annotation.*; + +/** + * 鑷姩鍔犺浇銆 浣跨敤鍦烘櫙锛 + * 1銆佽鏍囪涓@AutoLoad(false)鐨凷ervice绫讳笉浼氳鑷姩鍔犺浇, 褰撹渚濊禆鏃舵墠浼氳鍔犺浇 + * 2銆佽鏍囪涓@AutoLoad(false)鐨凷ervlet绫讳笉浼氳鑷姩鍔犺浇 + * + *

璇︽儏瑙: https://redkale.org + * @author zhangjx + */ +@Documented +@Target({TYPE}) +@Retention(RUNTIME) +public @interface AutoLoad { + + boolean value() default true; +} diff --git a/src/main/java/org/redkale/util/Bean.java b/src/main/java/org/redkale/util/Bean.java index c34c0ba64..60719440d 100644 --- a/src/main/java/org/redkale/util/Bean.java +++ b/src/main/java/org/redkale/util/Bean.java @@ -1,23 +1,23 @@ -/* - * 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.util; - -import java.lang.annotation.*; -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * 鏍囪鍙傛暟bean - * - * @since 2.5.0 - */ -@Inherited -@Documented -@Target(TYPE) -@Retention(RUNTIME) -public @interface Bean { - -} +/* + * 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.util; + +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * 鏍囪鍙傛暟bean + * + * @since 2.5.0 + */ +@Inherited +@Documented +@Target(TYPE) +@Retention(RUNTIME) +public @interface Bean { + +} diff --git a/src/main/java/org/redkale/util/ByteArray.java b/src/main/java/org/redkale/util/ByteArray.java index c1a20e1df..176c17882 100644 --- a/src/main/java/org/redkale/util/ByteArray.java +++ b/src/main/java/org/redkale/util/ByteArray.java @@ -1,965 +1,965 @@ -/* - * 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.util; - -import java.io.*; -import java.nio.ByteBuffer; -import java.nio.charset.*; -import java.util.Arrays; - -/** - * 绠鍗曠殑byte[]鎿嶄綔绫汇 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public final class ByteArray implements ByteTuple { - - private byte[] content; - - private int count; - - public ByteArray() { - this(1024); - } - - public ByteArray(int size) { - content = new byte[Math.max(128, size)]; - } - - public ByteArray(ByteTuple tuple) { - content = tuple.content(); - count = tuple.length(); - } - - public ByteArray(byte[] bs) { - content = bs; - count = 0; - } - - /** - * 娓呯┖鏁版嵁,灏哻ount缃负0,骞朵笉娓呮帀byte[]鐨勫唴瀹 - * - * @return ByteArray 鏄惁鐩稿悓 - */ - public ByteArray clear() { - this.count = 0; - return this; - } - - /** - * 鐢熸垚涓涓狾utputStream - * - * @return OutputStream - */ - public OutputStream newOutputStream() { - return new OutputStream() { - @Override - public void write(int b) throws IOException { - ByteArray.this.put((byte) b); - } - }; - } - - /** - * 姣旇緝鍐呭鏄惁鐩稿悓 - * - * @param bytes 寰呮瘮杈冨唴瀹 - * - * @return 鏄惁鐩稿悓 - */ - public boolean equal(final byte[] bytes) { - if (bytes == null) return false; - int len = count; - if (len != bytes.length) return false; - byte[] ba = content; - for (int i = 0; i < len; i++) { - if (ba[i] != bytes[i]) return false; - } - return true; - } - - /** - * 鍒ゆ柇鍐呭鏄惁涓虹┖ - * - * @return 鏄惁涓虹┖ - */ - public boolean isEmpty() { - return count == 0; - } - - /** - * 鑾峰彇瀛楄妭闀垮害 - * - * @return 闀垮害 - */ - @Override - public int length() { - return count; - } - - @Override - public int offset() { - return 0; - } - - /** - * 鑾峰彇鎸囧畾浣嶇疆鐨刡yte鍊,椤荤‘淇0 <= index < length - * - * @param index 浣嶇疆 - * - * @return byte鍊 - */ - public byte get(int index) { - return content[index]; - } - - /** - * 鑾峰彇鎸囧畾浣嶇疆鐨刢har鍊,椤荤‘淇0 <= offset+2 < length - * - * @param offset 浣嶇疆 - * - * @return short鍊 - */ - public char getChar(int offset) { - return (char) ((0xff00 & (content[offset] << 8)) | (0xff & content[offset + 1])); - } - - /** - * 鑾峰彇鎸囧畾浣嶇疆鐨剆hort鍊,椤荤‘淇0 <= offset+2 < length - * - * @param offset 浣嶇疆 - * - * @return short鍊 - */ - public int getShort(int offset) { - return (short) ((0xff00 & (content[offset] << 8)) | (0xff & content[offset + 1])); - } - - /** - * 鑾峰彇鎸囧畾浣嶇疆鐨刬nt鍊,椤荤‘淇0 <= offset+4 < length - * - * @param offset 浣嶇疆 - * - * @return int鍊 - */ - public int getInt(int offset) { - return ((content[offset] & 0xff) << 24) | ((content[offset + 1] & 0xff) << 16) | ((content[offset + 2] & 0xff) << 8) | (content[offset + 3] & 0xff); - } - - /** - * 鑾峰彇鎸囧畾浣嶇疆鐨刦loat鍊,椤荤‘淇0 <= offset+4 < length - * - * @param offset 浣嶇疆 - * - * @return float鍊 - */ - public float getFloat(int offset) { - return Float.intBitsToFloat(getInt(offset)); - } - - /** - * 鑾峰彇鎸囧畾浣嶇疆鐨刲ong鍊,椤荤‘淇0 <= offset+8 < length - * - * @param offset 浣嶇疆 - * - * @return long鍊 - */ - public long getLong(int offset) { - return (((long) content[offset] & 0xff) << 56) | (((long) content[offset + 1] & 0xff) << 48) | (((long) content[offset + 2] & 0xff) << 40) | (((long) content[offset + 3] & 0xff) << 32) - | (((long) content[offset + 4] & 0xff) << 24) | (((long) content[offset + 5] & 0xff) << 16) | (((long) content[offset + 6] & 0xff) << 8) | ((long) content[offset + 7] & 0xff); - } - - /** - * 鑾峰彇鎸囧畾浣嶇疆鐨刣ouble鍊,椤荤‘淇0 <= offset+8 < length - * - * @param offset 浣嶇疆 - * - * @return double鍊 - */ - public double getDouble(int offset) { - return Double.longBitsToDouble(getLong(offset)); - } - - /** - * 鑾峰彇鏈鍚庝竴涓瓧鑺傚,璋冪敤鍓嶉』淇濊瘉count澶т簬0 - * - * @return byte鍊 - */ - public byte getLastByte() { - return content[count - 1]; - } - - /** - * count鍑忎竴,璋冪敤鍓嶉』淇濊瘉count澶т簬0 - * - */ - public void backCount() { - count--; - } - - /** - * 灏哹uf鍐呭瑕嗙洊鍒版湰瀵硅薄鍐呭涓 - * - * @param buf 鐩爣瀹瑰櫒 - */ - public void copyTo(byte[] buf) { - System.arraycopy(this.content, 0, buf, 0, count); - } - - /** - * 灏咮yteBuffer鐨勫唴瀹硅鍙栧埌鏈璞′腑 - * - * @param buffer ByteBuffer - */ - public void put(ByteBuffer buffer) { - if (buffer == null) return; - int remain = buffer.remaining(); - if (remain == 0) return; - int l = this.content.length - count; - if (remain > l) { - byte[] ns = new byte[this.content.length + remain]; - if (count > 0) System.arraycopy(content, 0, ns, 0, count); - this.content = ns; - } - buffer.get(content, count, remain); - count += remain; - } - - /** - * 灏哸rray鐨勫唴瀹瑰紩鐢ㄧ粰鏈璞 - * - * @param array ByteArray - */ - public void directFrom(ByteArray array) { - if (array != null) { - this.content = array.content; - this.count = array.count; - } - } - - /** - * 灏哻ontent鐨勫唴瀹圭洿鎺ョ粰鏈璞 - * - * @param content 鍐呭 - * @param count 闀垮害 - */ - public void directFrom(byte[] content, int count) { - this.content = content; - this.count = count; - } - - /** - * 灏嗘湰瀵硅薄鐨勫唴瀹瑰紩鐢ㄥ鍒剁粰array - * - * @param array ByteArray - */ - public void directTo(ByteArray array) { - if (array != null) { - array.content = this.content; - array.count = this.count; - } - } - - /** - * 鐩存帴鑾峰彇鍏ㄩ儴鏁版嵁, 瀹為檯鏁版嵁闇瑕佹牴鎹甽ength闀垮害鏉ユ埅鍙 - * - * @return byte[] - */ - @Override - public byte[] content() { - return content; - } - - /** - * 鑾峰彇byte[] - * - * @return byte[] - */ - public byte[] getBytes() { - return Arrays.copyOf(content, count); - } - - /** - * 鑾峰彇byte[] - * - * @param offset 鍋忕Щ浣 - * @param length 闀垮害 - * - * @return byte[] - */ - public byte[] getBytes(int offset, int length) { - if (length < 1) return new byte[0]; - byte[] bs = new byte[length]; - System.arraycopy(this.content, offset, bs, 0, length); - return bs; - } - - /** - * 鏌ユ壘鎸囧畾鍊肩涓娆″嚭鐜扮殑浣嶇疆,娌℃湁杩斿洖-1 - * - * @param value 鏌ヨ鍊 - * - * @return 鎵鍦ㄤ綅缃 - */ - public int find(byte value) { - return find(0, value); - } - - /** - * 浠庢寚瀹氱殑璧峰浣嶇疆鏌ヨvalue鍊煎嚭鐜扮殑浣嶇疆,娌℃湁杩斿洖-1 - * - * @param offset 璧峰浣嶇疆 - * @param value 鏌ヨ鍊 - * - * @return 鎵鍦ㄤ綅缃 - */ - public int find(int offset, char value) { - return find(offset, (byte) value); - } - - /** - * 浠庢寚瀹氱殑璧峰浣嶇疆鏌ヨvalue鍊煎嚭鐜扮殑浣嶇疆,娌℃湁杩斿洖-1 - * - * @param offset 璧峰浣嶇疆 - * @param value 鏌ヨ鍊 - * - * @return 鎵鍦ㄤ綅缃 - */ - public int find(int offset, byte value) { - return find(offset, -1, value); - } - - /** - * 浠庢寚瀹氱殑璧峰浣嶇疆鍜岄暱搴︽煡璇alue鍊煎嚭鐜扮殑浣嶇疆,娌℃湁杩斿洖-1 - * - * @param offset 璧峰浣嶇疆 - * @param limit 闀垮害闄愬埗 - * @param value 鏌ヨ鍊 - * - * @return 鎵鍦ㄤ綅缃 - */ - public int find(int offset, int limit, char value) { - return find(offset, limit, (byte) value); - } - - /** - * 浠庢寚瀹氱殑璧峰浣嶇疆鍜岄暱搴︽煡璇alue鍊煎嚭鐜扮殑浣嶇疆,娌℃湁杩斿洖-1 - * - * @param offset 璧峰浣嶇疆 - * @param limit 闀垮害闄愬埗 - * @param value 鏌ヨ鍊 - * - * @return 鎵鍦ㄤ綅缃 - */ - public int find(int offset, int limit, byte value) { - byte[] bytes = this.content; - int end = limit > 0 ? limit : count; - for (int i = offset; i < end; i++) { - if (bytes[i] == value) return i; - } - return -1; - } - - /** - * 绉婚櫎鏈鍚庝竴涓瓧鑺 - * - * @return ByteArray - */ - public ByteArray removeLastByte() { - if (count > 0) count--; - return this; - } - - /** - * 鍐欏叆涓涓猚har鍊 - * - * @param value int鍊 - * - * @return ByteArray - */ - public ByteArray putChar(char value) { - return this.put((byte) (value >> 8 & 0xFF), - (byte) (value & 0xFF)); - } - - /** - * 鍐欏叆涓涓猚har鍊硷紝 content.length 蹇呴』涓嶈兘灏忎簬offset+2 - * - * @param offset 鍋忕Щ閲 - * @param value char鍊 - * - * @return ByteArray - */ - public ByteArray putChar(int offset, char value) { - return this.put(offset, (byte) (value >> 8 & 0xFF), - (byte) (value & 0xFF)); - } - - /** - * 鍐欏叆涓涓猻hort鍊 - * - * @param value short鍊 - * - * @return ByteArray - */ - public ByteArray putShort(short value) { - return this.put((byte) (value >> 8 & 0xFF), - (byte) (value & 0xFF)); - } - - /** - * 鍐欏叆涓涓猻hort鍊 - * - * @param value short鍊 - * - * @return ByteArray - */ - public ByteArray putShort(char value) { - int v = value; - return this.put((byte) (v >> 8 & 0xFF), - (byte) (v & 0xFF)); - } - - /** - * 鍐欏叆涓涓猻hort鍊 - * - * @param value short鍊 - * - * @return ByteArray - */ - public ByteArray putShort(int value) { - return this.put((byte) (value >> 8 & 0xFF), - (byte) (value & 0xFF)); - } - - /** - * 鍐欏叆涓涓猻hort鍊 - * - * @param value short鍊 - * - * @return ByteArray - */ - public ByteArray putUnsignedShort(int value) { - return this.put((byte) (value >> 8 & 0xFF), - (byte) (value & 0xFF)); - } - - /** - * 鍐欏叆涓涓棤绗﹀彿short鍊硷紝 content.length 蹇呴』涓嶈兘灏忎簬offset+2 - * - * @param offset 鍋忕Щ閲 - * @param value short鍊 - * - * @return ByteArray - */ - public ByteArray putUnsignedShort(int offset, int value) { - return this.put(offset, (byte) (value >> 8 & 0xFF), - (byte) (value & 0xFF)); - } - - /** - * 鍐欏叆涓涓猻hort鍊硷紝 content.length 蹇呴』涓嶈兘灏忎簬offset+2 - * - * @param offset 鍋忕Щ閲 - * @param value short鍊 - * - * @return ByteArray - */ - public ByteArray putShort(int offset, short value) { - return this.put(offset, (byte) (value >> 8 & 0xFF), - (byte) (value & 0xFF)); - } - - /** - * 鍐欏叆涓涓3瀛楄妭鐨刬nt鍊 - * - * @param value int鍊 - * - * @return ByteArray - */ - public ByteArray putMedium(int value) { - return this.put((byte) (value >> 16 & 0xFF), - (byte) (value >> 8 & 0xFF), - (byte) (value & 0xFF)); - } - - /** - * 鎸囧畾浣嶇疆鍐欏叆涓涓3瀛楄妭鐨刬nt鍊硷紝 content.length 蹇呴』涓嶈兘灏忎簬offset+3 - * - * @param offset 鍋忕Щ閲 - * @param value int鍊 - * - * @return ByteArray - */ - public ByteArray putMedium(int offset, int value) { - content[offset] = (byte) (value >> 16 & 0xFF); - content[offset + 1] = (byte) (value >> 8 & 0xFF); - content[offset + 2] = (byte) (value & 0xFF); - return this; - } - - /** - * 鍐欏叆涓涓3瀛楄妭鐨刬nt鍊 - * - * @param value int鍊 - * - * @return ByteArray - */ - public ByteArray putUnsignedMedium(int value) { - return this.put((byte) (value >> 16 & 0xFF), - (byte) (value >> 8 & 0xFF), - (byte) (value & 0xFF)); - } - - /** - * 鎸囧畾浣嶇疆鍐欏叆涓涓3瀛楄妭鐨刬nt鍊硷紝 content.length 蹇呴』涓嶈兘灏忎簬offset+3 - * - * @param offset 鍋忕Щ閲 - * @param value int鍊 - * - * @return ByteArray - */ - public ByteArray putUnsignedMedium(int offset, int value) { - content[offset] = (byte) (value >> 16 & 0xFF); - content[offset + 1] = (byte) (value >> 8 & 0xFF); - content[offset + 2] = (byte) (value & 0xFF); - return this; - } - - /** - * 鍐欏叆涓涓猧nt鍊 - * - * @param value int鍊 - * - * @return ByteArray - */ - public ByteArray putInt(int value) { - return this.put((byte) (value >> 24 & 0xFF), - (byte) (value >> 16 & 0xFF), - (byte) (value >> 8 & 0xFF), - (byte) (value & 0xFF)); - } - - /** - * 鍐欏叆涓涓猧nt鍊 - * - * @param value int鍊 - * - * @return ByteArray - */ - public ByteArray putUnsignedInt(long value) { - return this.put((byte) (value >> 24 & 0xFF), - (byte) (value >> 16 & 0xFF), - (byte) (value >> 8 & 0xFF), - (byte) (value & 0xFF)); - } - - /** - * 鎸囧畾浣嶇疆鍐欏叆涓涓猧nt鍊硷紝 content.length 蹇呴』涓嶈兘灏忎簬offset+4 - * - * @param offset 鍋忕Щ閲 - * @param value int鍊 - * - * @return ByteArray - */ - public ByteArray putInt(int offset, int value) { - content[offset] = (byte) (value >> 24 & 0xFF); - content[offset + 1] = (byte) (value >> 16 & 0xFF); - content[offset + 2] = (byte) (value >> 8 & 0xFF); - content[offset + 3] = (byte) (value & 0xFF); - return this; - } - - /** - * 鎸囧畾浣嶇疆鍐欏叆涓涓 鏃犵鍙穒nt鍊硷紝 content.length 蹇呴』涓嶈兘灏忎簬offset+4 - * - * @param offset 鍋忕Щ閲 - * @param value int鍊 - * - * @return ByteArray - */ - public ByteArray putUnsignedInt(int offset, long value) { - content[offset] = (byte) (value >> 24 & 0xFF); - content[offset + 1] = (byte) (value >> 16 & 0xFF); - content[offset + 2] = (byte) (value >> 8 & 0xFF); - content[offset + 3] = (byte) (value & 0xFF); - return this; - } - - /** - * 鍐欏叆涓涓猣loat鍊 - * - * @param value float鍊 - * - * @return ByteArray - */ - public ByteArray putFloat(float value) { - return this.putInt(Float.floatToIntBits(value)); - } - - /** - * 鎸囧畾浣嶇疆鍐欏叆涓涓猣loat鍊硷紝 content.length 蹇呴』涓嶈兘灏忎簬offset+4 - * - * @param offset 鍋忕Щ閲 - * @param value float鍊 - * - * @return ByteArray - */ - public ByteArray putFloat(int offset, float value) { - return this.putInt(offset, Float.floatToIntBits(value)); - } - - /** - * 鍐欏叆涓涓猯ong鍊 - * - * @param value long鍊 - * - * @return ByteArray - */ - public ByteArray putLong(long value) { - return this.put((byte) (value >> 56 & 0xFF), - (byte) (value >> 48 & 0xFF), - (byte) (value >> 40 & 0xFF), - (byte) (value >> 32 & 0xFF), - (byte) (value >> 24 & 0xFF), - (byte) (value >> 16 & 0xFF), - (byte) (value >> 8 & 0xFF), - (byte) (value & 0xFF)); - } - - /** - * 鎸囧畾浣嶇疆鍐欏叆涓涓猯ong鍊硷紝 content.length 蹇呴』涓嶈兘灏忎簬offset+8 - * - * @param offset 鍋忕Щ閲 - * @param value long鍊 - * - * @return ByteArray - */ - public ByteArray putLong(int offset, long value) { - return this.put(offset, (byte) (value >> 56 & 0xFF), - (byte) (value >> 48 & 0xFF), - (byte) (value >> 40 & 0xFF), - (byte) (value >> 32 & 0xFF), - (byte) (value >> 24 & 0xFF), - (byte) (value >> 16 & 0xFF), - (byte) (value >> 8 & 0xFF), - (byte) (value & 0xFF)); - } - - /** - * 鍐欏叆涓涓猟ouble鍊 - * - * @param value double鍊 - * - * @return ByteArray - */ - public ByteArray putDouble(double value) { - return this.putLong(Double.doubleToLongBits(value)); - } - - /** - * 鎸囧畾浣嶇疆鍐欏叆涓涓猟ouble鍊硷紝 content.length 蹇呴』涓嶈兘灏忎簬offset+8 - * - * @param offset 鍋忕Щ閲 - * @param value double鍊 - * - * @return ByteArray - */ - public ByteArray putDouble(int offset, double value) { - return this.putLong(offset, Double.doubleToLongBits(value)); - } - - public ByteArray putByte(short value) { - return put((byte) value); - } - - public ByteArray putByte(char value) { - return put((byte) value); - } - - public ByteArray putByte(int value) { - return put((byte) value); - } - - /** - * 鍐欏叆涓涓猙yte鍊 - * - * @param value byte鍊 - * - * @return ByteArray - */ - public ByteArray put(byte value) { - if (count >= content.length - 1) { - byte[] ns = new byte[content.length + 8]; - System.arraycopy(content, 0, ns, 0, count); - this.content = ns; - } - content[count++] = value; - return this; - } - - /** - * 鍐欏叆涓涓猙yte鍊硷紝 content.length 蹇呴』涓嶈兘灏忎簬offset+1 - * - * @param offset 鍋忕Щ閲 - * @param value byte鍊 - * - * @return ByteArray - */ - public ByteArray putByte(int offset, byte value) { - content[offset] = value; - return this; - } - - /** - * 鍐欏叆涓涓猙yte鍊硷紝 content.length 蹇呴』涓嶈兘灏忎簬offset+1 - * - * @param offset 鍋忕Щ閲 - * @param value byte鍊 - * - * @return ByteArray - */ - public ByteArray putByte(int offset, int value) { - content[offset] = (byte) value; - return this; - } - - /** - * 鍐欏叆涓缁刡yte鍊 - * - * @param values 涓缁刡yte鍊 - * - * @return ByteArray - */ - public ByteArray put(byte... values) { - if (values.length < 1) return this; - if (count >= content.length - values.length) { - byte[] ns = new byte[content.length + values.length]; - System.arraycopy(content, 0, ns, 0, count); - this.content = ns; - } - System.arraycopy(values, 0, content, count, values.length); - count += values.length; - return this; - } - - /** - * 鎸囧畾浣嶇疆鍐欏叆涓缁刡yte鍊硷紝 content.length 蹇呴』涓嶈兘灏忎簬offset+values.length - * - * @param offset 鍋忕Щ閲 - * @param values 涓缁刡yte鍊 - * - * @return ByteArray - */ - public ByteArray put(int offset, byte... values) { - if (values.length < 1) throw new IllegalArgumentException(); - System.arraycopy(values, 0, content, offset, values.length); - return this; - } - - /** - * 鍐欏叆涓缁刡yte鍊 - * - * @param values 涓缁刡yte鍊 - * @param offset 鍋忕Щ閲 - * @param length 闀垮害 - * - * @return ByteArray - */ - public ByteArray put(byte[] values, int offset, int length) { - if (count >= content.length - length) { - byte[] ns = new byte[content.length + Math.max(16, length)]; - System.arraycopy(content, 0, ns, 0, count); - this.content = ns; - } - System.arraycopy(values, offset, content, count, length); - count += length; - return this; - } - - /** - * 鍐欏叆涓缁刡yte鍊硷紝 content.length 蹇呴』涓嶈兘灏忎簬poffset+length - * - * @param poffset 鍋忕Щ閲 - * @param values 涓缁刡yte鍊 - * @param offset 鍋忕Щ閲 - * @param length 闀垮害 - * - * @return ByteArray - */ - public ByteArray put(int poffset, byte[] values, int offset, int length) { - System.arraycopy(values, offset, content, poffset, length); - return this; - } - - /** - * 鍐欏叆ByteArray涓殑涓閮ㄥ垎 - * - * @param array ByteArray - * @param offset 鍋忕Щ閲 - * @param length 闀垮害 - * - * @return ByteArray - */ - public ByteArray put(ByteArray array, int offset, int length) { - if (count >= content.length - length) { - byte[] ns = new byte[content.length + Math.max(16, length)]; - System.arraycopy(content, 0, ns, 0, count); - this.content = ns; - } - System.arraycopy(array.content, offset, content, count, length); - count += length; - return this; - } - - /** - * 鍐欏叆ByteBuffer鎸囧畾闀垮害鐨勬暟鎹 - * - * @param buffer 鏁版嵁 - * @param len 鎸囧畾闀垮害 - * - * @return ByteArray - */ - public ByteArray put(ByteBuffer buffer, int len) { - if (len < 1) return this; - if (count >= content.length - len) { - byte[] ns = new byte[content.length + len]; - System.arraycopy(content, 0, ns, 0, count); - this.content = ns; - } - buffer.get(content, count, len); - count += len; - return this; - } - - @Override - public String toString() { - return new String(content, 0, count); - } - - /** - * 鎸夋寚瀹氬瓧绗﹂泦杞垚瀛楃涓 - * - * @param charset 瀛楃闆 - * - * @return 瀛楃涓 - */ - public String toString(final Charset charset) { - return toString(0, count, charset); - } - - /** - * 灏嗘寚瀹氱殑璧峰浣嶇疆鍜岄暱搴︽寜鎸囧畾瀛楃闆嗚浆鎴愬瓧绗︿覆 - * - * @param offset 璧峰浣嶇疆 - * @param len 闀垮害 - * @param charset 瀛楃闆 - * - * @return 瀛楃涓 - */ - public String toString(final int offset, int len, final Charset charset) { - if (charset == null) return new String(content, offset, len, StandardCharsets.UTF_8); - return new String(content, offset, len, charset); - } - - /** - * 灏嗘寚瀹氱殑璧峰浣嶇疆鎸夋寚瀹氬瓧绗﹂泦杞垚瀛楃涓 - * - * @param offset 璧峰浣嶇疆 - * @param charset 瀛楃闆 - * - * @return 瀛楃涓 - */ - public String toString(final int offset, final Charset charset) { - if (charset == null) return new String(content, offset, count - offset, StandardCharsets.UTF_8); - return new String(content, offset, count - offset, charset); - } - - /** - * 灏嗘寚瀹氱殑璧峰浣嶇疆鍜岄暱搴︽寜鎸囧畾瀛楃闆嗚浆鎴愬瓧绗︿覆,骞秚rim - * - * @param offset 璧峰浣嶇疆 - * @param len 闀垮害 - * @param charset 瀛楃闆 - * - * @return 瀛楃涓 - */ -// public String toTrimString(int offset, int len, final Charset charset) { -// if (len == 0) return ""; -// int st = 0; -// while (st < len && (content[offset] & 0xff) <= ' ') { -// offset++; -// st++; -// } -// while (len > 0 && (content[len - 1] & 0xff) <= ' ') len--; -// if (len == 0) return ""; -// if (charset == null) return new String(content, offset, len - st, StandardCharsets.UTF_8); -// return new String(content, offset, len - st, charset); -// } - /** - * 灏嗘寚瀹氱殑璧峰浣嶇疆鍜岄暱搴︽寜鎸囧畾瀛楃闆嗗苟杞箟鍚庤浆鎴愬瓧绗︿覆 - * - * @param charset 瀛楃闆 - * - * @return 瀛楃涓 - */ -// public String toDecodeString(final Charset charset) { -// return toDecodeString(0, count, charset); -// } - /** - * 灏嗘寚瀹氱殑璧峰浣嶇疆鍜岄暱搴︽寜鎸囧畾瀛楃闆嗗苟杞箟鍚庤浆鎴愬瓧绗︿覆 - * - * @param offset 璧峰浣嶇疆 - * @param len 闀垮害 - * @param charset 瀛楃闆 - * - * @return 瀛楃涓 - */ -// public String toDecodeString(final int offset, int len, final Charset charset) { -// int start = offset; -// final int end = offset + len; -// boolean flag = false; //鏄惁闇瑕佽浆涔 -// byte[] bs = content; -// for (int i = offset; i < end; i++) { -// if (content[i] == '+' || content[i] == '%') { -// flag = true; -// break; -// } -// } -// if (flag) { -// int index = 0; -// bs = new byte[len]; -// for (int i = offset; i < end; i++) { -// switch (content[i]) { -// case '+': -// bs[index] = ' '; -// break; -// case '%': -// bs[index] = (byte) ((hexBit(content[++i]) * 16 + hexBit(content[++i]))); -// break; -// default: -// bs[index] = content[i]; -// break; -// } -// index++; -// } -// start = 0; -// len = index; -// } -// if (charset == null) return new String(bs, start, len, StandardCharsets.UTF_8); -// return new String(bs, start, len, charset); -// } -// -// private static int hexBit(byte b) { -// if ('0' <= b && '9' >= b) return b - '0'; -// if ('a' <= b && 'z' >= b) return b - 'a' + 10; -// if ('A' <= b && 'Z' >= b) return b - 'A' + 10; -// return b; -// } -} +/* + * 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.util; + +import java.io.*; +import java.nio.ByteBuffer; +import java.nio.charset.*; +import java.util.Arrays; + +/** + * 绠鍗曠殑byte[]鎿嶄綔绫汇 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public final class ByteArray implements ByteTuple { + + private byte[] content; + + private int count; + + public ByteArray() { + this(1024); + } + + public ByteArray(int size) { + content = new byte[Math.max(128, size)]; + } + + public ByteArray(ByteTuple tuple) { + content = tuple.content(); + count = tuple.length(); + } + + public ByteArray(byte[] bs) { + content = bs; + count = 0; + } + + /** + * 娓呯┖鏁版嵁,灏哻ount缃负0,骞朵笉娓呮帀byte[]鐨勫唴瀹 + * + * @return ByteArray 鏄惁鐩稿悓 + */ + public ByteArray clear() { + this.count = 0; + return this; + } + + /** + * 鐢熸垚涓涓狾utputStream + * + * @return OutputStream + */ + public OutputStream newOutputStream() { + return new OutputStream() { + @Override + public void write(int b) throws IOException { + ByteArray.this.put((byte) b); + } + }; + } + + /** + * 姣旇緝鍐呭鏄惁鐩稿悓 + * + * @param bytes 寰呮瘮杈冨唴瀹 + * + * @return 鏄惁鐩稿悓 + */ + public boolean equal(final byte[] bytes) { + if (bytes == null) return false; + int len = count; + if (len != bytes.length) return false; + byte[] ba = content; + for (int i = 0; i < len; i++) { + if (ba[i] != bytes[i]) return false; + } + return true; + } + + /** + * 鍒ゆ柇鍐呭鏄惁涓虹┖ + * + * @return 鏄惁涓虹┖ + */ + public boolean isEmpty() { + return count == 0; + } + + /** + * 鑾峰彇瀛楄妭闀垮害 + * + * @return 闀垮害 + */ + @Override + public int length() { + return count; + } + + @Override + public int offset() { + return 0; + } + + /** + * 鑾峰彇鎸囧畾浣嶇疆鐨刡yte鍊,椤荤‘淇0 <= index < length + * + * @param index 浣嶇疆 + * + * @return byte鍊 + */ + public byte get(int index) { + return content[index]; + } + + /** + * 鑾峰彇鎸囧畾浣嶇疆鐨刢har鍊,椤荤‘淇0 <= offset+2 < length + * + * @param offset 浣嶇疆 + * + * @return short鍊 + */ + public char getChar(int offset) { + return (char) ((0xff00 & (content[offset] << 8)) | (0xff & content[offset + 1])); + } + + /** + * 鑾峰彇鎸囧畾浣嶇疆鐨剆hort鍊,椤荤‘淇0 <= offset+2 < length + * + * @param offset 浣嶇疆 + * + * @return short鍊 + */ + public int getShort(int offset) { + return (short) ((0xff00 & (content[offset] << 8)) | (0xff & content[offset + 1])); + } + + /** + * 鑾峰彇鎸囧畾浣嶇疆鐨刬nt鍊,椤荤‘淇0 <= offset+4 < length + * + * @param offset 浣嶇疆 + * + * @return int鍊 + */ + public int getInt(int offset) { + return ((content[offset] & 0xff) << 24) | ((content[offset + 1] & 0xff) << 16) | ((content[offset + 2] & 0xff) << 8) | (content[offset + 3] & 0xff); + } + + /** + * 鑾峰彇鎸囧畾浣嶇疆鐨刦loat鍊,椤荤‘淇0 <= offset+4 < length + * + * @param offset 浣嶇疆 + * + * @return float鍊 + */ + public float getFloat(int offset) { + return Float.intBitsToFloat(getInt(offset)); + } + + /** + * 鑾峰彇鎸囧畾浣嶇疆鐨刲ong鍊,椤荤‘淇0 <= offset+8 < length + * + * @param offset 浣嶇疆 + * + * @return long鍊 + */ + public long getLong(int offset) { + return (((long) content[offset] & 0xff) << 56) | (((long) content[offset + 1] & 0xff) << 48) | (((long) content[offset + 2] & 0xff) << 40) | (((long) content[offset + 3] & 0xff) << 32) + | (((long) content[offset + 4] & 0xff) << 24) | (((long) content[offset + 5] & 0xff) << 16) | (((long) content[offset + 6] & 0xff) << 8) | ((long) content[offset + 7] & 0xff); + } + + /** + * 鑾峰彇鎸囧畾浣嶇疆鐨刣ouble鍊,椤荤‘淇0 <= offset+8 < length + * + * @param offset 浣嶇疆 + * + * @return double鍊 + */ + public double getDouble(int offset) { + return Double.longBitsToDouble(getLong(offset)); + } + + /** + * 鑾峰彇鏈鍚庝竴涓瓧鑺傚,璋冪敤鍓嶉』淇濊瘉count澶т簬0 + * + * @return byte鍊 + */ + public byte getLastByte() { + return content[count - 1]; + } + + /** + * count鍑忎竴,璋冪敤鍓嶉』淇濊瘉count澶т簬0 + * + */ + public void backCount() { + count--; + } + + /** + * 灏哹uf鍐呭瑕嗙洊鍒版湰瀵硅薄鍐呭涓 + * + * @param buf 鐩爣瀹瑰櫒 + */ + public void copyTo(byte[] buf) { + System.arraycopy(this.content, 0, buf, 0, count); + } + + /** + * 灏咮yteBuffer鐨勫唴瀹硅鍙栧埌鏈璞′腑 + * + * @param buffer ByteBuffer + */ + public void put(ByteBuffer buffer) { + if (buffer == null) return; + int remain = buffer.remaining(); + if (remain == 0) return; + int l = this.content.length - count; + if (remain > l) { + byte[] ns = new byte[this.content.length + remain]; + if (count > 0) System.arraycopy(content, 0, ns, 0, count); + this.content = ns; + } + buffer.get(content, count, remain); + count += remain; + } + + /** + * 灏哸rray鐨勫唴瀹瑰紩鐢ㄧ粰鏈璞 + * + * @param array ByteArray + */ + public void directFrom(ByteArray array) { + if (array != null) { + this.content = array.content; + this.count = array.count; + } + } + + /** + * 灏哻ontent鐨勫唴瀹圭洿鎺ョ粰鏈璞 + * + * @param content 鍐呭 + * @param count 闀垮害 + */ + public void directFrom(byte[] content, int count) { + this.content = content; + this.count = count; + } + + /** + * 灏嗘湰瀵硅薄鐨勫唴瀹瑰紩鐢ㄥ鍒剁粰array + * + * @param array ByteArray + */ + public void directTo(ByteArray array) { + if (array != null) { + array.content = this.content; + array.count = this.count; + } + } + + /** + * 鐩存帴鑾峰彇鍏ㄩ儴鏁版嵁, 瀹為檯鏁版嵁闇瑕佹牴鎹甽ength闀垮害鏉ユ埅鍙 + * + * @return byte[] + */ + @Override + public byte[] content() { + return content; + } + + /** + * 鑾峰彇byte[] + * + * @return byte[] + */ + public byte[] getBytes() { + return Arrays.copyOf(content, count); + } + + /** + * 鑾峰彇byte[] + * + * @param offset 鍋忕Щ浣 + * @param length 闀垮害 + * + * @return byte[] + */ + public byte[] getBytes(int offset, int length) { + if (length < 1) return new byte[0]; + byte[] bs = new byte[length]; + System.arraycopy(this.content, offset, bs, 0, length); + return bs; + } + + /** + * 鏌ユ壘鎸囧畾鍊肩涓娆″嚭鐜扮殑浣嶇疆,娌℃湁杩斿洖-1 + * + * @param value 鏌ヨ鍊 + * + * @return 鎵鍦ㄤ綅缃 + */ + public int find(byte value) { + return find(0, value); + } + + /** + * 浠庢寚瀹氱殑璧峰浣嶇疆鏌ヨvalue鍊煎嚭鐜扮殑浣嶇疆,娌℃湁杩斿洖-1 + * + * @param offset 璧峰浣嶇疆 + * @param value 鏌ヨ鍊 + * + * @return 鎵鍦ㄤ綅缃 + */ + public int find(int offset, char value) { + return find(offset, (byte) value); + } + + /** + * 浠庢寚瀹氱殑璧峰浣嶇疆鏌ヨvalue鍊煎嚭鐜扮殑浣嶇疆,娌℃湁杩斿洖-1 + * + * @param offset 璧峰浣嶇疆 + * @param value 鏌ヨ鍊 + * + * @return 鎵鍦ㄤ綅缃 + */ + public int find(int offset, byte value) { + return find(offset, -1, value); + } + + /** + * 浠庢寚瀹氱殑璧峰浣嶇疆鍜岄暱搴︽煡璇alue鍊煎嚭鐜扮殑浣嶇疆,娌℃湁杩斿洖-1 + * + * @param offset 璧峰浣嶇疆 + * @param limit 闀垮害闄愬埗 + * @param value 鏌ヨ鍊 + * + * @return 鎵鍦ㄤ綅缃 + */ + public int find(int offset, int limit, char value) { + return find(offset, limit, (byte) value); + } + + /** + * 浠庢寚瀹氱殑璧峰浣嶇疆鍜岄暱搴︽煡璇alue鍊煎嚭鐜扮殑浣嶇疆,娌℃湁杩斿洖-1 + * + * @param offset 璧峰浣嶇疆 + * @param limit 闀垮害闄愬埗 + * @param value 鏌ヨ鍊 + * + * @return 鎵鍦ㄤ綅缃 + */ + public int find(int offset, int limit, byte value) { + byte[] bytes = this.content; + int end = limit > 0 ? limit : count; + for (int i = offset; i < end; i++) { + if (bytes[i] == value) return i; + } + return -1; + } + + /** + * 绉婚櫎鏈鍚庝竴涓瓧鑺 + * + * @return ByteArray + */ + public ByteArray removeLastByte() { + if (count > 0) count--; + return this; + } + + /** + * 鍐欏叆涓涓猚har鍊 + * + * @param value int鍊 + * + * @return ByteArray + */ + public ByteArray putChar(char value) { + return this.put((byte) (value >> 8 & 0xFF), + (byte) (value & 0xFF)); + } + + /** + * 鍐欏叆涓涓猚har鍊硷紝 content.length 蹇呴』涓嶈兘灏忎簬offset+2 + * + * @param offset 鍋忕Щ閲 + * @param value char鍊 + * + * @return ByteArray + */ + public ByteArray putChar(int offset, char value) { + return this.put(offset, (byte) (value >> 8 & 0xFF), + (byte) (value & 0xFF)); + } + + /** + * 鍐欏叆涓涓猻hort鍊 + * + * @param value short鍊 + * + * @return ByteArray + */ + public ByteArray putShort(short value) { + return this.put((byte) (value >> 8 & 0xFF), + (byte) (value & 0xFF)); + } + + /** + * 鍐欏叆涓涓猻hort鍊 + * + * @param value short鍊 + * + * @return ByteArray + */ + public ByteArray putShort(char value) { + int v = value; + return this.put((byte) (v >> 8 & 0xFF), + (byte) (v & 0xFF)); + } + + /** + * 鍐欏叆涓涓猻hort鍊 + * + * @param value short鍊 + * + * @return ByteArray + */ + public ByteArray putShort(int value) { + return this.put((byte) (value >> 8 & 0xFF), + (byte) (value & 0xFF)); + } + + /** + * 鍐欏叆涓涓猻hort鍊 + * + * @param value short鍊 + * + * @return ByteArray + */ + public ByteArray putUnsignedShort(int value) { + return this.put((byte) (value >> 8 & 0xFF), + (byte) (value & 0xFF)); + } + + /** + * 鍐欏叆涓涓棤绗﹀彿short鍊硷紝 content.length 蹇呴』涓嶈兘灏忎簬offset+2 + * + * @param offset 鍋忕Щ閲 + * @param value short鍊 + * + * @return ByteArray + */ + public ByteArray putUnsignedShort(int offset, int value) { + return this.put(offset, (byte) (value >> 8 & 0xFF), + (byte) (value & 0xFF)); + } + + /** + * 鍐欏叆涓涓猻hort鍊硷紝 content.length 蹇呴』涓嶈兘灏忎簬offset+2 + * + * @param offset 鍋忕Щ閲 + * @param value short鍊 + * + * @return ByteArray + */ + public ByteArray putShort(int offset, short value) { + return this.put(offset, (byte) (value >> 8 & 0xFF), + (byte) (value & 0xFF)); + } + + /** + * 鍐欏叆涓涓3瀛楄妭鐨刬nt鍊 + * + * @param value int鍊 + * + * @return ByteArray + */ + public ByteArray putMedium(int value) { + return this.put((byte) (value >> 16 & 0xFF), + (byte) (value >> 8 & 0xFF), + (byte) (value & 0xFF)); + } + + /** + * 鎸囧畾浣嶇疆鍐欏叆涓涓3瀛楄妭鐨刬nt鍊硷紝 content.length 蹇呴』涓嶈兘灏忎簬offset+3 + * + * @param offset 鍋忕Щ閲 + * @param value int鍊 + * + * @return ByteArray + */ + public ByteArray putMedium(int offset, int value) { + content[offset] = (byte) (value >> 16 & 0xFF); + content[offset + 1] = (byte) (value >> 8 & 0xFF); + content[offset + 2] = (byte) (value & 0xFF); + return this; + } + + /** + * 鍐欏叆涓涓3瀛楄妭鐨刬nt鍊 + * + * @param value int鍊 + * + * @return ByteArray + */ + public ByteArray putUnsignedMedium(int value) { + return this.put((byte) (value >> 16 & 0xFF), + (byte) (value >> 8 & 0xFF), + (byte) (value & 0xFF)); + } + + /** + * 鎸囧畾浣嶇疆鍐欏叆涓涓3瀛楄妭鐨刬nt鍊硷紝 content.length 蹇呴』涓嶈兘灏忎簬offset+3 + * + * @param offset 鍋忕Щ閲 + * @param value int鍊 + * + * @return ByteArray + */ + public ByteArray putUnsignedMedium(int offset, int value) { + content[offset] = (byte) (value >> 16 & 0xFF); + content[offset + 1] = (byte) (value >> 8 & 0xFF); + content[offset + 2] = (byte) (value & 0xFF); + return this; + } + + /** + * 鍐欏叆涓涓猧nt鍊 + * + * @param value int鍊 + * + * @return ByteArray + */ + public ByteArray putInt(int value) { + return this.put((byte) (value >> 24 & 0xFF), + (byte) (value >> 16 & 0xFF), + (byte) (value >> 8 & 0xFF), + (byte) (value & 0xFF)); + } + + /** + * 鍐欏叆涓涓猧nt鍊 + * + * @param value int鍊 + * + * @return ByteArray + */ + public ByteArray putUnsignedInt(long value) { + return this.put((byte) (value >> 24 & 0xFF), + (byte) (value >> 16 & 0xFF), + (byte) (value >> 8 & 0xFF), + (byte) (value & 0xFF)); + } + + /** + * 鎸囧畾浣嶇疆鍐欏叆涓涓猧nt鍊硷紝 content.length 蹇呴』涓嶈兘灏忎簬offset+4 + * + * @param offset 鍋忕Щ閲 + * @param value int鍊 + * + * @return ByteArray + */ + public ByteArray putInt(int offset, int value) { + content[offset] = (byte) (value >> 24 & 0xFF); + content[offset + 1] = (byte) (value >> 16 & 0xFF); + content[offset + 2] = (byte) (value >> 8 & 0xFF); + content[offset + 3] = (byte) (value & 0xFF); + return this; + } + + /** + * 鎸囧畾浣嶇疆鍐欏叆涓涓 鏃犵鍙穒nt鍊硷紝 content.length 蹇呴』涓嶈兘灏忎簬offset+4 + * + * @param offset 鍋忕Щ閲 + * @param value int鍊 + * + * @return ByteArray + */ + public ByteArray putUnsignedInt(int offset, long value) { + content[offset] = (byte) (value >> 24 & 0xFF); + content[offset + 1] = (byte) (value >> 16 & 0xFF); + content[offset + 2] = (byte) (value >> 8 & 0xFF); + content[offset + 3] = (byte) (value & 0xFF); + return this; + } + + /** + * 鍐欏叆涓涓猣loat鍊 + * + * @param value float鍊 + * + * @return ByteArray + */ + public ByteArray putFloat(float value) { + return this.putInt(Float.floatToIntBits(value)); + } + + /** + * 鎸囧畾浣嶇疆鍐欏叆涓涓猣loat鍊硷紝 content.length 蹇呴』涓嶈兘灏忎簬offset+4 + * + * @param offset 鍋忕Щ閲 + * @param value float鍊 + * + * @return ByteArray + */ + public ByteArray putFloat(int offset, float value) { + return this.putInt(offset, Float.floatToIntBits(value)); + } + + /** + * 鍐欏叆涓涓猯ong鍊 + * + * @param value long鍊 + * + * @return ByteArray + */ + public ByteArray putLong(long value) { + return this.put((byte) (value >> 56 & 0xFF), + (byte) (value >> 48 & 0xFF), + (byte) (value >> 40 & 0xFF), + (byte) (value >> 32 & 0xFF), + (byte) (value >> 24 & 0xFF), + (byte) (value >> 16 & 0xFF), + (byte) (value >> 8 & 0xFF), + (byte) (value & 0xFF)); + } + + /** + * 鎸囧畾浣嶇疆鍐欏叆涓涓猯ong鍊硷紝 content.length 蹇呴』涓嶈兘灏忎簬offset+8 + * + * @param offset 鍋忕Щ閲 + * @param value long鍊 + * + * @return ByteArray + */ + public ByteArray putLong(int offset, long value) { + return this.put(offset, (byte) (value >> 56 & 0xFF), + (byte) (value >> 48 & 0xFF), + (byte) (value >> 40 & 0xFF), + (byte) (value >> 32 & 0xFF), + (byte) (value >> 24 & 0xFF), + (byte) (value >> 16 & 0xFF), + (byte) (value >> 8 & 0xFF), + (byte) (value & 0xFF)); + } + + /** + * 鍐欏叆涓涓猟ouble鍊 + * + * @param value double鍊 + * + * @return ByteArray + */ + public ByteArray putDouble(double value) { + return this.putLong(Double.doubleToLongBits(value)); + } + + /** + * 鎸囧畾浣嶇疆鍐欏叆涓涓猟ouble鍊硷紝 content.length 蹇呴』涓嶈兘灏忎簬offset+8 + * + * @param offset 鍋忕Щ閲 + * @param value double鍊 + * + * @return ByteArray + */ + public ByteArray putDouble(int offset, double value) { + return this.putLong(offset, Double.doubleToLongBits(value)); + } + + public ByteArray putByte(short value) { + return put((byte) value); + } + + public ByteArray putByte(char value) { + return put((byte) value); + } + + public ByteArray putByte(int value) { + return put((byte) value); + } + + /** + * 鍐欏叆涓涓猙yte鍊 + * + * @param value byte鍊 + * + * @return ByteArray + */ + public ByteArray put(byte value) { + if (count >= content.length - 1) { + byte[] ns = new byte[content.length + 8]; + System.arraycopy(content, 0, ns, 0, count); + this.content = ns; + } + content[count++] = value; + return this; + } + + /** + * 鍐欏叆涓涓猙yte鍊硷紝 content.length 蹇呴』涓嶈兘灏忎簬offset+1 + * + * @param offset 鍋忕Щ閲 + * @param value byte鍊 + * + * @return ByteArray + */ + public ByteArray putByte(int offset, byte value) { + content[offset] = value; + return this; + } + + /** + * 鍐欏叆涓涓猙yte鍊硷紝 content.length 蹇呴』涓嶈兘灏忎簬offset+1 + * + * @param offset 鍋忕Щ閲 + * @param value byte鍊 + * + * @return ByteArray + */ + public ByteArray putByte(int offset, int value) { + content[offset] = (byte) value; + return this; + } + + /** + * 鍐欏叆涓缁刡yte鍊 + * + * @param values 涓缁刡yte鍊 + * + * @return ByteArray + */ + public ByteArray put(byte... values) { + if (values.length < 1) return this; + if (count >= content.length - values.length) { + byte[] ns = new byte[content.length + values.length]; + System.arraycopy(content, 0, ns, 0, count); + this.content = ns; + } + System.arraycopy(values, 0, content, count, values.length); + count += values.length; + return this; + } + + /** + * 鎸囧畾浣嶇疆鍐欏叆涓缁刡yte鍊硷紝 content.length 蹇呴』涓嶈兘灏忎簬offset+values.length + * + * @param offset 鍋忕Щ閲 + * @param values 涓缁刡yte鍊 + * + * @return ByteArray + */ + public ByteArray put(int offset, byte... values) { + if (values.length < 1) throw new IllegalArgumentException(); + System.arraycopy(values, 0, content, offset, values.length); + return this; + } + + /** + * 鍐欏叆涓缁刡yte鍊 + * + * @param values 涓缁刡yte鍊 + * @param offset 鍋忕Щ閲 + * @param length 闀垮害 + * + * @return ByteArray + */ + public ByteArray put(byte[] values, int offset, int length) { + if (count >= content.length - length) { + byte[] ns = new byte[content.length + Math.max(16, length)]; + System.arraycopy(content, 0, ns, 0, count); + this.content = ns; + } + System.arraycopy(values, offset, content, count, length); + count += length; + return this; + } + + /** + * 鍐欏叆涓缁刡yte鍊硷紝 content.length 蹇呴』涓嶈兘灏忎簬poffset+length + * + * @param poffset 鍋忕Щ閲 + * @param values 涓缁刡yte鍊 + * @param offset 鍋忕Щ閲 + * @param length 闀垮害 + * + * @return ByteArray + */ + public ByteArray put(int poffset, byte[] values, int offset, int length) { + System.arraycopy(values, offset, content, poffset, length); + return this; + } + + /** + * 鍐欏叆ByteArray涓殑涓閮ㄥ垎 + * + * @param array ByteArray + * @param offset 鍋忕Щ閲 + * @param length 闀垮害 + * + * @return ByteArray + */ + public ByteArray put(ByteArray array, int offset, int length) { + if (count >= content.length - length) { + byte[] ns = new byte[content.length + Math.max(16, length)]; + System.arraycopy(content, 0, ns, 0, count); + this.content = ns; + } + System.arraycopy(array.content, offset, content, count, length); + count += length; + return this; + } + + /** + * 鍐欏叆ByteBuffer鎸囧畾闀垮害鐨勬暟鎹 + * + * @param buffer 鏁版嵁 + * @param len 鎸囧畾闀垮害 + * + * @return ByteArray + */ + public ByteArray put(ByteBuffer buffer, int len) { + if (len < 1) return this; + if (count >= content.length - len) { + byte[] ns = new byte[content.length + len]; + System.arraycopy(content, 0, ns, 0, count); + this.content = ns; + } + buffer.get(content, count, len); + count += len; + return this; + } + + @Override + public String toString() { + return new String(content, 0, count); + } + + /** + * 鎸夋寚瀹氬瓧绗﹂泦杞垚瀛楃涓 + * + * @param charset 瀛楃闆 + * + * @return 瀛楃涓 + */ + public String toString(final Charset charset) { + return toString(0, count, charset); + } + + /** + * 灏嗘寚瀹氱殑璧峰浣嶇疆鍜岄暱搴︽寜鎸囧畾瀛楃闆嗚浆鎴愬瓧绗︿覆 + * + * @param offset 璧峰浣嶇疆 + * @param len 闀垮害 + * @param charset 瀛楃闆 + * + * @return 瀛楃涓 + */ + public String toString(final int offset, int len, final Charset charset) { + if (charset == null) return new String(content, offset, len, StandardCharsets.UTF_8); + return new String(content, offset, len, charset); + } + + /** + * 灏嗘寚瀹氱殑璧峰浣嶇疆鎸夋寚瀹氬瓧绗﹂泦杞垚瀛楃涓 + * + * @param offset 璧峰浣嶇疆 + * @param charset 瀛楃闆 + * + * @return 瀛楃涓 + */ + public String toString(final int offset, final Charset charset) { + if (charset == null) return new String(content, offset, count - offset, StandardCharsets.UTF_8); + return new String(content, offset, count - offset, charset); + } + + /** + * 灏嗘寚瀹氱殑璧峰浣嶇疆鍜岄暱搴︽寜鎸囧畾瀛楃闆嗚浆鎴愬瓧绗︿覆,骞秚rim + * + * @param offset 璧峰浣嶇疆 + * @param len 闀垮害 + * @param charset 瀛楃闆 + * + * @return 瀛楃涓 + */ +// public String toTrimString(int offset, int len, final Charset charset) { +// if (len == 0) return ""; +// int st = 0; +// while (st < len && (content[offset] & 0xff) <= ' ') { +// offset++; +// st++; +// } +// while (len > 0 && (content[len - 1] & 0xff) <= ' ') len--; +// if (len == 0) return ""; +// if (charset == null) return new String(content, offset, len - st, StandardCharsets.UTF_8); +// return new String(content, offset, len - st, charset); +// } + /** + * 灏嗘寚瀹氱殑璧峰浣嶇疆鍜岄暱搴︽寜鎸囧畾瀛楃闆嗗苟杞箟鍚庤浆鎴愬瓧绗︿覆 + * + * @param charset 瀛楃闆 + * + * @return 瀛楃涓 + */ +// public String toDecodeString(final Charset charset) { +// return toDecodeString(0, count, charset); +// } + /** + * 灏嗘寚瀹氱殑璧峰浣嶇疆鍜岄暱搴︽寜鎸囧畾瀛楃闆嗗苟杞箟鍚庤浆鎴愬瓧绗︿覆 + * + * @param offset 璧峰浣嶇疆 + * @param len 闀垮害 + * @param charset 瀛楃闆 + * + * @return 瀛楃涓 + */ +// public String toDecodeString(final int offset, int len, final Charset charset) { +// int start = offset; +// final int end = offset + len; +// boolean flag = false; //鏄惁闇瑕佽浆涔 +// byte[] bs = content; +// for (int i = offset; i < end; i++) { +// if (content[i] == '+' || content[i] == '%') { +// flag = true; +// break; +// } +// } +// if (flag) { +// int index = 0; +// bs = new byte[len]; +// for (int i = offset; i < end; i++) { +// switch (content[i]) { +// case '+': +// bs[index] = ' '; +// break; +// case '%': +// bs[index] = (byte) ((hexBit(content[++i]) * 16 + hexBit(content[++i]))); +// break; +// default: +// bs[index] = content[i]; +// break; +// } +// index++; +// } +// start = 0; +// len = index; +// } +// if (charset == null) return new String(bs, start, len, StandardCharsets.UTF_8); +// return new String(bs, start, len, charset); +// } +// +// private static int hexBit(byte b) { +// if ('0' <= b && '9' >= b) return b - '0'; +// if ('a' <= b && 'z' >= b) return b - 'a' + 10; +// if ('A' <= b && 'Z' >= b) return b - 'A' + 10; +// return b; +// } +} diff --git a/src/main/java/org/redkale/util/ByteBufferReader.java b/src/main/java/org/redkale/util/ByteBufferReader.java index 09729f098..8eeeb1c5c 100644 --- a/src/main/java/org/redkale/util/ByteBufferReader.java +++ b/src/main/java/org/redkale/util/ByteBufferReader.java @@ -1,396 +1,396 @@ -/* - * 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.util; - -import java.nio.*; -import java.util.*; - -/** - * 浠yteBuffer涓烘暟鎹浇浣撶殑Reader
- * 娉ㄦ剰锛氭渶灏忓彲璇荤┖闂磋嚦灏戞槸8 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public class ByteBufferReader { - - private ByteBuffer[] buffers; - - private int currIndex; - - private ByteBuffer currBuffer; - - private final boolean bigEndian; - - public ByteBufferReader(Collection buffers) { - Objects.requireNonNull(buffers); - this.buffers = buffers.toArray(new ByteBuffer[buffers.size()]); - this.currBuffer = this.buffers[0]; - this.currIndex = 0; - this.bigEndian = this.currBuffer.order() == ByteOrder.BIG_ENDIAN; - } - - public ByteBufferReader(ByteBuffer[] buffers) { - Objects.requireNonNull(buffers); - this.buffers = buffers; - this.currBuffer = this.buffers[0]; - this.currIndex = 0; - this.bigEndian = this.currBuffer.order() == ByteOrder.BIG_ENDIAN; - } - - public ByteBufferReader(ByteBuffer buffer) { - Objects.requireNonNull(buffer); - this.buffers = new ByteBuffer[]{buffer}; - this.currBuffer = this.buffers[0]; - this.currIndex = 0; - this.bigEndian = this.currBuffer.order() == ByteOrder.BIG_ENDIAN; - } - - public ByteBufferReader append(ByteBuffer... buffs) { - for (ByteBuffer buf : buffs) { - Objects.requireNonNull(buf); - } - this.buffers = Utility.append(this.buffers, buffs); - return this; - } - - public static ByteBufferReader create(ByteBuffer buffer) { - return new ByteBufferReader(buffer); - } - - public static ByteBufferReader create(Collection buffers) { - return new ByteBufferReader(buffers); - } - - public static ByteBufferReader create(ByteBuffer[] buffers) { - return new ByteBufferReader(buffers); - } - - public static byte[] toBytes(ByteBuffer[] buffers) { - if (buffers == null) return null; - int size = 0; - for (ByteBuffer buffer : buffers) { - size += buffer.remaining(); - } - byte[] bs = new byte[size]; - int index = 0; - for (ByteBuffer buffer : buffers) { - int remain = buffer.remaining(); - buffer.get(bs, index, remain); - index += remain; - } - return bs; - } - - public static boolean hasRemaining(ByteBuffer... buffers) { - for (ByteBuffer buf : buffers) { - if (buf.hasRemaining()) return true; - } - return false; - } - - public static int remaining(ByteBuffer... buffers) { - int remains = 0; - for (ByteBuffer buf : buffers) { - remains += buf.remaining(); - } - return remains; - } - - public static int remaining(ByteBuffer[] buffers, int offset, int length) { - int remains = 0; - int end = offset + length; - for (int i = offset; i < end; i++) { - remains += buffers[i].remaining(); - } - return remains; - } - - public boolean hasRemaining() { - boolean v = this.currBuffer.hasRemaining(); - if (v) return v; - if (this.currIndex == this.buffers.length - 1) return false; - for (int i = this.currIndex + 1; i < this.buffers.length; i++) { - if (this.buffers[i].hasRemaining()) return true; - } - return false; - } - - public int remaining() { - int v = this.currBuffer.remaining(); - for (int i = this.currIndex + 1; i < this.buffers.length; i++) { - v += this.buffers[i].remaining(); - } - return v; - } - - //鎻愬墠棰勮涓涓瓧鑺 - public byte preget() { - ByteBuffer buf = this.currBuffer; - if (!buf.hasRemaining()) { - buf = this.buffers[this.currIndex + 1]; - } - return buf.get(buf.position()); - } - - public byte get() { - ByteBuffer buf = this.currBuffer; - if (!buf.hasRemaining()) { - buf = this.buffers[++this.currIndex]; - this.currBuffer = buf; - } - return this.currBuffer.get(); - } - - public short getShort() { - ByteBuffer buf = this.currBuffer; - int remain = buf.remaining(); - if (remain >= 2) return buf.getShort(); - if (remain == 0) { - buf = this.buffers[++this.currIndex]; - this.currBuffer = buf; - return buf.getShort(); - } - if (bigEndian) return (short) ((buf.get() << 8) | (get() & 0xff)); - return (short) ((buf.get() & 0xff) | (get() << 8)); - } - - public int getInt() { - ByteBuffer buf = this.currBuffer; - int remain = buf.remaining(); - if (remain >= 4) return buf.getInt(); - if (remain == 0) { - buf = this.buffers[++this.currIndex]; - this.currBuffer = buf; - return buf.getInt(); - } - if (bigEndian) { - if (remain == 1) { - return ((buf.get() << 24) - | ((get() & 0xff) << 16) - | ((get() & 0xff) << 8) - | ((get() & 0xff))); - } - if (remain == 2) { - return ((buf.get() << 24) - | ((buf.get() & 0xff) << 16) - | ((get() & 0xff) << 8) - | ((get() & 0xff))); - } - //remain == 3 - return ((buf.get() << 24) - | ((buf.get() & 0xff) << 16) - | ((buf.get() & 0xff) << 8) - | ((get() & 0xff))); - } - if (remain == 1) { - return ((buf.get() & 0xff) - | ((get() & 0xff) << 8) - | ((get() & 0xff) << 16) - | ((get() << 24))); - } - if (remain == 2) { - return ((buf.get() & 0xff) - | ((buf.get() & 0xff) << 8) - | ((get() & 0xff) << 16) - | ((get() << 24))); - } - //remain == 3 - return ((buf.get()) & 0xff) - | ((buf.get() & 0xff) << 8) - | ((buf.get() & 0xff) << 16) - | ((get() << 24)); - } - - public float getFloat() { - return Float.intBitsToFloat(getInt()); - } - - public long getLong() { - ByteBuffer buf = this.currBuffer; - int remain = buf.remaining(); - if (remain >= 8) return buf.getLong(); - if (remain == 0) { - buf = this.buffers[++this.currIndex]; - this.currBuffer = buf; - return buf.getLong(); - } - if (bigEndian) { - if (remain == 1) { - return ((((long) buf.get()) << 56) - | (((long) get() & 0xff) << 48) - | (((long) get() & 0xff) << 40) - | (((long) get() & 0xff) << 32) - | (((long) get() & 0xff) << 24) - | (((long) get() & 0xff) << 16) - | (((long) get() & 0xff) << 8) - | (((long) get() & 0xff))); - } - if (remain == 2) { - return ((((long) buf.get()) << 56) - | (((long) buf.get() & 0xff) << 48) - | (((long) get() & 0xff) << 40) - | (((long) get() & 0xff) << 32) - | (((long) get() & 0xff) << 24) - | (((long) get() & 0xff) << 16) - | (((long) get() & 0xff) << 8) - | (((long) get() & 0xff))); - } - if (remain == 3) { - return ((((long) buf.get()) << 56) - | (((long) buf.get() & 0xff) << 48) - | (((long) buf.get() & 0xff) << 40) - | (((long) get() & 0xff) << 32) - | (((long) get() & 0xff) << 24) - | (((long) get() & 0xff) << 16) - | (((long) get() & 0xff) << 8) - | (((long) get() & 0xff))); - } - if (remain == 4) { - return ((((long) buf.get()) << 56) - | (((long) buf.get() & 0xff) << 48) - | (((long) buf.get() & 0xff) << 40) - | (((long) buf.get() & 0xff) << 32) - | (((long) get() & 0xff) << 24) - | (((long) get() & 0xff) << 16) - | (((long) get() & 0xff) << 8) - | (((long) get() & 0xff))); - } - if (remain == 5) { - return ((((long) buf.get()) << 56) - | (((long) buf.get() & 0xff) << 48) - | (((long) buf.get() & 0xff) << 40) - | (((long) buf.get() & 0xff) << 32) - | (((long) buf.get() & 0xff) << 24) - | (((long) get() & 0xff) << 16) - | (((long) get() & 0xff) << 8) - | (((long) get() & 0xff))); - } - if (remain == 6) { - return ((((long) buf.get()) << 56) - | (((long) buf.get() & 0xff) << 48) - | (((long) buf.get() & 0xff) << 40) - | (((long) buf.get() & 0xff) << 32) - | (((long) buf.get() & 0xff) << 24) - | (((long) buf.get() & 0xff) << 16) - | (((long) get() & 0xff) << 8) - | (((long) get() & 0xff))); - } - //remain == 7 - return ((((long) buf.get()) << 56) - | (((long) buf.get() & 0xff) << 48) - | (((long) buf.get() & 0xff) << 40) - | (((long) buf.get() & 0xff) << 32) - | (((long) buf.get() & 0xff) << 24) - | (((long) buf.get() & 0xff) << 16) - | (((long) buf.get() & 0xff) << 8) - | (((long) get() & 0xff))); - } - if (remain == 1) { - return ((((long) buf.get() & 0xff)) - | (((long) get() & 0xff) << 8) - | (((long) get() & 0xff) << 16) - | (((long) get() & 0xff) << 24) - | (((long) get() & 0xff) << 32) - | (((long) get() & 0xff) << 40) - | (((long) get() & 0xff) << 48) - | (((long) get()) << 56)); - } - if (remain == 2) { - return ((((long) buf.get() & 0xff)) - | (((long) buf.get() & 0xff) << 8) - | (((long) get() & 0xff) << 16) - | (((long) get() & 0xff) << 24) - | (((long) get() & 0xff) << 32) - | (((long) get() & 0xff) << 40) - | (((long) get() & 0xff) << 48) - | (((long) get()) << 56)); - } - if (remain == 3) { - return ((((long) buf.get() & 0xff)) - | (((long) buf.get() & 0xff) << 8) - | (((long) buf.get() & 0xff) << 16) - | (((long) get() & 0xff) << 24) - | (((long) get() & 0xff) << 32) - | (((long) get() & 0xff) << 40) - | (((long) get() & 0xff) << 48) - | (((long) get()) << 56)); - } - if (remain == 4) { - return ((((long) buf.get() & 0xff)) - | (((long) buf.get() & 0xff) << 8) - | (((long) buf.get() & 0xff) << 16) - | (((long) buf.get() & 0xff) << 24) - | (((long) get() & 0xff) << 32) - | (((long) get() & 0xff) << 40) - | (((long) get() & 0xff) << 48) - | (((long) get()) << 56)); - } - if (remain == 5) { - return ((((long) buf.get() & 0xff)) - | (((long) buf.get() & 0xff) << 8) - | (((long) buf.get() & 0xff) << 16) - | (((long) buf.get() & 0xff) << 24) - | (((long) buf.get() & 0xff) << 32) - | (((long) get() & 0xff) << 40) - | (((long) get() & 0xff) << 48) - | (((long) get()) << 56)); - } - if (remain == 6) { - return ((((long) buf.get() & 0xff)) - | (((long) buf.get() & 0xff) << 8) - | (((long) buf.get() & 0xff) << 16) - | (((long) buf.get() & 0xff) << 24) - | (((long) buf.get() & 0xff) << 32) - | (((long) buf.get() & 0xff) << 40) - | (((long) get() & 0xff) << 48) - | (((long) get()) << 56)); - } - //remain == 7 - return ((((long) buf.get() & 0xff)) - | (((long) buf.get() & 0xff) << 8) - | (((long) buf.get() & 0xff) << 16) - | (((long) buf.get() & 0xff) << 24) - | (((long) buf.get() & 0xff) << 32) - | (((long) buf.get() & 0xff) << 40) - | (((long) buf.get() & 0xff) << 48) - | (((long) get()) << 56)); - } - - public double getDouble() { - return Double.longBitsToDouble(getLong()); - } - - public ByteBufferReader get(byte[] dst) { - return get(dst, 0, dst.length); - } - - public ByteBufferReader get(byte[] dst, int offset, int length) { - ByteBuffer buf = this.currBuffer; - int remain = buf.remaining(); - if (remain >= length) { - buf.get(dst, offset, length); - return this; - } - buf.get(dst, offset, remain); - this.currBuffer = this.buffers[++this.currIndex]; - return get(dst, offset + remain, length - remain); - } - - public ByteBufferReader skip(int size) { - ByteBuffer buf = this.currBuffer; - int remain = buf.remaining(); - if (remain >= size) { - buf.position(buf.position() + size); - return this; - } - buf.position(buf.position() + remain); - this.currBuffer = this.buffers[++this.currIndex]; - return skip(size - remain); - } -} +/* + * 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.util; + +import java.nio.*; +import java.util.*; + +/** + * 浠yteBuffer涓烘暟鎹浇浣撶殑Reader
+ * 娉ㄦ剰锛氭渶灏忓彲璇荤┖闂磋嚦灏戞槸8 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public class ByteBufferReader { + + private ByteBuffer[] buffers; + + private int currIndex; + + private ByteBuffer currBuffer; + + private final boolean bigEndian; + + public ByteBufferReader(Collection buffers) { + Objects.requireNonNull(buffers); + this.buffers = buffers.toArray(new ByteBuffer[buffers.size()]); + this.currBuffer = this.buffers[0]; + this.currIndex = 0; + this.bigEndian = this.currBuffer.order() == ByteOrder.BIG_ENDIAN; + } + + public ByteBufferReader(ByteBuffer[] buffers) { + Objects.requireNonNull(buffers); + this.buffers = buffers; + this.currBuffer = this.buffers[0]; + this.currIndex = 0; + this.bigEndian = this.currBuffer.order() == ByteOrder.BIG_ENDIAN; + } + + public ByteBufferReader(ByteBuffer buffer) { + Objects.requireNonNull(buffer); + this.buffers = new ByteBuffer[]{buffer}; + this.currBuffer = this.buffers[0]; + this.currIndex = 0; + this.bigEndian = this.currBuffer.order() == ByteOrder.BIG_ENDIAN; + } + + public ByteBufferReader append(ByteBuffer... buffs) { + for (ByteBuffer buf : buffs) { + Objects.requireNonNull(buf); + } + this.buffers = Utility.append(this.buffers, buffs); + return this; + } + + public static ByteBufferReader create(ByteBuffer buffer) { + return new ByteBufferReader(buffer); + } + + public static ByteBufferReader create(Collection buffers) { + return new ByteBufferReader(buffers); + } + + public static ByteBufferReader create(ByteBuffer[] buffers) { + return new ByteBufferReader(buffers); + } + + public static byte[] toBytes(ByteBuffer[] buffers) { + if (buffers == null) return null; + int size = 0; + for (ByteBuffer buffer : buffers) { + size += buffer.remaining(); + } + byte[] bs = new byte[size]; + int index = 0; + for (ByteBuffer buffer : buffers) { + int remain = buffer.remaining(); + buffer.get(bs, index, remain); + index += remain; + } + return bs; + } + + public static boolean hasRemaining(ByteBuffer... buffers) { + for (ByteBuffer buf : buffers) { + if (buf.hasRemaining()) return true; + } + return false; + } + + public static int remaining(ByteBuffer... buffers) { + int remains = 0; + for (ByteBuffer buf : buffers) { + remains += buf.remaining(); + } + return remains; + } + + public static int remaining(ByteBuffer[] buffers, int offset, int length) { + int remains = 0; + int end = offset + length; + for (int i = offset; i < end; i++) { + remains += buffers[i].remaining(); + } + return remains; + } + + public boolean hasRemaining() { + boolean v = this.currBuffer.hasRemaining(); + if (v) return v; + if (this.currIndex == this.buffers.length - 1) return false; + for (int i = this.currIndex + 1; i < this.buffers.length; i++) { + if (this.buffers[i].hasRemaining()) return true; + } + return false; + } + + public int remaining() { + int v = this.currBuffer.remaining(); + for (int i = this.currIndex + 1; i < this.buffers.length; i++) { + v += this.buffers[i].remaining(); + } + return v; + } + + //鎻愬墠棰勮涓涓瓧鑺 + public byte preget() { + ByteBuffer buf = this.currBuffer; + if (!buf.hasRemaining()) { + buf = this.buffers[this.currIndex + 1]; + } + return buf.get(buf.position()); + } + + public byte get() { + ByteBuffer buf = this.currBuffer; + if (!buf.hasRemaining()) { + buf = this.buffers[++this.currIndex]; + this.currBuffer = buf; + } + return this.currBuffer.get(); + } + + public short getShort() { + ByteBuffer buf = this.currBuffer; + int remain = buf.remaining(); + if (remain >= 2) return buf.getShort(); + if (remain == 0) { + buf = this.buffers[++this.currIndex]; + this.currBuffer = buf; + return buf.getShort(); + } + if (bigEndian) return (short) ((buf.get() << 8) | (get() & 0xff)); + return (short) ((buf.get() & 0xff) | (get() << 8)); + } + + public int getInt() { + ByteBuffer buf = this.currBuffer; + int remain = buf.remaining(); + if (remain >= 4) return buf.getInt(); + if (remain == 0) { + buf = this.buffers[++this.currIndex]; + this.currBuffer = buf; + return buf.getInt(); + } + if (bigEndian) { + if (remain == 1) { + return ((buf.get() << 24) + | ((get() & 0xff) << 16) + | ((get() & 0xff) << 8) + | ((get() & 0xff))); + } + if (remain == 2) { + return ((buf.get() << 24) + | ((buf.get() & 0xff) << 16) + | ((get() & 0xff) << 8) + | ((get() & 0xff))); + } + //remain == 3 + return ((buf.get() << 24) + | ((buf.get() & 0xff) << 16) + | ((buf.get() & 0xff) << 8) + | ((get() & 0xff))); + } + if (remain == 1) { + return ((buf.get() & 0xff) + | ((get() & 0xff) << 8) + | ((get() & 0xff) << 16) + | ((get() << 24))); + } + if (remain == 2) { + return ((buf.get() & 0xff) + | ((buf.get() & 0xff) << 8) + | ((get() & 0xff) << 16) + | ((get() << 24))); + } + //remain == 3 + return ((buf.get()) & 0xff) + | ((buf.get() & 0xff) << 8) + | ((buf.get() & 0xff) << 16) + | ((get() << 24)); + } + + public float getFloat() { + return Float.intBitsToFloat(getInt()); + } + + public long getLong() { + ByteBuffer buf = this.currBuffer; + int remain = buf.remaining(); + if (remain >= 8) return buf.getLong(); + if (remain == 0) { + buf = this.buffers[++this.currIndex]; + this.currBuffer = buf; + return buf.getLong(); + } + if (bigEndian) { + if (remain == 1) { + return ((((long) buf.get()) << 56) + | (((long) get() & 0xff) << 48) + | (((long) get() & 0xff) << 40) + | (((long) get() & 0xff) << 32) + | (((long) get() & 0xff) << 24) + | (((long) get() & 0xff) << 16) + | (((long) get() & 0xff) << 8) + | (((long) get() & 0xff))); + } + if (remain == 2) { + return ((((long) buf.get()) << 56) + | (((long) buf.get() & 0xff) << 48) + | (((long) get() & 0xff) << 40) + | (((long) get() & 0xff) << 32) + | (((long) get() & 0xff) << 24) + | (((long) get() & 0xff) << 16) + | (((long) get() & 0xff) << 8) + | (((long) get() & 0xff))); + } + if (remain == 3) { + return ((((long) buf.get()) << 56) + | (((long) buf.get() & 0xff) << 48) + | (((long) buf.get() & 0xff) << 40) + | (((long) get() & 0xff) << 32) + | (((long) get() & 0xff) << 24) + | (((long) get() & 0xff) << 16) + | (((long) get() & 0xff) << 8) + | (((long) get() & 0xff))); + } + if (remain == 4) { + return ((((long) buf.get()) << 56) + | (((long) buf.get() & 0xff) << 48) + | (((long) buf.get() & 0xff) << 40) + | (((long) buf.get() & 0xff) << 32) + | (((long) get() & 0xff) << 24) + | (((long) get() & 0xff) << 16) + | (((long) get() & 0xff) << 8) + | (((long) get() & 0xff))); + } + if (remain == 5) { + return ((((long) buf.get()) << 56) + | (((long) buf.get() & 0xff) << 48) + | (((long) buf.get() & 0xff) << 40) + | (((long) buf.get() & 0xff) << 32) + | (((long) buf.get() & 0xff) << 24) + | (((long) get() & 0xff) << 16) + | (((long) get() & 0xff) << 8) + | (((long) get() & 0xff))); + } + if (remain == 6) { + return ((((long) buf.get()) << 56) + | (((long) buf.get() & 0xff) << 48) + | (((long) buf.get() & 0xff) << 40) + | (((long) buf.get() & 0xff) << 32) + | (((long) buf.get() & 0xff) << 24) + | (((long) buf.get() & 0xff) << 16) + | (((long) get() & 0xff) << 8) + | (((long) get() & 0xff))); + } + //remain == 7 + return ((((long) buf.get()) << 56) + | (((long) buf.get() & 0xff) << 48) + | (((long) buf.get() & 0xff) << 40) + | (((long) buf.get() & 0xff) << 32) + | (((long) buf.get() & 0xff) << 24) + | (((long) buf.get() & 0xff) << 16) + | (((long) buf.get() & 0xff) << 8) + | (((long) get() & 0xff))); + } + if (remain == 1) { + return ((((long) buf.get() & 0xff)) + | (((long) get() & 0xff) << 8) + | (((long) get() & 0xff) << 16) + | (((long) get() & 0xff) << 24) + | (((long) get() & 0xff) << 32) + | (((long) get() & 0xff) << 40) + | (((long) get() & 0xff) << 48) + | (((long) get()) << 56)); + } + if (remain == 2) { + return ((((long) buf.get() & 0xff)) + | (((long) buf.get() & 0xff) << 8) + | (((long) get() & 0xff) << 16) + | (((long) get() & 0xff) << 24) + | (((long) get() & 0xff) << 32) + | (((long) get() & 0xff) << 40) + | (((long) get() & 0xff) << 48) + | (((long) get()) << 56)); + } + if (remain == 3) { + return ((((long) buf.get() & 0xff)) + | (((long) buf.get() & 0xff) << 8) + | (((long) buf.get() & 0xff) << 16) + | (((long) get() & 0xff) << 24) + | (((long) get() & 0xff) << 32) + | (((long) get() & 0xff) << 40) + | (((long) get() & 0xff) << 48) + | (((long) get()) << 56)); + } + if (remain == 4) { + return ((((long) buf.get() & 0xff)) + | (((long) buf.get() & 0xff) << 8) + | (((long) buf.get() & 0xff) << 16) + | (((long) buf.get() & 0xff) << 24) + | (((long) get() & 0xff) << 32) + | (((long) get() & 0xff) << 40) + | (((long) get() & 0xff) << 48) + | (((long) get()) << 56)); + } + if (remain == 5) { + return ((((long) buf.get() & 0xff)) + | (((long) buf.get() & 0xff) << 8) + | (((long) buf.get() & 0xff) << 16) + | (((long) buf.get() & 0xff) << 24) + | (((long) buf.get() & 0xff) << 32) + | (((long) get() & 0xff) << 40) + | (((long) get() & 0xff) << 48) + | (((long) get()) << 56)); + } + if (remain == 6) { + return ((((long) buf.get() & 0xff)) + | (((long) buf.get() & 0xff) << 8) + | (((long) buf.get() & 0xff) << 16) + | (((long) buf.get() & 0xff) << 24) + | (((long) buf.get() & 0xff) << 32) + | (((long) buf.get() & 0xff) << 40) + | (((long) get() & 0xff) << 48) + | (((long) get()) << 56)); + } + //remain == 7 + return ((((long) buf.get() & 0xff)) + | (((long) buf.get() & 0xff) << 8) + | (((long) buf.get() & 0xff) << 16) + | (((long) buf.get() & 0xff) << 24) + | (((long) buf.get() & 0xff) << 32) + | (((long) buf.get() & 0xff) << 40) + | (((long) buf.get() & 0xff) << 48) + | (((long) get()) << 56)); + } + + public double getDouble() { + return Double.longBitsToDouble(getLong()); + } + + public ByteBufferReader get(byte[] dst) { + return get(dst, 0, dst.length); + } + + public ByteBufferReader get(byte[] dst, int offset, int length) { + ByteBuffer buf = this.currBuffer; + int remain = buf.remaining(); + if (remain >= length) { + buf.get(dst, offset, length); + return this; + } + buf.get(dst, offset, remain); + this.currBuffer = this.buffers[++this.currIndex]; + return get(dst, offset + remain, length - remain); + } + + public ByteBufferReader skip(int size) { + ByteBuffer buf = this.currBuffer; + int remain = buf.remaining(); + if (remain >= size) { + buf.position(buf.position() + size); + return this; + } + buf.position(buf.position() + remain); + this.currBuffer = this.buffers[++this.currIndex]; + return skip(size - remain); + } +} diff --git a/src/main/java/org/redkale/util/ByteBufferWriter.java b/src/main/java/org/redkale/util/ByteBufferWriter.java index d89720ee4..5938a05e7 100644 --- a/src/main/java/org/redkale/util/ByteBufferWriter.java +++ b/src/main/java/org/redkale/util/ByteBufferWriter.java @@ -1,220 +1,220 @@ -/* - * 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.util; - -import java.nio.*; -import java.util.function.Supplier; - -/** - * 浠yteBuffer涓烘暟鎹浇浣撶殑Writer - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public class ByteBufferWriter { - - private final Supplier supplier; - - private ByteBuffer[] buffers; - - private int position; - - private int writeBytesCounter = 0; //put(byte[] src, int offset, int length) 璋冪敤鐨勬鏁 - - private boolean bigEndian = true; - - protected ByteBufferWriter(Supplier supplier) { - this.supplier = supplier; - } - - public static ByteBufferWriter create(Supplier supplier) { - return new ByteBufferWriter(supplier); - } - - public static ByteBufferWriter create(Supplier supplier, ByteBuffer one) { - ByteBufferWriter writer = new ByteBufferWriter(supplier); - writer.bigEndian = one.order() == ByteOrder.BIG_ENDIAN; - writer.buffers = new ByteBuffer[]{one}; - return writer; - } - - public static ByteBuffer[] toBuffers(Supplier supplier, byte[] content) { - ByteBufferWriter writer = new ByteBufferWriter(supplier); - writer.put(false, content, 0, content.length); - return writer.toBuffers(); - } - - public static ByteBuffer[] toBuffers(Supplier supplier, byte[] content, int offset, int length) { - ByteBufferWriter writer = new ByteBufferWriter(supplier); - writer.put(false, content, offset, length); - return writer.toBuffers(); - } - - private ByteBuffer getLastBuffer(int size) { - if (this.buffers == null) { - ByteBuffer buf = supplier.get(); - this.bigEndian = buf.order() == ByteOrder.BIG_ENDIAN; - this.buffers = Utility.append(this.buffers, buf); - return buf; - } else if (this.buffers[this.buffers.length - 1].remaining() < size) { - ByteBuffer buf = supplier.get(); - this.buffers = Utility.append(this.buffers, buf); - return buf; - } - return this.buffers[this.buffers.length - 1]; - } - - public ByteBuffer[] toBuffers() { - if (buffers == null) return new ByteBuffer[0]; - for (ByteBuffer buf : this.buffers) { - buf.flip(); - } - return this.buffers; - } - - public int position() { - return position; - } - - public ByteBufferWriter put(byte b) { - getLastBuffer(1).put(b); - position++; - return this; - } - - public ByteBufferWriter putShort(short value) { - getLastBuffer(2).putShort(value); - position += 2; - return this; - } - - public ByteBufferWriter putInt(int value) { - getLastBuffer(4).putInt(value); - position += 4; - return this; - } - - //閲嶆柊璁剧疆鎸囧畾浣嶇疆鐨勫 - public ByteBufferWriter putInt(final int index, int value) { - int start = 0; - ByteBuffer[] buffs = this.buffers; - for (int i = 0; i < buffs.length; i++) { - int pos = buffs[i].position(); - if (pos + start > index) { - int r = pos + start - index; - if (r >= 4) { - buffs[i].putInt(index - start, value); - return this; - } else { - byte b1 = bigEndian ? (byte) ((value >> 24) & 0xFF) : (byte) (value & 0xFF); - byte b2 = bigEndian ? (byte) ((value >> 16) & 0xFF) : (byte) ((value >> 8) & 0xFF); - byte b3 = bigEndian ? (byte) ((value >> 8) & 0xFF) : (byte) ((value >> 16) & 0xFF); - byte b4 = bigEndian ? (byte) (value & 0xFF) : (byte) ((value >> 24) & 0xFF); - if (r == 3) { - buffs[i].put(index - start, b1); - buffs[i].put(index - start + 1, b2); - buffs[i].put(index - start + 2, b3); - buffs[i + 1].put(0, b4); - } else if (r == 2) { - buffs[i].put(index - start, b1); - buffs[i].put(index - start + 1, b2); - buffs[i + 1].put(0, b3); - buffs[i + 1].put(1, b4); - } else if (r == 1) { - buffs[i].put(index - start, b1); - buffs[i + 1].put(0, b2); - buffs[i + 1].put(1, b3); - buffs[i + 1].put(2, b4); - } - return this; - } - } else { - start += pos; - } - } - throw new ArrayIndexOutOfBoundsException(index); - } - -// public static void main(String[] args) throws Throwable { -// ObjectPool pool = new ObjectPool<>(20, (p) -> ByteBuffer.allocate(10), (ByteBuffer t) -> t.clear(), (ByteBuffer t) -> false); -// ByteBufferWriter writer = ByteBufferWriter.create(pool); -// for (int i = 1; i <= 18; i++) { -// writer.put((byte) i); -// } -// System.out.println(Arrays.toString(toBytes(writer.toBuffers()))); -// -// writer = ByteBufferWriter.create(pool); -// for (int i = 1; i <= 18; i++) { -// writer.put((byte) i); -// } -// int value = 0x223344; -// byte[] b4 = new byte[]{(byte) ((value >> 24) & 0xFF), (byte) ((value >> 16) & 0xFF), (byte) ((value >> 8) & 0xFF), (byte) (value & 0xFF)}; -// writer.putInt(9, value); -// System.out.println(Arrays.toString(b4)); -// System.out.println(Arrays.toString(toBytes(writer.toBuffers()))); -// } - public ByteBufferWriter putFloat(float value) { - getLastBuffer(4).putFloat(value); - position += 4; - return this; - } - - public ByteBufferWriter putLong(long value) { - getLastBuffer(8).putLong(value); - position += 8; - return this; - } - - public ByteBufferWriter putDouble(double value) { - getLastBuffer(8).putDouble(value); - position += 8; - return this; - } - - public int put(byte[] src) { - return put(true, src, 0, src.length); - } - - public int put(byte[] src, int offset, int length) { - return put(true, src, offset, length); - } - - public int put(byte[] src, int offset, int length, byte[] src2, int offset2, int length2) { - ByteBuffer buf = getLastBuffer(1); - int remain = buf.remaining(); - if (remain >= length + length2) { - buf.put(src, offset, length); - if (src2 != null) buf.put(src2, offset2, length2); - position += length + length2; - this.writeBytesCounter++; - } else { - put(true, src, offset, length); - if (src2 != null) put(false, src2, offset2, length2); - } - return writeBytesCounter; - } - - private int put(boolean outside, byte[] src, int offset, int length) { - ByteBuffer buf = getLastBuffer(1); - int remain = buf.remaining(); - if (remain >= length) { - buf.put(src, offset, length); - position += length; - } else { - buf.put(src, offset, remain); - position += remain; - put(false, src, offset + remain, length - remain); - } - if (outside) this.writeBytesCounter++; - return writeBytesCounter; - } - - public int getWriteBytesCounter() { - return this.writeBytesCounter; - } -} +/* + * 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.util; + +import java.nio.*; +import java.util.function.Supplier; + +/** + * 浠yteBuffer涓烘暟鎹浇浣撶殑Writer + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public class ByteBufferWriter { + + private final Supplier supplier; + + private ByteBuffer[] buffers; + + private int position; + + private int writeBytesCounter = 0; //put(byte[] src, int offset, int length) 璋冪敤鐨勬鏁 + + private boolean bigEndian = true; + + protected ByteBufferWriter(Supplier supplier) { + this.supplier = supplier; + } + + public static ByteBufferWriter create(Supplier supplier) { + return new ByteBufferWriter(supplier); + } + + public static ByteBufferWriter create(Supplier supplier, ByteBuffer one) { + ByteBufferWriter writer = new ByteBufferWriter(supplier); + writer.bigEndian = one.order() == ByteOrder.BIG_ENDIAN; + writer.buffers = new ByteBuffer[]{one}; + return writer; + } + + public static ByteBuffer[] toBuffers(Supplier supplier, byte[] content) { + ByteBufferWriter writer = new ByteBufferWriter(supplier); + writer.put(false, content, 0, content.length); + return writer.toBuffers(); + } + + public static ByteBuffer[] toBuffers(Supplier supplier, byte[] content, int offset, int length) { + ByteBufferWriter writer = new ByteBufferWriter(supplier); + writer.put(false, content, offset, length); + return writer.toBuffers(); + } + + private ByteBuffer getLastBuffer(int size) { + if (this.buffers == null) { + ByteBuffer buf = supplier.get(); + this.bigEndian = buf.order() == ByteOrder.BIG_ENDIAN; + this.buffers = Utility.append(this.buffers, buf); + return buf; + } else if (this.buffers[this.buffers.length - 1].remaining() < size) { + ByteBuffer buf = supplier.get(); + this.buffers = Utility.append(this.buffers, buf); + return buf; + } + return this.buffers[this.buffers.length - 1]; + } + + public ByteBuffer[] toBuffers() { + if (buffers == null) return new ByteBuffer[0]; + for (ByteBuffer buf : this.buffers) { + buf.flip(); + } + return this.buffers; + } + + public int position() { + return position; + } + + public ByteBufferWriter put(byte b) { + getLastBuffer(1).put(b); + position++; + return this; + } + + public ByteBufferWriter putShort(short value) { + getLastBuffer(2).putShort(value); + position += 2; + return this; + } + + public ByteBufferWriter putInt(int value) { + getLastBuffer(4).putInt(value); + position += 4; + return this; + } + + //閲嶆柊璁剧疆鎸囧畾浣嶇疆鐨勫 + public ByteBufferWriter putInt(final int index, int value) { + int start = 0; + ByteBuffer[] buffs = this.buffers; + for (int i = 0; i < buffs.length; i++) { + int pos = buffs[i].position(); + if (pos + start > index) { + int r = pos + start - index; + if (r >= 4) { + buffs[i].putInt(index - start, value); + return this; + } else { + byte b1 = bigEndian ? (byte) ((value >> 24) & 0xFF) : (byte) (value & 0xFF); + byte b2 = bigEndian ? (byte) ((value >> 16) & 0xFF) : (byte) ((value >> 8) & 0xFF); + byte b3 = bigEndian ? (byte) ((value >> 8) & 0xFF) : (byte) ((value >> 16) & 0xFF); + byte b4 = bigEndian ? (byte) (value & 0xFF) : (byte) ((value >> 24) & 0xFF); + if (r == 3) { + buffs[i].put(index - start, b1); + buffs[i].put(index - start + 1, b2); + buffs[i].put(index - start + 2, b3); + buffs[i + 1].put(0, b4); + } else if (r == 2) { + buffs[i].put(index - start, b1); + buffs[i].put(index - start + 1, b2); + buffs[i + 1].put(0, b3); + buffs[i + 1].put(1, b4); + } else if (r == 1) { + buffs[i].put(index - start, b1); + buffs[i + 1].put(0, b2); + buffs[i + 1].put(1, b3); + buffs[i + 1].put(2, b4); + } + return this; + } + } else { + start += pos; + } + } + throw new ArrayIndexOutOfBoundsException(index); + } + +// public static void main(String[] args) throws Throwable { +// ObjectPool pool = new ObjectPool<>(20, (p) -> ByteBuffer.allocate(10), (ByteBuffer t) -> t.clear(), (ByteBuffer t) -> false); +// ByteBufferWriter writer = ByteBufferWriter.create(pool); +// for (int i = 1; i <= 18; i++) { +// writer.put((byte) i); +// } +// System.out.println(Arrays.toString(toBytes(writer.toBuffers()))); +// +// writer = ByteBufferWriter.create(pool); +// for (int i = 1; i <= 18; i++) { +// writer.put((byte) i); +// } +// int value = 0x223344; +// byte[] b4 = new byte[]{(byte) ((value >> 24) & 0xFF), (byte) ((value >> 16) & 0xFF), (byte) ((value >> 8) & 0xFF), (byte) (value & 0xFF)}; +// writer.putInt(9, value); +// System.out.println(Arrays.toString(b4)); +// System.out.println(Arrays.toString(toBytes(writer.toBuffers()))); +// } + public ByteBufferWriter putFloat(float value) { + getLastBuffer(4).putFloat(value); + position += 4; + return this; + } + + public ByteBufferWriter putLong(long value) { + getLastBuffer(8).putLong(value); + position += 8; + return this; + } + + public ByteBufferWriter putDouble(double value) { + getLastBuffer(8).putDouble(value); + position += 8; + return this; + } + + public int put(byte[] src) { + return put(true, src, 0, src.length); + } + + public int put(byte[] src, int offset, int length) { + return put(true, src, offset, length); + } + + public int put(byte[] src, int offset, int length, byte[] src2, int offset2, int length2) { + ByteBuffer buf = getLastBuffer(1); + int remain = buf.remaining(); + if (remain >= length + length2) { + buf.put(src, offset, length); + if (src2 != null) buf.put(src2, offset2, length2); + position += length + length2; + this.writeBytesCounter++; + } else { + put(true, src, offset, length); + if (src2 != null) put(false, src2, offset2, length2); + } + return writeBytesCounter; + } + + private int put(boolean outside, byte[] src, int offset, int length) { + ByteBuffer buf = getLastBuffer(1); + int remain = buf.remaining(); + if (remain >= length) { + buf.put(src, offset, length); + position += length; + } else { + buf.put(src, offset, remain); + position += remain; + put(false, src, offset + remain, length - remain); + } + if (outside) this.writeBytesCounter++; + return writeBytesCounter; + } + + public int getWriteBytesCounter() { + return this.writeBytesCounter; + } +} diff --git a/src/main/java/org/redkale/util/ByteTuple.java b/src/main/java/org/redkale/util/ByteTuple.java index c738a24a0..70d43d966 100644 --- a/src/main/java/org/redkale/util/ByteTuple.java +++ b/src/main/java/org/redkale/util/ByteTuple.java @@ -1,24 +1,24 @@ -/* - * 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.util; - -/** - * 绠鍗曠殑byte[]鏁版嵁鎺ュ彛銆 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @since 2.3.0 - */ -public interface ByteTuple { - - public byte[] content(); - - public int offset(); - - public int length(); -} +/* + * 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.util; + +/** + * 绠鍗曠殑byte[]鏁版嵁鎺ュ彛銆 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @since 2.3.0 + */ +public interface ByteTuple { + + public byte[] content(); + + public int offset(); + + public int length(); +} diff --git a/src/main/java/org/redkale/util/Command.java b/src/main/java/org/redkale/util/Command.java index 282f8e469..80397eb27 100644 --- a/src/main/java/org/redkale/util/Command.java +++ b/src/main/java/org/redkale/util/Command.java @@ -1,28 +1,28 @@ -/* - * 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.util; - -import java.lang.annotation.*; -import static java.lang.annotation.ElementType.*; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * 鎺ユ敹鍛戒护鐨勬爣璁帮紝 鍙兘鏍囪鍦ㄦ湰鍦版ā寮忎笅Service閲屽弬鏁颁负String涓旇繑鍥炵被鍨嬩负void鐨刾ublic鏂规硶涓 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * - * @since 2.1.0 - */ -@Inherited -@Documented -@Target({METHOD}) -@Retention(RUNTIME) -public @interface Command { - -} +/* + * 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.util; + +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * 鎺ユ敹鍛戒护鐨勬爣璁帮紝 鍙兘鏍囪鍦ㄦ湰鍦版ā寮忎笅Service閲屽弬鏁颁负String涓旇繑鍥炵被鍨嬩负void鐨刾ublic鏂规硶涓 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.1.0 + */ +@Inherited +@Documented +@Target({METHOD}) +@Retention(RUNTIME) +public @interface Command { + +} diff --git a/src/main/java/org/redkale/util/Comment.java b/src/main/java/org/redkale/util/Comment.java index fa11d8031..0f5f779ee 100644 --- a/src/main/java/org/redkale/util/Comment.java +++ b/src/main/java/org/redkale/util/Comment.java @@ -1,29 +1,29 @@ -/* - * 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.util; - -import java.lang.annotation.*; -import static java.lang.annotation.ElementType.*; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * 鏍囪娉ㄩ噴锛屽娉 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@Inherited -@Documented -@Target({TYPE, METHOD, FIELD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, ANNOTATION_TYPE, TYPE_PARAMETER}) -@Retention(RUNTIME) -public @interface Comment { - - String name() default ""; - - String value(); -} +/* + * 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.util; + +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * 鏍囪娉ㄩ噴锛屽娉 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@Inherited +@Documented +@Target({TYPE, METHOD, FIELD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, ANNOTATION_TYPE, TYPE_PARAMETER}) +@Retention(RUNTIME) +public @interface Comment { + + String name() default ""; + + String value(); +} diff --git a/src/main/java/org/redkale/util/ConstructorParameters.java b/src/main/java/org/redkale/util/ConstructorParameters.java index b7adcaa41..ab456a138 100644 --- a/src/main/java/org/redkale/util/ConstructorParameters.java +++ b/src/main/java/org/redkale/util/ConstructorParameters.java @@ -1,26 +1,26 @@ -/* - * 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.util; - -import java.lang.annotation.*; -import static java.lang.annotation.ElementType.*; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * 绫讳技java.beans.ConstructorProperties, 蹇呴』閰嶅悎Creator浣跨敤 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@Documented -@Target({METHOD, CONSTRUCTOR}) -@Retention(RUNTIME) -public @interface ConstructorParameters { - - String[] value(); -} +/* + * 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.util; + +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * 绫讳技java.beans.ConstructorProperties, 蹇呴』閰嶅悎Creator浣跨敤 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@Documented +@Target({METHOD, CONSTRUCTOR}) +@Retention(RUNTIME) +public @interface ConstructorParameters { + + String[] value(); +} diff --git a/src/main/java/org/redkale/util/Creator.java b/src/main/java/org/redkale/util/Creator.java index abcebc80e..c6b075ab2 100644 --- a/src/main/java/org/redkale/util/Creator.java +++ b/src/main/java/org/redkale/util/Creator.java @@ -1,688 +1,688 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ -package org.redkale.util; - -import java.io.*; -import java.lang.reflect.*; -import java.net.*; -import java.util.*; -import java.util.AbstractMap.SimpleEntry; -import java.util.concurrent.*; -import java.util.function.*; -import java.util.logging.*; -import java.util.stream.Stream; -import org.redkale.asm.*; -import org.redkale.asm.Type; -import static org.redkale.asm.Opcodes.*; - -/** - *

- * 瀹炵幇涓涓被鐨勬瀯閫犳柟娉曘 浠f浛浣庢晥鐨勫弽灏勫疄鐜版柟寮忋 涓嶆敮鎸佹暟缁勭被銆 - * 甯歌鐨勬棤鍙傛暟鐨勬瀯閫犲嚱鏁扮被閮藉彲浠ヨ嚜鍔ㄧ敓鎴怌reator锛 瀵瑰簲鑷畾涔夌殑绫诲彲浠ユ彁渚涗竴涓潤鎬佹瀯寤篊reator鏂规硶銆 - * 渚嬪: - *

- * public class Record {
- *
- *    private final int id;
- *
- *    private String name;
- *
- *    Record(int id, String name) {
- *        this.id = id;
- *        this.name = name;
- *    }
- *
- *    private static Creator createCreator() {
- *        return new Creator<Record>() {
- *            @Override
- *            @ConstructorParameters({"id", "name"})
- *            public Record create(Object... params) {
- *                if(params[0] == null) params[0] = 0;
- *                return new Record((Integer) params[0], (String) params[1]);
- *            }
- *         };
- *    }
- * }
- * 
- * - * 鎴栬: - *
- * public class Record {
- *
- *    private final int id;
- *
- *    private String name;
- *
- *    @ConstructorParameters({"id", "name"})
- *    public Record(int id, String name) {
- *        this.id = id;
- *        this.name = name;
- *    }
- * }
- * 
- * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param 鏋勫缓瀵硅薄鐨勬暟鎹被鍨 - */ -public interface Creator { - - @SuppressWarnings("unchecked") - static class CreatorInner { - - static final Logger logger = Logger.getLogger(Creator.class.getSimpleName()); - - static final Map creatorCacheMap = new HashMap<>(); - - static final Map arrayCacheMap = new ConcurrentHashMap<>(); - - static { - creatorCacheMap.put(Object.class, p -> new Object()); - creatorCacheMap.put(ArrayList.class, p -> new ArrayList<>()); - creatorCacheMap.put(HashMap.class, p -> new HashMap<>()); - creatorCacheMap.put(HashSet.class, p -> new HashSet<>()); - creatorCacheMap.put(Stream.class, p -> new ArrayList<>().stream()); - creatorCacheMap.put(ConcurrentHashMap.class, p -> new ConcurrentHashMap<>()); - creatorCacheMap.put(CompletableFuture.class, p -> new CompletableFuture<>()); - creatorCacheMap.put(CompletionStage.class, p -> new CompletableFuture<>()); - creatorCacheMap.put(Map.Entry.class, new Creator() { - @Override - @ConstructorParameters({"key", "value"}) - public Map.Entry create(Object... params) { - return new AbstractMap.SimpleEntry(params[0], params[1]); - } - }); - creatorCacheMap.put(AbstractMap.SimpleEntry.class, new Creator() { - @Override - @ConstructorParameters({"key", "value"}) - public AbstractMap.SimpleEntry create(Object... params) { - return new AbstractMap.SimpleEntry(params[0], params[1]); - } - }); - creatorCacheMap.put(AnyValue.DefaultAnyValue.class, p -> new AnyValue.DefaultAnyValue()); - creatorCacheMap.put(AnyValue.class, p -> new AnyValue.DefaultAnyValue()); - - arrayCacheMap.put(int.class, t -> new int[t]); - arrayCacheMap.put(byte.class, t -> new byte[t]); - arrayCacheMap.put(long.class, t -> new long[t]); - arrayCacheMap.put(String.class, t -> new String[t]); - arrayCacheMap.put(Object.class, t -> new Object[t]); - arrayCacheMap.put(boolean.class, t -> new boolean[t]); - arrayCacheMap.put(short.class, t -> new short[t]); - arrayCacheMap.put(char.class, t -> new char[t]); - arrayCacheMap.put(float.class, t -> new float[t]); - arrayCacheMap.put(double.class, t -> new double[t]); - } - - static class SimpleClassVisitor extends ClassVisitor { - - private final String constructorDesc; - - private final List fieldnames; - - private boolean started; - - public SimpleClassVisitor(int api, List fieldnames, String constructorDesc) { - super(api); - this.fieldnames = fieldnames; - this.constructorDesc = constructorDesc; - } - - @Override - public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { - if (java.lang.reflect.Modifier.isStatic(access) || !"".equals(name)) return null; - if (constructorDesc != null && !constructorDesc.equals(desc)) return null; - if (this.started) return null; - this.started = true; - //杩斿洖鐨凩ist涓弬鏁板垪琛ㄥ彲鑳戒細姣旀柟娉曞弬鏁伴噺澶氾紝鍥犱负鏂规硶鍐呯殑涓存椂鍙橀噺涔熶細瀛樺叆list涓紝 鎵浠ラ渶瑕乴ist鐨勫厓绱犻泦鍚堟瘮鏂规硶鐨勫弬鏁板 - return new MethodVisitor(Opcodes.ASM6) { - @Override - public void visitLocalVariable(String name, String description, String signature, Label start, Label end, int index) { - if (index < 1) return; - int size = fieldnames.size(); - //index涓嶄細鎸夐『搴忔墽琛岀殑 - if (index > size) { - for (int i = size; i < index; i++) { - fieldnames.add(" "); - } - fieldnames.set(index - 1, name); - } - fieldnames.set(index - 1, name); - } - }; - } - } - - public static SimpleEntry[] getConstructorField(Class clazz, int paramcount, String constructorDesc) { - String n = clazz.getName(); - InputStream in = clazz.getResourceAsStream(n.substring(n.lastIndexOf('.') + 1) + ".class"); - if (in == null) return null; - ByteArrayOutputStream out = new ByteArrayOutputStream(1024); - byte[] bytes = new byte[1024]; - int pos; - try { - while ((pos = in.read(bytes)) != -1) { - out.write(bytes, 0, pos); - } - in.close(); - } catch (IOException io) { - return null; - } - final List fieldnames = new ArrayList<>(); - new ClassReader(out.toByteArray()).accept(new SimpleClassVisitor(Opcodes.ASM6, fieldnames, constructorDesc), 0); - while (fieldnames.remove(" ")); //鍒犳帀绌哄厓绱 - if (fieldnames.isEmpty()) return null; - if (paramcount == fieldnames.size()) { - return getConstructorField(clazz, paramcount, fieldnames.toArray(new String[fieldnames.size()])); - } else { - String[] fs = new String[paramcount]; - for (int i = 0; i < fs.length; i++) { - fs[i] = fieldnames.get(i); - } - return getConstructorField(clazz, paramcount, fs); - } - } - - public static SimpleEntry[] getConstructorField(Class clazz, int paramcount, String[] names) { - SimpleEntry[] se = new SimpleEntry[names.length]; - for (int i = 0; i < names.length; i++) { //鏌ヨ鍙傛暟鍚嶅搴旂殑Field - try { - Field field = clazz.getDeclaredField(names[i]); - se[i] = new SimpleEntry<>(field.getName(), field.getType()); - } catch (NoSuchFieldException fe) { - Class cz = clazz; - Field field = null; - while ((cz = cz.getSuperclass()) != Object.class) { - try { - field = cz.getDeclaredField(names[i]); - break; - } catch (NoSuchFieldException nsfe) { - } - } - if (field == null) return null; - se[i] = new SimpleEntry<>(field.getName(), field.getType()); - } catch (Exception e) { - if (logger.isLoggable(Level.FINE)) logger.log(Level.FINE, clazz + " getConstructorField error", e); - return null; - } - } - return se; - } - - public static SimpleEntry[] getConstructorField(Class clazz, int paramcount, Parameter[] params) { - SimpleEntry[] se = new SimpleEntry[params.length]; - for (int i = 0; i < params.length; i++) { //鏌ヨ鍙傛暟鍚嶅搴旂殑Field - try { - Field field = clazz.getDeclaredField(params[i].getName()); - se[i] = new SimpleEntry<>(field.getName(), field.getType()); - } catch (Exception e) { - return null; - } - } - return se; - } - - static class TypeArrayIntFunction implements IntFunction { - - private final Class type; - - public TypeArrayIntFunction(Class type) { - this.type = type; - } - - @Override - public T[] apply(int value) { - return (T[]) Array.newInstance(type, value); - } - - } - - public static IntFunction createArrayFunction(final Class clazz) { - final String interName = clazz.getName().replace('.', '/'); - final String interDesc = Type.getDescriptor(clazz); - final ClassLoader loader = clazz.getClassLoader(); - final String newDynName = "org/redkaledyn/creator/_DynArrayFunction__" + clazz.getName().replace('.', '_').replace('$', '_'); - try { - Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); - return (IntFunction) (clz == null ? loader.loadClass(newDynName.replace('/', '.')) : clz).getDeclaredConstructor().newInstance(); - } catch (Throwable ex) { - } - - //------------------------------------------------------------- - ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); - MethodVisitor mv; - cw.visit(V11, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, "Ljava/lang/Object;Ljava/util/function/IntFunction<[" + interDesc + ">;", "java/lang/Object", new String[]{"java/util/function/IntFunction"}); - - {//IntFunction鑷韩鐨勬瀯閫犳柟娉 - mv = cw.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(); - } - {//apply 鏂规硶 - mv = cw.visitMethod(ACC_PUBLIC, "apply", "(I)[" + interDesc, null, null); - mv.visitVarInsn(ILOAD, 1); - mv.visitTypeInsn(ANEWARRAY, interName); - mv.visitInsn(ARETURN); - mv.visitMaxs(1, 2); - mv.visitEnd(); - } - { //铏氭嫙 apply 鏂规硶 - mv = cw.visitMethod(ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, "apply", "(I)Ljava/lang/Object;", null, null); - mv.visitVarInsn(ALOAD, 0); - mv.visitVarInsn(ILOAD, 1); - mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "apply", "(I)[" + interDesc, false); - mv.visitInsn(ARETURN); - mv.visitMaxs(2, 2); - mv.visitEnd(); - } - cw.visitEnd(); - final byte[] bytes = cw.toByteArray(); - try { - Class resultClazz = new ClassLoader(loader) { - public final Class loadClass(String name, byte[] b) { - return defineClass(name, b, 0, b.length); - } - }.loadClass(newDynName.replace('/', '.'), bytes); - RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, resultClazz); - RedkaleClassLoader.putReflectionDeclaredConstructors(resultClazz, newDynName.replace('/', '.')); - return (IntFunction) resultClazz.getDeclaredConstructor().newInstance(); - } catch (Exception ex) { - ex.printStackTrace(); //涓鑸笉浼氬彂鐢 - return t -> (T[]) Array.newInstance(clazz, t); - //throw new RuntimeException(ex); - } - } - } - - /** - * 鍒涘缓瀵硅薄 - * - * @param params 鏋勯犲嚱鏁扮殑鍙傛暟 - * - * @return 鏋勫缓鐨勫璞 - */ - public T create(Object... params); - - /** - * 鍒涘缓鎸囧畾绫诲瀷瀵硅薄鏁扮粍鐨処ntFunction - * - * @param 娉涘瀷 - * @param type 绫诲瀷 - * - * @return IntFunction - */ - public static IntFunction arrayFunction(final Class type) { - return CreatorInner.arrayCacheMap.computeIfAbsent(type, t -> CreatorInner.createArrayFunction(t)); - } - - /** - * 鍒涘缓鎸囧畾澶у皬鐨勫璞℃暟缁 - * - * @param 娉涘瀷 - * @param type 绫诲瀷 - * @param size 鏁扮粍澶у皬 - * - * @return 鏁扮粍 - */ - public static T[] newArray(final Class type, final int size) { - if (type == int.class) return (T[]) (Object) new int[size]; - if (type == byte.class) return (T[]) (Object) new byte[size]; - if (type == long.class) return (T[]) (Object) new long[size]; - if (type == String.class) return (T[]) new String[size]; - if (type == Object.class) return (T[]) new Object[size]; - if (type == boolean.class) return (T[]) (Object) new boolean[size]; - if (type == short.class) return (T[]) (Object) new short[size]; - if (type == char.class) return (T[]) (Object) new char[size]; - if (type == float.class) return (T[]) (Object) new float[size]; - if (type == double.class) return (T[]) (Object) new double[size]; - //return (T[]) Array.newInstance(type, size); - return arrayFunction(type).apply(size); - } - - /** - * 鏍规嵁Supplier鐢熶骇Creator - * - * @param 鏋勫缓绫荤殑鏁版嵁绫诲瀷 - * @param supplier Supplier - * - * @return Creator瀵硅薄 - */ - public static Creator create(final Supplier supplier) { - Objects.requireNonNull(supplier); - return (Object... params) -> supplier.get(); - } - - /** - * 鏍规嵁Function鐢熶骇Creator - * - * @param 鏋勫缓绫荤殑鏁版嵁绫诲瀷 - * @param func Function - * - * @return Creator瀵硅薄 - */ - public static Creator create(final Function func) { - Objects.requireNonNull(func); - return (Object... params) -> func.apply(params); - } - - /** - * 鏍规嵁鎸囧畾鐨刢lass閲囩敤ASM鎶鏈敓浜reator銆 - * - * @param 鏋勫缓绫荤殑鏁版嵁绫诲瀷 - * @param clazz 鏋勫缓绫 - * - * @return Creator瀵硅薄 - */ - @SuppressWarnings("unchecked") - public static Creator create(Class clazz) { - if (List.class.isAssignableFrom(clazz) && (clazz.isAssignableFrom(ArrayList.class) || clazz.getName().startsWith("java.util.Collections") || clazz.getName().startsWith("java.util.ImmutableCollections") || clazz.getName().startsWith("java.util.Arrays"))) { - clazz = (Class) ArrayList.class; - } else if (Map.class.isAssignableFrom(clazz) && (clazz.isAssignableFrom(HashMap.class) || clazz.getName().startsWith("java.util.Collections") || clazz.getName().startsWith("java.util.ImmutableCollections"))) { - clazz = (Class) HashMap.class; - } else if (Set.class.isAssignableFrom(clazz) && (clazz.isAssignableFrom(HashSet.class) || clazz.getName().startsWith("java.util.Collections") || clazz.getName().startsWith("java.util.ImmutableCollections"))) { - clazz = (Class) HashSet.class; - } else if (Map.class.isAssignableFrom(clazz) && clazz.isAssignableFrom(ConcurrentHashMap.class)) { - clazz = (Class) ConcurrentHashMap.class; - } else if (Deque.class.isAssignableFrom(clazz) && (clazz.isAssignableFrom(ArrayDeque.class) || clazz.getName().startsWith("java.util.Collections") || clazz.getName().startsWith("java.util.ImmutableCollections"))) { - clazz = (Class) ArrayDeque.class; - } else if (Collection.class.isAssignableFrom(clazz) && clazz.isAssignableFrom(ArrayList.class)) { - clazz = (Class) ArrayList.class; - } else if (Map.Entry.class.isAssignableFrom(clazz) && (Modifier.isInterface(clazz.getModifiers()) || Modifier.isAbstract(clazz.getModifiers()) || !Modifier.isPublic(clazz.getModifiers()))) { - clazz = (Class) AbstractMap.SimpleEntry.class; - } else if (Iterable.class == clazz) { - clazz = (Class) ArrayList.class; - } - Creator creator = CreatorInner.creatorCacheMap.get(clazz); - if (creator != null) return creator; - if (clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers())) { - throw new RuntimeException("[" + clazz + "] is a interface or abstract class, cannot create it's Creator."); - } - for (final Method method : clazz.getDeclaredMethods()) { //鏌ユ壘绫讳腑鏄惁瀛樺湪鎻愪緵鍒涘缓Creator瀹炰緥鐨勯潤鎬佹柟娉 - if (!Modifier.isStatic(method.getModifiers())) continue; - if (method.getParameterTypes().length != 0) continue; - if (method.getReturnType() != Creator.class) continue; - try { - method.setAccessible(true); - Creator c = (Creator) method.invoke(null); - if (c != null) { - RedkaleClassLoader.putReflectionDeclaredMethods(clazz.getName()); - RedkaleClassLoader.putReflectionMethod(clazz.getName(), method); - return c; - } - } catch (Exception e) { - throw new RuntimeException(e); - } - } - final String supDynName = Creator.class.getName().replace('.', '/'); - final String interName = clazz.getName().replace('.', '/'); - final String interDesc = Type.getDescriptor(clazz); - ClassLoader loader = Thread.currentThread().getContextClassLoader(); - if (String.class.getClassLoader() != clazz.getClassLoader()) { - loader = clazz.getClassLoader(); - } - final String newDynName = "org/redkaledyn/creator/_Dyn" + Creator.class.getSimpleName() + "__" + clazz.getName().replace('.', '_').replace('$', '_'); - try { - Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); - return (Creator) (clz == null ? loader.loadClass(newDynName.replace('/', '.')) : clz).getDeclaredConstructor().newInstance(); - } catch (Throwable ex) { - } - - Constructor constructor0 = null; - SimpleEntry[] constructorParameters0 = null; //鏋勯犲嚱鏁扮殑鍙傛暟 - - if (constructor0 == null) { // 1銆佹煡鎵緋ublic鐨勭┖鍙傛暟鏋勯犲嚱鏁 - for (Constructor c : clazz.getConstructors()) { - if (c.getParameterCount() == 0) { - constructor0 = c; - constructorParameters0 = new SimpleEntry[0]; - break; - } - } - } - if (constructor0 == null) { // 2銆佹煡鎵緋ublic甯onstructorParameters娉ㄨВ鐨勬瀯閫犲嚱鏁 - for (Constructor c : clazz.getConstructors()) { - ConstructorParameters cp = (ConstructorParameters) c.getAnnotation(ConstructorParameters.class); - if (cp == null) continue; - SimpleEntry[] fields = CreatorInner.getConstructorField(clazz, c.getParameterCount(), cp.value()); - if (fields != null) { - constructor0 = c; - constructorParameters0 = fields; - break; - } - } - } - if (constructor0 == null) { // 3銆佹煡鎵緋ublic涓斾笉甯onstructorParameters娉ㄨВ鐨勬瀯閫犲嚱鏁 - List cs = new ArrayList<>(); - for (Constructor c : clazz.getConstructors()) { - if (c.getAnnotation(ConstructorParameters.class) != null) continue; - if (c.getParameterCount() < 1) continue; - cs.add(c); - } - //浼樺厛鍙傛暟鏈澶氱殑鏋勯犲嚱鏁 - cs.sort((o1, o2) -> o2.getParameterCount() - o1.getParameterCount()); - for (Constructor c : cs) { - SimpleEntry[] fields = CreatorInner.getConstructorField(clazz, c.getParameterCount(), Type.getConstructorDescriptor(c)); - if (fields != null) { - constructor0 = c; - constructorParameters0 = fields; - break; - } - } - } - if (constructor0 == null) { // 4銆佹煡鎵鹃潪private甯onstructorParameters鐨勬瀯閫犲嚱鏁 - for (Constructor c : clazz.getDeclaredConstructors()) { - if (Modifier.isPublic(c.getModifiers()) || Modifier.isPrivate(c.getModifiers())) continue; - ConstructorParameters cp = (ConstructorParameters) c.getAnnotation(ConstructorParameters.class); - if (cp == null) continue; - SimpleEntry[] fields = CreatorInner.getConstructorField(clazz, c.getParameterCount(), cp.value()); - if (fields != null) { - constructor0 = c; - constructorParameters0 = fields; - break; - } - } - } - if (constructor0 == null) { // 5銆佹煡鎵鹃潪private涓斾笉甯onstructorParameters鐨勬瀯閫犲嚱鏁 - List cs = new ArrayList<>(); - for (Constructor c : clazz.getDeclaredConstructors()) { - if (Modifier.isPublic(c.getModifiers()) || Modifier.isPrivate(c.getModifiers())) continue; - if (c.getAnnotation(ConstructorParameters.class) != null) continue; - if (c.getParameterCount() < 1) continue; - cs.add(c); - } - //浼樺厛鍙傛暟鏈澶氱殑鏋勯犲嚱鏁 - cs.sort((o1, o2) -> o2.getParameterCount() - o1.getParameterCount()); - for (Constructor c : cs) { - SimpleEntry[] fields = CreatorInner.getConstructorField(clazz, c.getParameterCount(), Type.getConstructorDescriptor(c)); - if (fields != null) { - constructor0 = c; - constructorParameters0 = fields; - break; - } - } - } - final Constructor constructor = constructor0; - final SimpleEntry[] constructorParameters = constructorParameters0; - if (constructor == null || constructorParameters == null) { - throw new RuntimeException("[" + clazz + "] have no public or ConstructorParameters-Annotation constructor."); - } - //------------------------------------------------------------- - ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); - FieldVisitor fv; - MethodVisitor mv; - AnnotationVisitor av0; - cw.visit(V11, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, "Ljava/lang/Object;L" + supDynName + "<" + interDesc + ">;", "java/lang/Object", new String[]{supDynName}); - - {//Creator鑷韩鐨勬瀯閫犳柟娉 - mv = cw.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(); - } - {//create 鏂规硶 - mv = cw.visitMethod(ACC_PUBLIC + ACC_VARARGS, "create", "([Ljava/lang/Object;)L" + interName + ";", null, null); - if (constructorParameters.length > 0) { - av0 = mv.visitAnnotation(Type.getDescriptor(ConstructorParameters.class), true); - AnnotationVisitor av1 = av0.visitArray("value"); - for (SimpleEntry n : constructorParameters) { - av1.visit(null, n.getKey()); - } - av1.visitEnd(); - av0.visitEnd(); - } - final int[] iconsts = {ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4, ICONST_5}; - { //鏈塒rimitive鏁版嵁绫诲瀷涓斿间负null鐨勫弬鏁伴渶瑕佽祴榛樿鍊 - for (int i = 0; i < constructorParameters.length; i++) { - final Class pt = constructorParameters[i].getValue(); - if (!pt.isPrimitive()) continue; - mv.visitVarInsn(ALOAD, 1); - if (i < 6) { - mv.visitInsn(iconsts[i]); - } else if (i <= Byte.MAX_VALUE) { - mv.visitIntInsn(BIPUSH, i); - } else if (i <= Short.MAX_VALUE) { - mv.visitIntInsn(SIPUSH, i); - } else { - mv.visitLdcInsn(i); - } - mv.visitInsn(AALOAD); - Label lab = new Label(); - mv.visitJumpInsn(IFNONNULL, lab); - mv.visitVarInsn(ALOAD, 1); - if (i < 6) { - mv.visitInsn(iconsts[i]); - } else if (i <= Byte.MAX_VALUE) { - mv.visitIntInsn(BIPUSH, i); - } else if (i <= Short.MAX_VALUE) { - mv.visitIntInsn(SIPUSH, i); - } else { - mv.visitLdcInsn(i); - } - if (pt == int.class) { - mv.visitInsn(ICONST_0); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false); - } else if (pt == long.class) { - mv.visitInsn(LCONST_0); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", false); - } else if (pt == boolean.class) { - mv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "FALSE", "Ljava/lang/Boolean;"); - } else if (pt == short.class) { - mv.visitInsn(ICONST_0); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;", false); - } else if (pt == float.class) { - mv.visitInsn(FCONST_0); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", false); - } else if (pt == byte.class) { - mv.visitInsn(ICONST_0); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;", false); - } else if (pt == double.class) { - mv.visitInsn(DCONST_0); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false); - } else if (pt == char.class) { - mv.visitInsn(ICONST_0); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;", false); - } - mv.visitInsn(AASTORE); - mv.visitLabel(lab); - } - } - mv.visitTypeInsn(NEW, interName); - mv.visitInsn(DUP); - //--------------------------------------- - { - for (int i = 0; i < constructorParameters.length; i++) { - mv.visitVarInsn(ALOAD, 1); - if (i < 6) { - mv.visitInsn(iconsts[i]); - } else if (i <= Byte.MAX_VALUE) { - mv.visitIntInsn(BIPUSH, i); - } else if (i <= Short.MAX_VALUE) { - mv.visitIntInsn(SIPUSH, i); - } else { - mv.visitLdcInsn(i); - } - mv.visitInsn(AALOAD); - final Class ct = constructorParameters[i].getValue(); - if (ct.isPrimitive()) { - final Class bigct = Array.get(Array.newInstance(ct, 1), 0).getClass(); - mv.visitTypeInsn(CHECKCAST, bigct.getName().replace('.', '/')); - try { - Method pm = bigct.getMethod(ct.getSimpleName() + "Value"); - mv.visitMethodInsn(INVOKEVIRTUAL, bigct.getName().replace('.', '/'), pm.getName(), Type.getMethodDescriptor(pm), false); - } catch (Exception ex) { - throw new RuntimeException(ex); //涓嶅彲鑳戒細鍙戠敓 - } - } else { - mv.visitTypeInsn(CHECKCAST, ct.getName().replace('.', '/')); - } - } - } - //--------------------------------------- - mv.visitMethodInsn(INVOKESPECIAL, interName, "", Type.getConstructorDescriptor(constructor), false); - mv.visitInsn(ARETURN); - mv.visitMaxs((constructorParameters.length > 0 ? (constructorParameters.length + 3) : 2), 2); - mv.visitEnd(); - } - { //铏氭嫙 create 鏂规硶 - mv = cw.visitMethod(ACC_PUBLIC + ACC_BRIDGE + ACC_VARARGS + ACC_SYNTHETIC, "create", "([Ljava/lang/Object;)Ljava/lang/Object;", null, null); - mv.visitVarInsn(ALOAD, 0); - mv.visitVarInsn(ALOAD, 1); - mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "create", "([Ljava/lang/Object;)" + interDesc, false); - mv.visitInsn(ARETURN); - mv.visitMaxs(2, 2); - mv.visitEnd(); - } - cw.visitEnd(); - final byte[] bytes = cw.toByteArray(); - final boolean ispub = Modifier.isPublic(constructor.getModifiers()); - Class resultClazz = null; - if (loader instanceof URLClassLoader && !ispub) { - try { - final URLClassLoader urlLoader = (URLClassLoader) loader; - final URL url = new URL("memclass", "localhost", -1, "/" + newDynName.replace('/', '.') + "/", new URLStreamHandler() { - @Override - protected URLConnection openConnection(URL u) throws IOException { - return new URLConnection(u) { - @Override - public void connect() throws IOException { - } - - @Override - public InputStream getInputStream() throws IOException { - return new ByteArrayInputStream(bytes); - } - }; - } - }); - Method addURLMethod = URLClassLoader.class.getDeclaredMethod("addURL", URL.class); - addURLMethod.setAccessible(true); - addURLMethod.invoke(urlLoader, url); - resultClazz = urlLoader.loadClass(newDynName.replace('/', '.')); - } catch (Throwable t) { //寮傚父鏃犻渶鐞嗕細锛 浣跨敤涓嬩竴绉峫oader鏂瑰紡 - t.printStackTrace(); - } - } - if (!ispub && resultClazz == null) throw new RuntimeException("[" + clazz + "] have no public or ConstructorParameters-Annotation constructor."); - try { - if (resultClazz == null) resultClazz = new ClassLoader(loader) { - public final Class loadClass(String name, byte[] b) { - return defineClass(name, b, 0, b.length); - } - }.loadClass(newDynName.replace('/', '.'), bytes); - RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, resultClazz); - RedkaleClassLoader.putReflectionDeclaredConstructors(resultClazz, newDynName.replace('/', '.')); - return (Creator) resultClazz.getDeclaredConstructor().newInstance(); - } catch (Exception ex) { - throw new RuntimeException(ex); - } - } -} +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.util; + +import java.io.*; +import java.lang.reflect.*; +import java.net.*; +import java.util.*; +import java.util.AbstractMap.SimpleEntry; +import java.util.concurrent.*; +import java.util.function.*; +import java.util.logging.*; +import java.util.stream.Stream; +import org.redkale.asm.*; +import org.redkale.asm.Type; +import static org.redkale.asm.Opcodes.*; + +/** + *

+ * 瀹炵幇涓涓被鐨勬瀯閫犳柟娉曘 浠f浛浣庢晥鐨勫弽灏勫疄鐜版柟寮忋 涓嶆敮鎸佹暟缁勭被銆 + * 甯歌鐨勬棤鍙傛暟鐨勬瀯閫犲嚱鏁扮被閮藉彲浠ヨ嚜鍔ㄧ敓鎴怌reator锛 瀵瑰簲鑷畾涔夌殑绫诲彲浠ユ彁渚涗竴涓潤鎬佹瀯寤篊reator鏂规硶銆 + * 渚嬪: + *

+ * public class Record {
+ *
+ *    private final int id;
+ *
+ *    private String name;
+ *
+ *    Record(int id, String name) {
+ *        this.id = id;
+ *        this.name = name;
+ *    }
+ *
+ *    private static Creator createCreator() {
+ *        return new Creator<Record>() {
+ *            @Override
+ *            @ConstructorParameters({"id", "name"})
+ *            public Record create(Object... params) {
+ *                if(params[0] == null) params[0] = 0;
+ *                return new Record((Integer) params[0], (String) params[1]);
+ *            }
+ *         };
+ *    }
+ * }
+ * 
+ * + * 鎴栬: + *
+ * public class Record {
+ *
+ *    private final int id;
+ *
+ *    private String name;
+ *
+ *    @ConstructorParameters({"id", "name"})
+ *    public Record(int id, String name) {
+ *        this.id = id;
+ *        this.name = name;
+ *    }
+ * }
+ * 
+ * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param 鏋勫缓瀵硅薄鐨勬暟鎹被鍨 + */ +public interface Creator { + + @SuppressWarnings("unchecked") + static class CreatorInner { + + static final Logger logger = Logger.getLogger(Creator.class.getSimpleName()); + + static final Map creatorCacheMap = new HashMap<>(); + + static final Map arrayCacheMap = new ConcurrentHashMap<>(); + + static { + creatorCacheMap.put(Object.class, p -> new Object()); + creatorCacheMap.put(ArrayList.class, p -> new ArrayList<>()); + creatorCacheMap.put(HashMap.class, p -> new HashMap<>()); + creatorCacheMap.put(HashSet.class, p -> new HashSet<>()); + creatorCacheMap.put(Stream.class, p -> new ArrayList<>().stream()); + creatorCacheMap.put(ConcurrentHashMap.class, p -> new ConcurrentHashMap<>()); + creatorCacheMap.put(CompletableFuture.class, p -> new CompletableFuture<>()); + creatorCacheMap.put(CompletionStage.class, p -> new CompletableFuture<>()); + creatorCacheMap.put(Map.Entry.class, new Creator() { + @Override + @ConstructorParameters({"key", "value"}) + public Map.Entry create(Object... params) { + return new AbstractMap.SimpleEntry(params[0], params[1]); + } + }); + creatorCacheMap.put(AbstractMap.SimpleEntry.class, new Creator() { + @Override + @ConstructorParameters({"key", "value"}) + public AbstractMap.SimpleEntry create(Object... params) { + return new AbstractMap.SimpleEntry(params[0], params[1]); + } + }); + creatorCacheMap.put(AnyValue.DefaultAnyValue.class, p -> new AnyValue.DefaultAnyValue()); + creatorCacheMap.put(AnyValue.class, p -> new AnyValue.DefaultAnyValue()); + + arrayCacheMap.put(int.class, t -> new int[t]); + arrayCacheMap.put(byte.class, t -> new byte[t]); + arrayCacheMap.put(long.class, t -> new long[t]); + arrayCacheMap.put(String.class, t -> new String[t]); + arrayCacheMap.put(Object.class, t -> new Object[t]); + arrayCacheMap.put(boolean.class, t -> new boolean[t]); + arrayCacheMap.put(short.class, t -> new short[t]); + arrayCacheMap.put(char.class, t -> new char[t]); + arrayCacheMap.put(float.class, t -> new float[t]); + arrayCacheMap.put(double.class, t -> new double[t]); + } + + static class SimpleClassVisitor extends ClassVisitor { + + private final String constructorDesc; + + private final List fieldnames; + + private boolean started; + + public SimpleClassVisitor(int api, List fieldnames, String constructorDesc) { + super(api); + this.fieldnames = fieldnames; + this.constructorDesc = constructorDesc; + } + + @Override + public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { + if (java.lang.reflect.Modifier.isStatic(access) || !"".equals(name)) return null; + if (constructorDesc != null && !constructorDesc.equals(desc)) return null; + if (this.started) return null; + this.started = true; + //杩斿洖鐨凩ist涓弬鏁板垪琛ㄥ彲鑳戒細姣旀柟娉曞弬鏁伴噺澶氾紝鍥犱负鏂规硶鍐呯殑涓存椂鍙橀噺涔熶細瀛樺叆list涓紝 鎵浠ラ渶瑕乴ist鐨勫厓绱犻泦鍚堟瘮鏂规硶鐨勫弬鏁板 + return new MethodVisitor(Opcodes.ASM6) { + @Override + public void visitLocalVariable(String name, String description, String signature, Label start, Label end, int index) { + if (index < 1) return; + int size = fieldnames.size(); + //index涓嶄細鎸夐『搴忔墽琛岀殑 + if (index > size) { + for (int i = size; i < index; i++) { + fieldnames.add(" "); + } + fieldnames.set(index - 1, name); + } + fieldnames.set(index - 1, name); + } + }; + } + } + + public static SimpleEntry[] getConstructorField(Class clazz, int paramcount, String constructorDesc) { + String n = clazz.getName(); + InputStream in = clazz.getResourceAsStream(n.substring(n.lastIndexOf('.') + 1) + ".class"); + if (in == null) return null; + ByteArrayOutputStream out = new ByteArrayOutputStream(1024); + byte[] bytes = new byte[1024]; + int pos; + try { + while ((pos = in.read(bytes)) != -1) { + out.write(bytes, 0, pos); + } + in.close(); + } catch (IOException io) { + return null; + } + final List fieldnames = new ArrayList<>(); + new ClassReader(out.toByteArray()).accept(new SimpleClassVisitor(Opcodes.ASM6, fieldnames, constructorDesc), 0); + while (fieldnames.remove(" ")); //鍒犳帀绌哄厓绱 + if (fieldnames.isEmpty()) return null; + if (paramcount == fieldnames.size()) { + return getConstructorField(clazz, paramcount, fieldnames.toArray(new String[fieldnames.size()])); + } else { + String[] fs = new String[paramcount]; + for (int i = 0; i < fs.length; i++) { + fs[i] = fieldnames.get(i); + } + return getConstructorField(clazz, paramcount, fs); + } + } + + public static SimpleEntry[] getConstructorField(Class clazz, int paramcount, String[] names) { + SimpleEntry[] se = new SimpleEntry[names.length]; + for (int i = 0; i < names.length; i++) { //鏌ヨ鍙傛暟鍚嶅搴旂殑Field + try { + Field field = clazz.getDeclaredField(names[i]); + se[i] = new SimpleEntry<>(field.getName(), field.getType()); + } catch (NoSuchFieldException fe) { + Class cz = clazz; + Field field = null; + while ((cz = cz.getSuperclass()) != Object.class) { + try { + field = cz.getDeclaredField(names[i]); + break; + } catch (NoSuchFieldException nsfe) { + } + } + if (field == null) return null; + se[i] = new SimpleEntry<>(field.getName(), field.getType()); + } catch (Exception e) { + if (logger.isLoggable(Level.FINE)) logger.log(Level.FINE, clazz + " getConstructorField error", e); + return null; + } + } + return se; + } + + public static SimpleEntry[] getConstructorField(Class clazz, int paramcount, Parameter[] params) { + SimpleEntry[] se = new SimpleEntry[params.length]; + for (int i = 0; i < params.length; i++) { //鏌ヨ鍙傛暟鍚嶅搴旂殑Field + try { + Field field = clazz.getDeclaredField(params[i].getName()); + se[i] = new SimpleEntry<>(field.getName(), field.getType()); + } catch (Exception e) { + return null; + } + } + return se; + } + + static class TypeArrayIntFunction implements IntFunction { + + private final Class type; + + public TypeArrayIntFunction(Class type) { + this.type = type; + } + + @Override + public T[] apply(int value) { + return (T[]) Array.newInstance(type, value); + } + + } + + public static IntFunction createArrayFunction(final Class clazz) { + final String interName = clazz.getName().replace('.', '/'); + final String interDesc = Type.getDescriptor(clazz); + final ClassLoader loader = clazz.getClassLoader(); + final String newDynName = "org/redkaledyn/creator/_DynArrayFunction__" + clazz.getName().replace('.', '_').replace('$', '_'); + try { + Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); + return (IntFunction) (clz == null ? loader.loadClass(newDynName.replace('/', '.')) : clz).getDeclaredConstructor().newInstance(); + } catch (Throwable ex) { + } + + //------------------------------------------------------------- + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); + MethodVisitor mv; + cw.visit(V11, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, "Ljava/lang/Object;Ljava/util/function/IntFunction<[" + interDesc + ">;", "java/lang/Object", new String[]{"java/util/function/IntFunction"}); + + {//IntFunction鑷韩鐨勬瀯閫犳柟娉 + mv = cw.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(); + } + {//apply 鏂规硶 + mv = cw.visitMethod(ACC_PUBLIC, "apply", "(I)[" + interDesc, null, null); + mv.visitVarInsn(ILOAD, 1); + mv.visitTypeInsn(ANEWARRAY, interName); + mv.visitInsn(ARETURN); + mv.visitMaxs(1, 2); + mv.visitEnd(); + } + { //铏氭嫙 apply 鏂规硶 + mv = cw.visitMethod(ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, "apply", "(I)Ljava/lang/Object;", null, null); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ILOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "apply", "(I)[" + interDesc, false); + mv.visitInsn(ARETURN); + mv.visitMaxs(2, 2); + mv.visitEnd(); + } + cw.visitEnd(); + final byte[] bytes = cw.toByteArray(); + try { + Class resultClazz = new ClassLoader(loader) { + public final Class loadClass(String name, byte[] b) { + return defineClass(name, b, 0, b.length); + } + }.loadClass(newDynName.replace('/', '.'), bytes); + RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, resultClazz); + RedkaleClassLoader.putReflectionDeclaredConstructors(resultClazz, newDynName.replace('/', '.')); + return (IntFunction) resultClazz.getDeclaredConstructor().newInstance(); + } catch (Exception ex) { + ex.printStackTrace(); //涓鑸笉浼氬彂鐢 + return t -> (T[]) Array.newInstance(clazz, t); + //throw new RuntimeException(ex); + } + } + } + + /** + * 鍒涘缓瀵硅薄 + * + * @param params 鏋勯犲嚱鏁扮殑鍙傛暟 + * + * @return 鏋勫缓鐨勫璞 + */ + public T create(Object... params); + + /** + * 鍒涘缓鎸囧畾绫诲瀷瀵硅薄鏁扮粍鐨処ntFunction + * + * @param 娉涘瀷 + * @param type 绫诲瀷 + * + * @return IntFunction + */ + public static IntFunction arrayFunction(final Class type) { + return CreatorInner.arrayCacheMap.computeIfAbsent(type, t -> CreatorInner.createArrayFunction(t)); + } + + /** + * 鍒涘缓鎸囧畾澶у皬鐨勫璞℃暟缁 + * + * @param 娉涘瀷 + * @param type 绫诲瀷 + * @param size 鏁扮粍澶у皬 + * + * @return 鏁扮粍 + */ + public static T[] newArray(final Class type, final int size) { + if (type == int.class) return (T[]) (Object) new int[size]; + if (type == byte.class) return (T[]) (Object) new byte[size]; + if (type == long.class) return (T[]) (Object) new long[size]; + if (type == String.class) return (T[]) new String[size]; + if (type == Object.class) return (T[]) new Object[size]; + if (type == boolean.class) return (T[]) (Object) new boolean[size]; + if (type == short.class) return (T[]) (Object) new short[size]; + if (type == char.class) return (T[]) (Object) new char[size]; + if (type == float.class) return (T[]) (Object) new float[size]; + if (type == double.class) return (T[]) (Object) new double[size]; + //return (T[]) Array.newInstance(type, size); + return arrayFunction(type).apply(size); + } + + /** + * 鏍规嵁Supplier鐢熶骇Creator + * + * @param 鏋勫缓绫荤殑鏁版嵁绫诲瀷 + * @param supplier Supplier + * + * @return Creator瀵硅薄 + */ + public static Creator create(final Supplier supplier) { + Objects.requireNonNull(supplier); + return (Object... params) -> supplier.get(); + } + + /** + * 鏍规嵁Function鐢熶骇Creator + * + * @param 鏋勫缓绫荤殑鏁版嵁绫诲瀷 + * @param func Function + * + * @return Creator瀵硅薄 + */ + public static Creator create(final Function func) { + Objects.requireNonNull(func); + return (Object... params) -> func.apply(params); + } + + /** + * 鏍规嵁鎸囧畾鐨刢lass閲囩敤ASM鎶鏈敓浜reator銆 + * + * @param 鏋勫缓绫荤殑鏁版嵁绫诲瀷 + * @param clazz 鏋勫缓绫 + * + * @return Creator瀵硅薄 + */ + @SuppressWarnings("unchecked") + public static Creator create(Class clazz) { + if (List.class.isAssignableFrom(clazz) && (clazz.isAssignableFrom(ArrayList.class) || clazz.getName().startsWith("java.util.Collections") || clazz.getName().startsWith("java.util.ImmutableCollections") || clazz.getName().startsWith("java.util.Arrays"))) { + clazz = (Class) ArrayList.class; + } else if (Map.class.isAssignableFrom(clazz) && (clazz.isAssignableFrom(HashMap.class) || clazz.getName().startsWith("java.util.Collections") || clazz.getName().startsWith("java.util.ImmutableCollections"))) { + clazz = (Class) HashMap.class; + } else if (Set.class.isAssignableFrom(clazz) && (clazz.isAssignableFrom(HashSet.class) || clazz.getName().startsWith("java.util.Collections") || clazz.getName().startsWith("java.util.ImmutableCollections"))) { + clazz = (Class) HashSet.class; + } else if (Map.class.isAssignableFrom(clazz) && clazz.isAssignableFrom(ConcurrentHashMap.class)) { + clazz = (Class) ConcurrentHashMap.class; + } else if (Deque.class.isAssignableFrom(clazz) && (clazz.isAssignableFrom(ArrayDeque.class) || clazz.getName().startsWith("java.util.Collections") || clazz.getName().startsWith("java.util.ImmutableCollections"))) { + clazz = (Class) ArrayDeque.class; + } else if (Collection.class.isAssignableFrom(clazz) && clazz.isAssignableFrom(ArrayList.class)) { + clazz = (Class) ArrayList.class; + } else if (Map.Entry.class.isAssignableFrom(clazz) && (Modifier.isInterface(clazz.getModifiers()) || Modifier.isAbstract(clazz.getModifiers()) || !Modifier.isPublic(clazz.getModifiers()))) { + clazz = (Class) AbstractMap.SimpleEntry.class; + } else if (Iterable.class == clazz) { + clazz = (Class) ArrayList.class; + } + Creator creator = CreatorInner.creatorCacheMap.get(clazz); + if (creator != null) return creator; + if (clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers())) { + throw new RuntimeException("[" + clazz + "] is a interface or abstract class, cannot create it's Creator."); + } + for (final Method method : clazz.getDeclaredMethods()) { //鏌ユ壘绫讳腑鏄惁瀛樺湪鎻愪緵鍒涘缓Creator瀹炰緥鐨勯潤鎬佹柟娉 + if (!Modifier.isStatic(method.getModifiers())) continue; + if (method.getParameterTypes().length != 0) continue; + if (method.getReturnType() != Creator.class) continue; + try { + method.setAccessible(true); + Creator c = (Creator) method.invoke(null); + if (c != null) { + RedkaleClassLoader.putReflectionDeclaredMethods(clazz.getName()); + RedkaleClassLoader.putReflectionMethod(clazz.getName(), method); + return c; + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + final String supDynName = Creator.class.getName().replace('.', '/'); + final String interName = clazz.getName().replace('.', '/'); + final String interDesc = Type.getDescriptor(clazz); + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + if (String.class.getClassLoader() != clazz.getClassLoader()) { + loader = clazz.getClassLoader(); + } + final String newDynName = "org/redkaledyn/creator/_Dyn" + Creator.class.getSimpleName() + "__" + clazz.getName().replace('.', '_').replace('$', '_'); + try { + Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); + return (Creator) (clz == null ? loader.loadClass(newDynName.replace('/', '.')) : clz).getDeclaredConstructor().newInstance(); + } catch (Throwable ex) { + } + + Constructor constructor0 = null; + SimpleEntry[] constructorParameters0 = null; //鏋勯犲嚱鏁扮殑鍙傛暟 + + if (constructor0 == null) { // 1銆佹煡鎵緋ublic鐨勭┖鍙傛暟鏋勯犲嚱鏁 + for (Constructor c : clazz.getConstructors()) { + if (c.getParameterCount() == 0) { + constructor0 = c; + constructorParameters0 = new SimpleEntry[0]; + break; + } + } + } + if (constructor0 == null) { // 2銆佹煡鎵緋ublic甯onstructorParameters娉ㄨВ鐨勬瀯閫犲嚱鏁 + for (Constructor c : clazz.getConstructors()) { + ConstructorParameters cp = (ConstructorParameters) c.getAnnotation(ConstructorParameters.class); + if (cp == null) continue; + SimpleEntry[] fields = CreatorInner.getConstructorField(clazz, c.getParameterCount(), cp.value()); + if (fields != null) { + constructor0 = c; + constructorParameters0 = fields; + break; + } + } + } + if (constructor0 == null) { // 3銆佹煡鎵緋ublic涓斾笉甯onstructorParameters娉ㄨВ鐨勬瀯閫犲嚱鏁 + List cs = new ArrayList<>(); + for (Constructor c : clazz.getConstructors()) { + if (c.getAnnotation(ConstructorParameters.class) != null) continue; + if (c.getParameterCount() < 1) continue; + cs.add(c); + } + //浼樺厛鍙傛暟鏈澶氱殑鏋勯犲嚱鏁 + cs.sort((o1, o2) -> o2.getParameterCount() - o1.getParameterCount()); + for (Constructor c : cs) { + SimpleEntry[] fields = CreatorInner.getConstructorField(clazz, c.getParameterCount(), Type.getConstructorDescriptor(c)); + if (fields != null) { + constructor0 = c; + constructorParameters0 = fields; + break; + } + } + } + if (constructor0 == null) { // 4銆佹煡鎵鹃潪private甯onstructorParameters鐨勬瀯閫犲嚱鏁 + for (Constructor c : clazz.getDeclaredConstructors()) { + if (Modifier.isPublic(c.getModifiers()) || Modifier.isPrivate(c.getModifiers())) continue; + ConstructorParameters cp = (ConstructorParameters) c.getAnnotation(ConstructorParameters.class); + if (cp == null) continue; + SimpleEntry[] fields = CreatorInner.getConstructorField(clazz, c.getParameterCount(), cp.value()); + if (fields != null) { + constructor0 = c; + constructorParameters0 = fields; + break; + } + } + } + if (constructor0 == null) { // 5銆佹煡鎵鹃潪private涓斾笉甯onstructorParameters鐨勬瀯閫犲嚱鏁 + List cs = new ArrayList<>(); + for (Constructor c : clazz.getDeclaredConstructors()) { + if (Modifier.isPublic(c.getModifiers()) || Modifier.isPrivate(c.getModifiers())) continue; + if (c.getAnnotation(ConstructorParameters.class) != null) continue; + if (c.getParameterCount() < 1) continue; + cs.add(c); + } + //浼樺厛鍙傛暟鏈澶氱殑鏋勯犲嚱鏁 + cs.sort((o1, o2) -> o2.getParameterCount() - o1.getParameterCount()); + for (Constructor c : cs) { + SimpleEntry[] fields = CreatorInner.getConstructorField(clazz, c.getParameterCount(), Type.getConstructorDescriptor(c)); + if (fields != null) { + constructor0 = c; + constructorParameters0 = fields; + break; + } + } + } + final Constructor constructor = constructor0; + final SimpleEntry[] constructorParameters = constructorParameters0; + if (constructor == null || constructorParameters == null) { + throw new RuntimeException("[" + clazz + "] have no public or ConstructorParameters-Annotation constructor."); + } + //------------------------------------------------------------- + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); + FieldVisitor fv; + MethodVisitor mv; + AnnotationVisitor av0; + cw.visit(V11, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, "Ljava/lang/Object;L" + supDynName + "<" + interDesc + ">;", "java/lang/Object", new String[]{supDynName}); + + {//Creator鑷韩鐨勬瀯閫犳柟娉 + mv = cw.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(); + } + {//create 鏂规硶 + mv = cw.visitMethod(ACC_PUBLIC + ACC_VARARGS, "create", "([Ljava/lang/Object;)L" + interName + ";", null, null); + if (constructorParameters.length > 0) { + av0 = mv.visitAnnotation(Type.getDescriptor(ConstructorParameters.class), true); + AnnotationVisitor av1 = av0.visitArray("value"); + for (SimpleEntry n : constructorParameters) { + av1.visit(null, n.getKey()); + } + av1.visitEnd(); + av0.visitEnd(); + } + final int[] iconsts = {ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4, ICONST_5}; + { //鏈塒rimitive鏁版嵁绫诲瀷涓斿间负null鐨勫弬鏁伴渶瑕佽祴榛樿鍊 + for (int i = 0; i < constructorParameters.length; i++) { + final Class pt = constructorParameters[i].getValue(); + if (!pt.isPrimitive()) continue; + mv.visitVarInsn(ALOAD, 1); + if (i < 6) { + mv.visitInsn(iconsts[i]); + } else if (i <= Byte.MAX_VALUE) { + mv.visitIntInsn(BIPUSH, i); + } else if (i <= Short.MAX_VALUE) { + mv.visitIntInsn(SIPUSH, i); + } else { + mv.visitLdcInsn(i); + } + mv.visitInsn(AALOAD); + Label lab = new Label(); + mv.visitJumpInsn(IFNONNULL, lab); + mv.visitVarInsn(ALOAD, 1); + if (i < 6) { + mv.visitInsn(iconsts[i]); + } else if (i <= Byte.MAX_VALUE) { + mv.visitIntInsn(BIPUSH, i); + } else if (i <= Short.MAX_VALUE) { + mv.visitIntInsn(SIPUSH, i); + } else { + mv.visitLdcInsn(i); + } + if (pt == int.class) { + mv.visitInsn(ICONST_0); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false); + } else if (pt == long.class) { + mv.visitInsn(LCONST_0); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", false); + } else if (pt == boolean.class) { + mv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "FALSE", "Ljava/lang/Boolean;"); + } else if (pt == short.class) { + mv.visitInsn(ICONST_0); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;", false); + } else if (pt == float.class) { + mv.visitInsn(FCONST_0); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", false); + } else if (pt == byte.class) { + mv.visitInsn(ICONST_0); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;", false); + } else if (pt == double.class) { + mv.visitInsn(DCONST_0); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false); + } else if (pt == char.class) { + mv.visitInsn(ICONST_0); + mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;", false); + } + mv.visitInsn(AASTORE); + mv.visitLabel(lab); + } + } + mv.visitTypeInsn(NEW, interName); + mv.visitInsn(DUP); + //--------------------------------------- + { + for (int i = 0; i < constructorParameters.length; i++) { + mv.visitVarInsn(ALOAD, 1); + if (i < 6) { + mv.visitInsn(iconsts[i]); + } else if (i <= Byte.MAX_VALUE) { + mv.visitIntInsn(BIPUSH, i); + } else if (i <= Short.MAX_VALUE) { + mv.visitIntInsn(SIPUSH, i); + } else { + mv.visitLdcInsn(i); + } + mv.visitInsn(AALOAD); + final Class ct = constructorParameters[i].getValue(); + if (ct.isPrimitive()) { + final Class bigct = Array.get(Array.newInstance(ct, 1), 0).getClass(); + mv.visitTypeInsn(CHECKCAST, bigct.getName().replace('.', '/')); + try { + Method pm = bigct.getMethod(ct.getSimpleName() + "Value"); + mv.visitMethodInsn(INVOKEVIRTUAL, bigct.getName().replace('.', '/'), pm.getName(), Type.getMethodDescriptor(pm), false); + } catch (Exception ex) { + throw new RuntimeException(ex); //涓嶅彲鑳戒細鍙戠敓 + } + } else { + mv.visitTypeInsn(CHECKCAST, ct.getName().replace('.', '/')); + } + } + } + //--------------------------------------- + mv.visitMethodInsn(INVOKESPECIAL, interName, "", Type.getConstructorDescriptor(constructor), false); + mv.visitInsn(ARETURN); + mv.visitMaxs((constructorParameters.length > 0 ? (constructorParameters.length + 3) : 2), 2); + mv.visitEnd(); + } + { //铏氭嫙 create 鏂规硶 + mv = cw.visitMethod(ACC_PUBLIC + ACC_BRIDGE + ACC_VARARGS + ACC_SYNTHETIC, "create", "([Ljava/lang/Object;)Ljava/lang/Object;", null, null); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "create", "([Ljava/lang/Object;)" + interDesc, false); + mv.visitInsn(ARETURN); + mv.visitMaxs(2, 2); + mv.visitEnd(); + } + cw.visitEnd(); + final byte[] bytes = cw.toByteArray(); + final boolean ispub = Modifier.isPublic(constructor.getModifiers()); + Class resultClazz = null; + if (loader instanceof URLClassLoader && !ispub) { + try { + final URLClassLoader urlLoader = (URLClassLoader) loader; + final URL url = new URL("memclass", "localhost", -1, "/" + newDynName.replace('/', '.') + "/", new URLStreamHandler() { + @Override + protected URLConnection openConnection(URL u) throws IOException { + return new URLConnection(u) { + @Override + public void connect() throws IOException { + } + + @Override + public InputStream getInputStream() throws IOException { + return new ByteArrayInputStream(bytes); + } + }; + } + }); + Method addURLMethod = URLClassLoader.class.getDeclaredMethod("addURL", URL.class); + addURLMethod.setAccessible(true); + addURLMethod.invoke(urlLoader, url); + resultClazz = urlLoader.loadClass(newDynName.replace('/', '.')); + } catch (Throwable t) { //寮傚父鏃犻渶鐞嗕細锛 浣跨敤涓嬩竴绉峫oader鏂瑰紡 + t.printStackTrace(); + } + } + if (!ispub && resultClazz == null) throw new RuntimeException("[" + clazz + "] have no public or ConstructorParameters-Annotation constructor."); + try { + if (resultClazz == null) resultClazz = new ClassLoader(loader) { + public final Class loadClass(String name, byte[] b) { + return defineClass(name, b, 0, b.length); + } + }.loadClass(newDynName.replace('/', '.'), bytes); + RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, resultClazz); + RedkaleClassLoader.putReflectionDeclaredConstructors(resultClazz, newDynName.replace('/', '.')); + return (Creator) resultClazz.getDeclaredConstructor().newInstance(); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } +} diff --git a/src/main/java/org/redkale/util/DLong.java b/src/main/java/org/redkale/util/DLong.java index fb79d9b9f..7481f6895 100644 --- a/src/main/java/org/redkale/util/DLong.java +++ b/src/main/java/org/redkale/util/DLong.java @@ -1,129 +1,129 @@ -/* - * 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.util; - -import java.nio.*; -import java.util.*; - -/** - * 16bytes鏁版嵁缁撴瀯 - * 娉ㄦ剰锛 涓轰簡鎻愰珮鎬ц兘锛 DLong涓殑bytes鏄洿鎺ヨ繑鍥烇紝 涓嶅緱瀵筨ytes鐨勫唴瀹硅繘琛屼慨鏀广 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public final class DLong extends Number implements Comparable { - - public static final DLong ZERO = new DLong(new byte[16]); - - protected final byte[] value; - - protected DLong(long v1, long v2) { //鏆傛椂涓嶇敤 - this.value = new byte[]{(byte) (v1 >> 56), (byte) (v1 >> 48), (byte) (v1 >> 40), (byte) (v1 >> 32), - (byte) (v1 >> 24), (byte) (v1 >> 16), (byte) (v1 >> 8), (byte) v1, (byte) (v2 >> 56), (byte) (v2 >> 48), (byte) (v2 >> 40), (byte) (v2 >> 32), - (byte) (v2 >> 24), (byte) (v2 >> 16), (byte) (v2 >> 8), (byte) v2}; - } - - protected DLong(byte[] bytes) { - if (bytes == null || bytes.length != 16) throw new NumberFormatException("Not 16 length bytes"); - this.value = bytes; - } - - public byte[] getBytes() { - return Arrays.copyOf(value, value.length); - } - - public byte[] directBytes() { - return value; - } - - public static DLong create(byte[] bytes) { - return new DLong(bytes); - } - - public static DLong read(ByteBuffer buffer) { - byte[] bs = new byte[16]; - buffer.get(bs); - return new DLong(bs); - } - - public static ByteBuffer write(ByteBuffer buffer, DLong dlong) { - buffer.put(dlong.value); - return buffer; - } - - public static ByteArray write(ByteArray array, DLong dlong) { - array.put(dlong.value); - return array; - } - - public static ByteArray write(ByteArray array, int offset, DLong dlong) { - array.put(offset, dlong.value); - return array; - } - - public boolean equals(byte[] bytes) { - return Arrays.equals(this.value, bytes); - } - - @Override - public boolean equals(Object obj) { - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; - final DLong other = (DLong) obj; - return Arrays.equals(this.value, other.value); - } - - @Override - public int hashCode() { - return Arrays.hashCode(value); - } - - @Override - public String toString() { - if (this == ZERO) return "0"; - return new String(Utility.binToHex(value)); - } - - @Override - public int intValue() { - return ((value[12] & 0xff) << 24) | ((value[13] & 0xff) << 16) | ((value[14] & 0xff) << 8) | (value[15] & 0xff); - } - - @Override - public long longValue() { - return ((((long) value[8] & 0xff) << 56) - | (((long) value[9] & 0xff) << 48) - | (((long) value[10] & 0xff) << 40) - | (((long) value[11] & 0xff) << 32) - | (((long) value[12] & 0xff) << 24) - | (((long) value[13] & 0xff) << 16) - | (((long) value[14] & 0xff) << 8) - | (((long) value[15] & 0xff))); - } - - @Override - public float floatValue() { - return (float) longValue(); - } - - @Override - public double doubleValue() { - return (double) longValue(); - } - - @Override - public int compareTo(DLong o) { - if (o == null) return 1; - for (int i = 0; i < value.length; i++) { - if (this.value[i] != o.value[i]) return this.value[i] - o.value[i]; - } - return 0; - } - -} +/* + * 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.util; + +import java.nio.*; +import java.util.*; + +/** + * 16bytes鏁版嵁缁撴瀯 + * 娉ㄦ剰锛 涓轰簡鎻愰珮鎬ц兘锛 DLong涓殑bytes鏄洿鎺ヨ繑鍥烇紝 涓嶅緱瀵筨ytes鐨勫唴瀹硅繘琛屼慨鏀广 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public final class DLong extends Number implements Comparable { + + public static final DLong ZERO = new DLong(new byte[16]); + + protected final byte[] value; + + protected DLong(long v1, long v2) { //鏆傛椂涓嶇敤 + this.value = new byte[]{(byte) (v1 >> 56), (byte) (v1 >> 48), (byte) (v1 >> 40), (byte) (v1 >> 32), + (byte) (v1 >> 24), (byte) (v1 >> 16), (byte) (v1 >> 8), (byte) v1, (byte) (v2 >> 56), (byte) (v2 >> 48), (byte) (v2 >> 40), (byte) (v2 >> 32), + (byte) (v2 >> 24), (byte) (v2 >> 16), (byte) (v2 >> 8), (byte) v2}; + } + + protected DLong(byte[] bytes) { + if (bytes == null || bytes.length != 16) throw new NumberFormatException("Not 16 length bytes"); + this.value = bytes; + } + + public byte[] getBytes() { + return Arrays.copyOf(value, value.length); + } + + public byte[] directBytes() { + return value; + } + + public static DLong create(byte[] bytes) { + return new DLong(bytes); + } + + public static DLong read(ByteBuffer buffer) { + byte[] bs = new byte[16]; + buffer.get(bs); + return new DLong(bs); + } + + public static ByteBuffer write(ByteBuffer buffer, DLong dlong) { + buffer.put(dlong.value); + return buffer; + } + + public static ByteArray write(ByteArray array, DLong dlong) { + array.put(dlong.value); + return array; + } + + public static ByteArray write(ByteArray array, int offset, DLong dlong) { + array.put(offset, dlong.value); + return array; + } + + public boolean equals(byte[] bytes) { + return Arrays.equals(this.value, bytes); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + final DLong other = (DLong) obj; + return Arrays.equals(this.value, other.value); + } + + @Override + public int hashCode() { + return Arrays.hashCode(value); + } + + @Override + public String toString() { + if (this == ZERO) return "0"; + return new String(Utility.binToHex(value)); + } + + @Override + public int intValue() { + return ((value[12] & 0xff) << 24) | ((value[13] & 0xff) << 16) | ((value[14] & 0xff) << 8) | (value[15] & 0xff); + } + + @Override + public long longValue() { + return ((((long) value[8] & 0xff) << 56) + | (((long) value[9] & 0xff) << 48) + | (((long) value[10] & 0xff) << 40) + | (((long) value[11] & 0xff) << 32) + | (((long) value[12] & 0xff) << 24) + | (((long) value[13] & 0xff) << 16) + | (((long) value[14] & 0xff) << 8) + | (((long) value[15] & 0xff))); + } + + @Override + public float floatValue() { + return (float) longValue(); + } + + @Override + public double doubleValue() { + return (double) longValue(); + } + + @Override + public int compareTo(DLong o) { + if (o == null) return 1; + for (int i = 0; i < value.length; i++) { + if (this.value[i] != o.value[i]) return this.value[i] - o.value[i]; + } + return 0; + } + +} diff --git a/src/main/java/org/redkale/util/LogExcludeLevel.java b/src/main/java/org/redkale/util/LogExcludeLevel.java index 23fe8c107..25c022932 100644 --- a/src/main/java/org/redkale/util/LogExcludeLevel.java +++ b/src/main/java/org/redkale/util/LogExcludeLevel.java @@ -1,46 +1,46 @@ -/* - * 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.util; - -import java.lang.annotation.*; -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * 绛変簬level鏃ュ織绾у埆涓斿寘鍚玨eys瀛楃涓茬殑鏃ュ織鎵嶄細琚帓闄
- * - *

- * @LogExcludeLevel(levels = {"FINEST"}, keys = {"SET username ="})
- * public class UserRecord {
- *      public int userid;
- *      public String username = "";
- * }
- *
- * 杩欐牱褰撹皟鐢―ataSource瀵筓serRecord瀵硅薄杩涜鎿嶄綔鏃讹紝鎷兼帴鐨凷QL璇彞鍚"SET username ="瀛楁牱鐨勯兘浼氬湪FINEST鏃ュ織绾у埆杩囨护鎺
- * 
- *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@Documented -@Target({TYPE}) -@Retention(RUNTIME) -@Repeatable(LogExcludeLevel.LogExcludeLevels.class) -public @interface LogExcludeLevel { - - String[] levels(); - - String[] keys(); - - @Documented - @Target({TYPE}) - @Retention(RUNTIME) - @interface LogExcludeLevels { - - LogExcludeLevel[] value(); - } -} +/* + * 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.util; + +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * 绛変簬level鏃ュ織绾у埆涓斿寘鍚玨eys瀛楃涓茬殑鏃ュ織鎵嶄細琚帓闄
+ * + *

+ * @LogExcludeLevel(levels = {"FINEST"}, keys = {"SET username ="})
+ * public class UserRecord {
+ *      public int userid;
+ *      public String username = "";
+ * }
+ *
+ * 杩欐牱褰撹皟鐢―ataSource瀵筓serRecord瀵硅薄杩涜鎿嶄綔鏃讹紝鎷兼帴鐨凷QL璇彞鍚"SET username ="瀛楁牱鐨勯兘浼氬湪FINEST鏃ュ織绾у埆杩囨护鎺
+ * 
+ *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@Documented +@Target({TYPE}) +@Retention(RUNTIME) +@Repeatable(LogExcludeLevel.LogExcludeLevels.class) +public @interface LogExcludeLevel { + + String[] levels(); + + String[] keys(); + + @Documented + @Target({TYPE}) + @Retention(RUNTIME) + @interface LogExcludeLevels { + + LogExcludeLevel[] value(); + } +} diff --git a/src/main/java/org/redkale/util/LogLevel.java b/src/main/java/org/redkale/util/LogLevel.java index 7eebba258..050e073af 100644 --- a/src/main/java/org/redkale/util/LogLevel.java +++ b/src/main/java/org/redkale/util/LogLevel.java @@ -1,26 +1,26 @@ -/* - * 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.util; - -import java.lang.annotation.*; -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * 琚爣璁扮殑鏃ュ織绾у埆浠ヤ笂鐨勬墠浼氳璁板綍 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@Documented -@Target({TYPE}) -@Retention(RUNTIME) -public @interface LogLevel { - - String value(); -} +/* + * 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.util; + +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * 琚爣璁扮殑鏃ュ織绾у埆浠ヤ笂鐨勬墠浼氳璁板綍 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@Documented +@Target({TYPE}) +@Retention(RUNTIME) +public @interface LogLevel { + + String value(); +} diff --git a/src/main/java/org/redkale/util/ObjectPool.java b/src/main/java/org/redkale/util/ObjectPool.java index 5286db3d3..c40e13bcf 100644 --- a/src/main/java/org/redkale/util/ObjectPool.java +++ b/src/main/java/org/redkale/util/ObjectPool.java @@ -1,250 +1,250 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ -package org.redkale.util; - -import java.util.*; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.atomic.*; -import java.util.function.*; -import java.util.logging.*; - -/** - * 瀵硅薄姹 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param 瀵硅薄姹犲厓绱犵殑鏁版嵁绫诲瀷 - */ -public class ObjectPool implements Supplier, Consumer { - - protected static final Logger logger = Logger.getLogger(ObjectPool.class.getSimpleName()); - - protected final boolean debug; - - protected Creator creator; - - protected int max; - - protected final Consumer prepare; - - protected final Predicate recycler; - - protected final LongAdder creatCounter; - - protected final LongAdder cycleCounter; - - protected final Queue queue; - - protected final boolean unsafeDequeable; - - protected final ObjectPool parent; - - protected Thread unsafeThread; - - protected ObjectPool(ObjectPool parent, LongAdder creatCounter, LongAdder cycleCounter, int max, Creator creator, Consumer prepare, Predicate recycler, Queue queue) { - this.parent = parent; - this.creatCounter = creatCounter; - this.cycleCounter = cycleCounter; - this.creator = creator; - this.prepare = prepare; - this.recycler = recycler; - this.max = max; - this.debug = logger.isLoggable(Level.FINEST); - this.queue = queue; - this.unsafeDequeable = queue instanceof ArrayDeque; - } - - //闈炵嚎绋嬪畨鍏ㄧ増 - public static ObjectPool createUnsafePool(Class clazz, Consumer prepare, Predicate recycler) { - return createUnsafePool(2, clazz, prepare, recycler); - } - - //闈炵嚎绋嬪畨鍏ㄧ増 - public static ObjectPool createUnsafePool(int max, Class clazz, Consumer prepare, Predicate recycler) { - return createUnsafePool(max, Creator.create(clazz), prepare, recycler); - } - - //闈炵嚎绋嬪畨鍏ㄧ増 - public static ObjectPool createUnsafePool(Creator creator, Consumer prepare, Predicate recycler) { - return createUnsafePool(2, creator, prepare, recycler); - } - - //闈炵嚎绋嬪畨鍏ㄧ増 - public static ObjectPool createUnsafePool(int max, Creator creator, Consumer prepare, Predicate recycler) { - return createUnsafePool(null, null, max, creator, prepare, recycler); - } - - //闈炵嚎绋嬪畨鍏ㄧ増 - public static ObjectPool createUnsafePool(int max, Supplier creator, Consumer prepare, Predicate recycler) { - return createUnsafePool(null, null, max, creator, prepare, recycler); - } - - //闈炵嚎绋嬪畨鍏ㄧ増 - public static ObjectPool createUnsafePool(LongAdder creatCounter, LongAdder cycleCounter, int max, Supplier creator, Consumer prepare, Predicate recycler) { - return createUnsafePool(creatCounter, cycleCounter, max, c -> creator.get(), prepare, recycler); - } - - //闈炵嚎绋嬪畨鍏ㄧ増 - public static ObjectPool createUnsafePool(LongAdder creatCounter, LongAdder cycleCounter, int max, Creator creator, Consumer prepare, Predicate recycler) { - return createUnsafePool(null, creatCounter, cycleCounter, max, creator, prepare, recycler); - } - - //闈炵嚎绋嬪畨鍏ㄧ増 - public static ObjectPool createUnsafePool(ObjectPool parent, Class clazz, Consumer prepare, Predicate recycler) { - return createUnsafePool(parent, 2, clazz, prepare, recycler); - } - - //闈炵嚎绋嬪畨鍏ㄧ増 - public static ObjectPool createUnsafePool(ObjectPool parent, int max, Class clazz, Consumer prepare, Predicate recycler) { - return createUnsafePool(parent, max, Creator.create(clazz), prepare, recycler); - } - - //闈炵嚎绋嬪畨鍏ㄧ増 - public static ObjectPool createUnsafePool(ObjectPool parent, Creator creator, Consumer prepare, Predicate recycler) { - return createUnsafePool(parent, 2, creator, prepare, recycler); - } - - //闈炵嚎绋嬪畨鍏ㄧ増 - public static ObjectPool createUnsafePool(ObjectPool parent, int max, Creator creator, Consumer prepare, Predicate recycler) { - return createUnsafePool(parent, null, null, max, creator, prepare, recycler); - } - - //闈炵嚎绋嬪畨鍏ㄧ増 - public static ObjectPool createUnsafePool(ObjectPool parent, int max, Supplier creator, Consumer prepare, Predicate recycler) { - return createUnsafePool(parent, null, null, max, creator, prepare, recycler); - } - - //闈炵嚎绋嬪畨鍏ㄧ増 - public static ObjectPool createUnsafePool(ObjectPool parent, LongAdder creatCounter, LongAdder cycleCounter, int max, Supplier creator, Consumer prepare, Predicate recycler) { - return createUnsafePool(parent, creatCounter, cycleCounter, max, c -> creator.get(), prepare, recycler); - } - - //闈炵嚎绋嬪畨鍏ㄧ増 - public static ObjectPool createUnsafePool(ObjectPool parent, LongAdder creatCounter, LongAdder cycleCounter, int max, Creator creator, Consumer prepare, Predicate recycler) { - return new ObjectPool(parent, creatCounter, cycleCounter, Math.max(Utility.cpus(), max), - creator, prepare, recycler, new ArrayDeque<>(Math.max(Utility.cpus(), max))); - } - - //绾跨▼瀹夊叏鐗 - public static ObjectPool createSafePool(Class clazz, Consumer prepare, Predicate recycler) { - return createSafePool(2, clazz, prepare, recycler); - } - - //绾跨▼瀹夊叏鐗 - public static ObjectPool createSafePool(int max, Class clazz, Consumer prepare, Predicate recycler) { - return createSafePool(max, Creator.create(clazz), prepare, recycler); - } - - //绾跨▼瀹夊叏鐗 - public static ObjectPool createSafePool(Creator creator, Consumer prepare, Predicate recycler) { - return createSafePool(2, creator, prepare, recycler); - } - - //绾跨▼瀹夊叏鐗 - public static ObjectPool createSafePool(int max, Creator creator, Consumer prepare, Predicate recycler) { - return createSafePool(null, null, max, creator, prepare, recycler); - } - - //绾跨▼瀹夊叏鐗 - public static ObjectPool createSafePool(int max, Supplier creator, Consumer prepare, Predicate recycler) { - return createSafePool(null, null, max, creator, prepare, recycler); - } - - //绾跨▼瀹夊叏鐗 - public static ObjectPool createSafePool(LongAdder creatCounter, LongAdder cycleCounter, int max, Supplier creator, Consumer prepare, Predicate recycler) { - return createSafePool(creatCounter, cycleCounter, max, c -> creator.get(), prepare, recycler); - } - - //绾跨▼瀹夊叏鐗 - public static ObjectPool createSafePool(LongAdder creatCounter, LongAdder cycleCounter, int max, Creator creator, Consumer prepare, Predicate recycler) { - return new ObjectPool(null, creatCounter, cycleCounter, Math.max(Utility.cpus(), max), - creator, prepare, recycler, new LinkedBlockingQueue<>(Math.max(Utility.cpus(), max))); - } - - public void setCreator(Creator creator) { - this.creator = creator; - } - - public Creator getCreator() { - return this.creator; - } - - public int getMax() { - return max; - } - - public Consumer getPrepare() { - return prepare; - } - - public Predicate getRecycler() { - return recycler; - } - - public LongAdder getCreatCounter() { - return creatCounter; - } - - public LongAdder getCycleCounter() { - return cycleCounter; - } - - @Override - public T get() { - if (unsafeDequeable) { - if (unsafeThread == null) { - unsafeThread = Thread.currentThread(); - } else if (unsafeThread != Thread.currentThread()) { - throw new IllegalCallerException("unsafeThread is " + unsafeThread + ", but currentThread is " + Thread.currentThread()); - } - } - T result = queue.poll(); - if (result == null) { - if (parent != null) result = parent.queue.poll(); - if (result == null) { - if (creatCounter != null) creatCounter.increment(); - result = this.creator.create(); - } - } - if (prepare != null) prepare.accept(result); - return result; - } - - @Override - public void accept(final T e) { - if (e == null) return; - if (unsafeDequeable) { - if (unsafeThread == null) { - unsafeThread = Thread.currentThread(); - } else if (unsafeThread != Thread.currentThread()) { - throw new IllegalCallerException("unsafeThread is " + unsafeThread + ", but currentThread is " + Thread.currentThread()); - } - } - if (recycler.test(e)) { - if (cycleCounter != null) cycleCounter.increment(); -// if (debug) { -// for (T t : queue) { -// if (t == e) { -// logger.log(Level.WARNING, "[" + Thread.currentThread().getName() + "] repeat offer the same object(" + e + ")", new Exception()); -// return; -// } -// } -// } - boolean rs = unsafeDequeable ? queue.size() < max && queue.offer(e) : queue.offer(e); - if (!rs && parent != null) parent.accept(e); - } - } - - public long getCreatCount() { - return creatCounter == null ? -1 : creatCounter.longValue(); - } - - public long getCycleCount() { - return cycleCounter == null ? -1 : cycleCounter.longValue(); - } - -} +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.util; + +import java.util.*; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.atomic.*; +import java.util.function.*; +import java.util.logging.*; + +/** + * 瀵硅薄姹 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param 瀵硅薄姹犲厓绱犵殑鏁版嵁绫诲瀷 + */ +public class ObjectPool implements Supplier, Consumer { + + protected static final Logger logger = Logger.getLogger(ObjectPool.class.getSimpleName()); + + protected final boolean debug; + + protected Creator creator; + + protected int max; + + protected final Consumer prepare; + + protected final Predicate recycler; + + protected final LongAdder creatCounter; + + protected final LongAdder cycleCounter; + + protected final Queue queue; + + protected final boolean unsafeDequeable; + + protected final ObjectPool parent; + + protected Thread unsafeThread; + + protected ObjectPool(ObjectPool parent, LongAdder creatCounter, LongAdder cycleCounter, int max, Creator creator, Consumer prepare, Predicate recycler, Queue queue) { + this.parent = parent; + this.creatCounter = creatCounter; + this.cycleCounter = cycleCounter; + this.creator = creator; + this.prepare = prepare; + this.recycler = recycler; + this.max = max; + this.debug = logger.isLoggable(Level.FINEST); + this.queue = queue; + this.unsafeDequeable = queue instanceof ArrayDeque; + } + + //闈炵嚎绋嬪畨鍏ㄧ増 + public static ObjectPool createUnsafePool(Class clazz, Consumer prepare, Predicate recycler) { + return createUnsafePool(2, clazz, prepare, recycler); + } + + //闈炵嚎绋嬪畨鍏ㄧ増 + public static ObjectPool createUnsafePool(int max, Class clazz, Consumer prepare, Predicate recycler) { + return createUnsafePool(max, Creator.create(clazz), prepare, recycler); + } + + //闈炵嚎绋嬪畨鍏ㄧ増 + public static ObjectPool createUnsafePool(Creator creator, Consumer prepare, Predicate recycler) { + return createUnsafePool(2, creator, prepare, recycler); + } + + //闈炵嚎绋嬪畨鍏ㄧ増 + public static ObjectPool createUnsafePool(int max, Creator creator, Consumer prepare, Predicate recycler) { + return createUnsafePool(null, null, max, creator, prepare, recycler); + } + + //闈炵嚎绋嬪畨鍏ㄧ増 + public static ObjectPool createUnsafePool(int max, Supplier creator, Consumer prepare, Predicate recycler) { + return createUnsafePool(null, null, max, creator, prepare, recycler); + } + + //闈炵嚎绋嬪畨鍏ㄧ増 + public static ObjectPool createUnsafePool(LongAdder creatCounter, LongAdder cycleCounter, int max, Supplier creator, Consumer prepare, Predicate recycler) { + return createUnsafePool(creatCounter, cycleCounter, max, c -> creator.get(), prepare, recycler); + } + + //闈炵嚎绋嬪畨鍏ㄧ増 + public static ObjectPool createUnsafePool(LongAdder creatCounter, LongAdder cycleCounter, int max, Creator creator, Consumer prepare, Predicate recycler) { + return createUnsafePool(null, creatCounter, cycleCounter, max, creator, prepare, recycler); + } + + //闈炵嚎绋嬪畨鍏ㄧ増 + public static ObjectPool createUnsafePool(ObjectPool parent, Class clazz, Consumer prepare, Predicate recycler) { + return createUnsafePool(parent, 2, clazz, prepare, recycler); + } + + //闈炵嚎绋嬪畨鍏ㄧ増 + public static ObjectPool createUnsafePool(ObjectPool parent, int max, Class clazz, Consumer prepare, Predicate recycler) { + return createUnsafePool(parent, max, Creator.create(clazz), prepare, recycler); + } + + //闈炵嚎绋嬪畨鍏ㄧ増 + public static ObjectPool createUnsafePool(ObjectPool parent, Creator creator, Consumer prepare, Predicate recycler) { + return createUnsafePool(parent, 2, creator, prepare, recycler); + } + + //闈炵嚎绋嬪畨鍏ㄧ増 + public static ObjectPool createUnsafePool(ObjectPool parent, int max, Creator creator, Consumer prepare, Predicate recycler) { + return createUnsafePool(parent, null, null, max, creator, prepare, recycler); + } + + //闈炵嚎绋嬪畨鍏ㄧ増 + public static ObjectPool createUnsafePool(ObjectPool parent, int max, Supplier creator, Consumer prepare, Predicate recycler) { + return createUnsafePool(parent, null, null, max, creator, prepare, recycler); + } + + //闈炵嚎绋嬪畨鍏ㄧ増 + public static ObjectPool createUnsafePool(ObjectPool parent, LongAdder creatCounter, LongAdder cycleCounter, int max, Supplier creator, Consumer prepare, Predicate recycler) { + return createUnsafePool(parent, creatCounter, cycleCounter, max, c -> creator.get(), prepare, recycler); + } + + //闈炵嚎绋嬪畨鍏ㄧ増 + public static ObjectPool createUnsafePool(ObjectPool parent, LongAdder creatCounter, LongAdder cycleCounter, int max, Creator creator, Consumer prepare, Predicate recycler) { + return new ObjectPool(parent, creatCounter, cycleCounter, Math.max(Utility.cpus(), max), + creator, prepare, recycler, new ArrayDeque<>(Math.max(Utility.cpus(), max))); + } + + //绾跨▼瀹夊叏鐗 + public static ObjectPool createSafePool(Class clazz, Consumer prepare, Predicate recycler) { + return createSafePool(2, clazz, prepare, recycler); + } + + //绾跨▼瀹夊叏鐗 + public static ObjectPool createSafePool(int max, Class clazz, Consumer prepare, Predicate recycler) { + return createSafePool(max, Creator.create(clazz), prepare, recycler); + } + + //绾跨▼瀹夊叏鐗 + public static ObjectPool createSafePool(Creator creator, Consumer prepare, Predicate recycler) { + return createSafePool(2, creator, prepare, recycler); + } + + //绾跨▼瀹夊叏鐗 + public static ObjectPool createSafePool(int max, Creator creator, Consumer prepare, Predicate recycler) { + return createSafePool(null, null, max, creator, prepare, recycler); + } + + //绾跨▼瀹夊叏鐗 + public static ObjectPool createSafePool(int max, Supplier creator, Consumer prepare, Predicate recycler) { + return createSafePool(null, null, max, creator, prepare, recycler); + } + + //绾跨▼瀹夊叏鐗 + public static ObjectPool createSafePool(LongAdder creatCounter, LongAdder cycleCounter, int max, Supplier creator, Consumer prepare, Predicate recycler) { + return createSafePool(creatCounter, cycleCounter, max, c -> creator.get(), prepare, recycler); + } + + //绾跨▼瀹夊叏鐗 + public static ObjectPool createSafePool(LongAdder creatCounter, LongAdder cycleCounter, int max, Creator creator, Consumer prepare, Predicate recycler) { + return new ObjectPool(null, creatCounter, cycleCounter, Math.max(Utility.cpus(), max), + creator, prepare, recycler, new LinkedBlockingQueue<>(Math.max(Utility.cpus(), max))); + } + + public void setCreator(Creator creator) { + this.creator = creator; + } + + public Creator getCreator() { + return this.creator; + } + + public int getMax() { + return max; + } + + public Consumer getPrepare() { + return prepare; + } + + public Predicate getRecycler() { + return recycler; + } + + public LongAdder getCreatCounter() { + return creatCounter; + } + + public LongAdder getCycleCounter() { + return cycleCounter; + } + + @Override + public T get() { + if (unsafeDequeable) { + if (unsafeThread == null) { + unsafeThread = Thread.currentThread(); + } else if (unsafeThread != Thread.currentThread()) { + throw new IllegalCallerException("unsafeThread is " + unsafeThread + ", but currentThread is " + Thread.currentThread()); + } + } + T result = queue.poll(); + if (result == null) { + if (parent != null) result = parent.queue.poll(); + if (result == null) { + if (creatCounter != null) creatCounter.increment(); + result = this.creator.create(); + } + } + if (prepare != null) prepare.accept(result); + return result; + } + + @Override + public void accept(final T e) { + if (e == null) return; + if (unsafeDequeable) { + if (unsafeThread == null) { + unsafeThread = Thread.currentThread(); + } else if (unsafeThread != Thread.currentThread()) { + throw new IllegalCallerException("unsafeThread is " + unsafeThread + ", but currentThread is " + Thread.currentThread()); + } + } + if (recycler.test(e)) { + if (cycleCounter != null) cycleCounter.increment(); +// if (debug) { +// for (T t : queue) { +// if (t == e) { +// logger.log(Level.WARNING, "[" + Thread.currentThread().getName() + "] repeat offer the same object(" + e + ")", new Exception()); +// return; +// } +// } +// } + boolean rs = unsafeDequeable ? queue.size() < max && queue.offer(e) : queue.offer(e); + if (!rs && parent != null) parent.accept(e); + } + } + + public long getCreatCount() { + return creatCounter == null ? -1 : creatCounter.longValue(); + } + + public long getCycleCount() { + return cycleCounter == null ? -1 : cycleCounter.longValue(); + } + +} diff --git a/src/main/java/org/redkale/util/Redkale.java b/src/main/java/org/redkale/util/Redkale.java index bb7e1f48b..c2491ed06 100644 --- a/src/main/java/org/redkale/util/Redkale.java +++ b/src/main/java/org/redkale/util/Redkale.java @@ -1,37 +1,37 @@ -/* - * 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.util; - -/** - * 鐗堟湰 - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public final class Redkale { - - private static final String rootPackage = "org.redkale"; - - private Redkale() { - } - - public static String getRootPackage() { - return rootPackage; - } - - public static String getDotedVersion() { - return "2.5.0"; - } - - public static int getMajorVersion() { - return 2; - } - - public static int getMinorVersion() { - return 5; - } -} +/* + * 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.util; + +/** + * 鐗堟湰 + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public final class Redkale { + + private static final String rootPackage = "org.redkale"; + + private Redkale() { + } + + public static String getRootPackage() { + return rootPackage; + } + + public static String getDotedVersion() { + return "2.5.0"; + } + + public static int getMajorVersion() { + return 2; + } + + public static int getMinorVersion() { + return 5; + } +} diff --git a/src/main/java/org/redkale/util/RedkaleClassLoader.java b/src/main/java/org/redkale/util/RedkaleClassLoader.java index 17900e9e9..84b21d79e 100644 --- a/src/main/java/org/redkale/util/RedkaleClassLoader.java +++ b/src/main/java/org/redkale/util/RedkaleClassLoader.java @@ -1,484 +1,484 @@ -/* - * 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.util; - -import java.io.*; -import java.lang.reflect.*; -import java.net.*; -import java.nio.file.Paths; -import java.util.*; -import java.util.concurrent.*; -import java.util.function.BiConsumer; -import java.util.function.Consumer; - -/** - * Redkale鍐呴儴ClassLoader - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public class RedkaleClassLoader extends URLClassLoader { - - public static final String RESOURCE_CACHE_CLASSES_PATH = "/META-INF/redkale/redkale.load.classes"; - - public static final String RESOURCE_CACHE_CONF_PATH = "/META-INF/redkale/conf"; - - public static final URL URL_NONE; - - static { - URL url = null; - try { - url = URI.create("file://redkale/uri").toURL(); //涓嶈兘鏄痡ar缁撳熬锛屽惁鍒欎細瑙嗕负jar鏂囦欢url - } catch (MalformedURLException e) { - } - URL_NONE = url; - } - - private static final String[] buildClasses = {}; - - private static final String[] buildPackages = { - "org.redkaledyn", //鎵鏈夊姩鎬佺敓鎴愮被鐨勬牴package - "org.redkale.boot", "org.redkale.boot.watch", - "org.redkale.cluster", "org.redkale.convert", - "org.redkale.convert.bson", "org.redkale.convert.ext", - "org.redkale.convert.json", "org.redkale.mq", - "org.redkale.net", "org.redkale.net.client", - "org.redkale.net.http", "org.redkale.net.sncp", - "org.redkale.service", "org.redkale.source", - "org.redkale.util", "org.redkale.watch" - }; - - //redkale閲屾墍鏈変娇鐢ㄥ姩鎬佸瓧鑺傜爜鐢熸垚鐨勭被閮介渶瑕佸瓨浜庢澶 - private static final ConcurrentHashMap dynClassBytesMap = new ConcurrentHashMap<>(); - - private static final ConcurrentHashMap dynClassTypeMap = new ConcurrentHashMap<>(); - - private static final CopyOnWriteArraySet resourcePathSet = new CopyOnWriteArraySet<>(); - - private static final ConcurrentHashMap serviceLoaderMap = new ConcurrentHashMap<>(); - - private static final ConcurrentHashMap> bundleResourcesMap = new ConcurrentHashMap<>(); - - private static final ConcurrentHashMap> reflectionMap = new ConcurrentHashMap<>(); - - public RedkaleClassLoader(ClassLoader parent) { - super(new URL[0], parent); - } - - public RedkaleClassLoader(URL[] urls, ClassLoader parent) { - super(urls, parent); - } - - public static URI getConfResourceAsURI(String confURI, String file) { - if (confURI != null && !confURI.contains("!")) { //甯!鐨勬槸 /usr/xxx.jar!/META-INF/conf/xxx - File f = new File(URI.create(confURI).getPath(), file); - if (f.isFile() && f.canRead()) { - return f.toURI(); - } - } - URL url = RedkaleClassLoader.class.getResource(RESOURCE_CACHE_CONF_PATH + (file.startsWith("/") ? file : ("/" + file))); - return url == null ? null : URI.create(url.toString()); - } - - public static InputStream getConfResourceAsStream(String confURI, String file) { - if (confURI != null && !confURI.contains("!")) { //甯!鐨勬槸 /usr/xxx.jar!/META-INF/conf/xxx - File f = new File(URI.create(confURI).getPath(), file); - if (f.isFile() && f.canRead()) { - try { - return new FileInputStream(f); - } catch (FileNotFoundException e) { //鍑犱箮涓嶄細鍙戠敓 - throw new RuntimeException(e); - } - } - } - return RedkaleClassLoader.class.getResourceAsStream(RESOURCE_CACHE_CONF_PATH + (file.startsWith("/") ? file : ("/" + file))); - } - - public static void forEachBundleResource(BiConsumer> action) { - bundleResourcesMap.forEach(action); - } - - public static void putBundleResource(String name, String locale) { - bundleResourcesMap.computeIfAbsent(name, k -> new CopyOnWriteArraySet<>()).add(locale); - } - - public static void putResourcePath(String name) { - resourcePathSet.add(name); - } - - public static void forEachResourcePath(Consumer action) { - for (String name : resourcePathSet) { - action.accept(name); - } - } - - public static void forEachBuildClass(Consumer action) { - for (String name : buildClasses) { - action.accept(name); - } - } - - public static void forEachBuildPackage(Consumer action) { - for (String name : buildPackages) { - action.accept(name); - } - } - - public static byte[] putDynClass(String name, byte[] bs, Class clazz) { - Objects.requireNonNull(name); - Objects.requireNonNull(bs); - Objects.requireNonNull(clazz); - dynClassTypeMap.put(name, clazz); - return dynClassBytesMap.put(name, bs); - } - - public static Class findDynClass(String name) { - return dynClassTypeMap.get(name); - } - - public static void forEachDynClass(BiConsumer action) { - dynClassBytesMap.forEach(action); - } - - public static void putReflectionClass(String name) { - synchronized (reflectionMap) { - Map map = reflectionMap.get(name); - if (map == null) { - map = new LinkedHashMap<>(); - map.put("name", name); - reflectionMap.put(name, map); - } - } - } - - public static void putServiceLoader(Class clazz) { - serviceLoaderMap.put(clazz.getName(), clazz); - putReflectionClass(clazz.getName()); - } - - public static void forEachServiceLoader(BiConsumer action) { - serviceLoaderMap.forEach(action); - } - - public static void putReflectionField(String name, Field field) { - synchronized (reflectionMap) { - Map map = reflectionMap.get(name); - if (map == null) { - map = new LinkedHashMap(); - map.put("name", name); - reflectionMap.put(name, map); - } - List> list = (List) map.get("fields"); - if (list == null) { - list = new ArrayList<>(); - map.put("fields", list); - list.add((Map) Utility.ofMap("name", field.getName())); - } else { - boolean contains = false; - for (Map item : list) { - if (field.getName().equals(item.get("name"))) { - contains = true; - break; - } - } - if (!contains) list.add((Map) Utility.ofMap("name", field.getName())); - } - } - } - - public static void putReflectionMethod(String name, Method method) { - synchronized (reflectionMap) { - Map map = reflectionMap.get(name); - if (map == null) { - map = new LinkedHashMap(); - map.put("name", name); - reflectionMap.put(name, map); - } - List> list = (List) map.get("methods"); - if (list == null) { - list = new ArrayList<>(); - map.put("methods", list); - list.add(createMap(method.getName(), method.getParameterTypes())); - } else { - Class[] cts = method.getParameterTypes(); - String[] types = new String[cts.length]; - for (int i = 0; i < types.length; i++) { - types[i] = cts[i].getName(); - } - boolean contains = false; - for (Map item : list) { - if (method.getName().equals(item.get("name")) - && Arrays.equals(types, (String[]) item.get("parameterTypes"))) { - contains = true; - break; - } - } - if (!contains) list.add(createMap(method.getName(), method.getParameterTypes())); - } - } - } - - public static void putReflectionDeclaredConstructors(Class clazz, String name, Class... cts) { - synchronized (reflectionMap) { - Map map = reflectionMap.get(name); - if (map == null) { - map = new LinkedHashMap(); - map.put("name", name); - reflectionMap.put(name, map); - } - map.put("allDeclaredConstructors", true); - - if (clazz != null) { - if (clazz.isInterface()) return; - if (Modifier.isAbstract(clazz.getModifiers())) return; - try { - clazz.getDeclaredConstructor(cts); - } catch (Throwable t) { - return; - } - } - String[] types = new String[cts.length]; - for (int i = 0; i < types.length; i++) { - types[i] = cts[i].getName(); - } - List> list = (List) map.get("methods"); - if (list == null) { - list = new ArrayList<>(); - map.put("methods", list); - list.add((Map) Utility.ofMap("name", "", "parameterTypes", types)); - } else { - boolean contains = false; - for (Map item : list) { - if ("".equals(item.get("name")) && Arrays.equals(types, (String[]) item.get("parameterTypes"))) { - contains = true; - break; - } - } - if (!contains) list.add((Map) Utility.ofMap("name", "", "parameterTypes", types)); - } - } - } - - public static void putReflectionPublicConstructors(Class clazz, String name) { - synchronized (reflectionMap) { - Map map = reflectionMap.get(name); - if (map == null) { - map = new LinkedHashMap(); - map.put("name", name); - reflectionMap.put(name, map); - } - map.put("allPublicConstructors", true); - - if (clazz != null) { - if (clazz.isInterface()) return; - if (Modifier.isAbstract(clazz.getModifiers())) return; - try { - clazz.getConstructor(); - } catch (Throwable t) { - return; - } - } - List> list = (List) map.get("methods"); - if (list == null) { - list = new ArrayList<>(); - map.put("methods", list); - list.add((Map) Utility.ofMap("name", "", "parameterTypes", new String[0])); - } else { - boolean contains = false; - for (Map item : list) { - if ("".equals(item.get("name")) && ((String[]) item.get("parameterTypes")).length == 0) { - contains = true; - break; - } - } - if (!contains) list.add((Map) Utility.ofMap("name", "", "parameterTypes", new String[0])); - } - } - } - - public static void putReflectionDeclaredMethods(String name) { - synchronized (reflectionMap) { - Map map = reflectionMap.get(name); - if (map == null) { - map = new LinkedHashMap(); - map.put("name", name); - reflectionMap.put(name, map); - } - map.put("allDeclaredMethods", true); - } - } - - public static void putReflectionPublicMethods(String name) { - synchronized (reflectionMap) { - Map map = reflectionMap.get(name); - if (map == null) { - map = new LinkedHashMap(); - map.put("name", name); - reflectionMap.put(name, map); - } - map.put("allPublicMethods", true); - } - } - - public static void putReflectionDeclaredFields(String name) { - synchronized (reflectionMap) { - Map map = reflectionMap.get(name); - if (map == null) { - map = new LinkedHashMap(); - map.put("name", name); - reflectionMap.put(name, map); - } - map.put("allDeclaredFields", true); - } - } - - public static void putReflectionPublicFields(String name) { - synchronized (reflectionMap) { - Map map = reflectionMap.get(name); - if (map == null) { - map = new LinkedHashMap(); - map.put("name", name); - reflectionMap.put(name, map); - } - map.put("allPublicFields", true); - } - } - - public static void putReflectionDeclaredClasses(String name) { - synchronized (reflectionMap) { - Map map = reflectionMap.get(name); - if (map == null) { - map = new LinkedHashMap(); - map.put("name", name); - reflectionMap.put(name, map); - } - map.put("allDeclaredClasses", true); - } - } - - public static void putReflectionPublicClasses(String name) { - synchronized (reflectionMap) { - Map map = reflectionMap.get(name); - if (map == null) { - map = new LinkedHashMap(); - map.put("name", name); - reflectionMap.put(name, map); - } - map.put("allPublicClasses", true); - } - } - - //https://www.graalvm.org/reference-manual/native-image/Reflection/#manual-configuration - private static Map createMap(String name, Class... cts) { - Map map = new LinkedHashMap<>(); - map.put("name", name); - String[] types = new String[cts.length]; - for (int i = 0; i < types.length; i++) { - types[i] = cts[i].getName(); - } - map.put("parameterTypes", types); - return map; - } - - public static void forEachReflection(BiConsumer> action) { - reflectionMap.forEach(action); - } - - public Class loadClass(String name, byte[] b) { - return defineClass(name, b, 0, b.length); - } - - public void forEachCacheClass(Consumer action) { //getAllURLs杩斿洖URL_NONE鏃堕渶瑕侀噸杞芥鏂规硶 - if (this.getParent() instanceof RedkaleClassLoader) { - ((RedkaleClassLoader) getParent()).forEachCacheClass(action); - } - } - - @Override - public void addURL(URL url) { - super.addURL(url); - } - - @Override - public URL[] getURLs() { - return super.getURLs(); - } - - public URL[] getAllURLs() { - ClassLoader loader = this; - HashSet set = new HashSet<>(); - String appPath = System.getProperty("java.class.path"); - if (appPath != null && !appPath.isEmpty()) { - for (String path : appPath.replace("://", "&&").replace(":\\", "##").replace(':', ';').split(";")) { - try { - set.add(Paths.get(path.replace("&&", "://").replace("##", ":\\")).toRealPath().toFile().toURI().toURL()); - } catch (Exception e) { - } - } - } - do { - String loaderName = loader.getClass().getName(); - if (loaderName.startsWith("sun.") && loaderName.contains("ExtClassLoader")) continue; - if (loader instanceof URLClassLoader) { - for (URL url : ((URLClassLoader) loader).getURLs()) { - set.add(url); - } - } else { //鍙兘JDK9鍙婁互涓 - loader.getResource("org.redkale"); //蹇呴』瑕佽繍琛屼竴娆★紝纭繚URLClassPath鐨勫艰濉厖瀹屾瘯 - Class loaderClazz = loader.getClass(); - Object ucp = null; - do { //璇诲彇 java.base/jdk.internal.loader.BuiltinClassLoader鐨刄RLClassPath ucp鍊 - try { - //闇瑕佸湪鍛戒护琛岄噷鍔犲叆锛 --add-opens java.base/jdk.internal.loader=ALL-UNNAMED - Field field = loaderClazz.getDeclaredField("ucp"); - field.setAccessible(true); - ucp = field.get(loader); - break; - } catch (Throwable e) { - } - } while ((loaderClazz = loaderClazz.getSuperclass()) != Object.class); - if (ucp != null) { //URLClassPath - URL[] urls = null; - try { //璇诲彇 java.base/jdk.internal.loader.URLClassPath鐨剈rls鍊 - Method method = ucp.getClass().getMethod("getURLs"); - urls = (URL[]) method.invoke(ucp); - } catch (Exception e) { - } - if (urls != null) { - for (URL url : urls) { - set.add(url); - } - } - } - } - } while ((loader = loader.getParent()) != null); - return set.toArray(new URL[set.size()]); - } - - public static class RedkaleCacheClassLoader extends RedkaleClassLoader { - - protected final Set classes; - - public RedkaleCacheClassLoader(ClassLoader parent, Set classes) { - super(parent); - this.classes = classes; - } - - @Override - public URL[] getAllURLs() { - return new URL[]{URL_NONE}; - } - - @Override - public void forEachCacheClass(Consumer action) { - classes.forEach(action); - if (getParent() instanceof RedkaleClassLoader) { - ((RedkaleClassLoader) getParent()).forEachCacheClass(action); - } - } - } -} +/* + * 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.util; + +import java.io.*; +import java.lang.reflect.*; +import java.net.*; +import java.nio.file.Paths; +import java.util.*; +import java.util.concurrent.*; +import java.util.function.BiConsumer; +import java.util.function.Consumer; + +/** + * Redkale鍐呴儴ClassLoader + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public class RedkaleClassLoader extends URLClassLoader { + + public static final String RESOURCE_CACHE_CLASSES_PATH = "/META-INF/redkale/redkale.load.classes"; + + public static final String RESOURCE_CACHE_CONF_PATH = "/META-INF/redkale/conf"; + + public static final URL URL_NONE; + + static { + URL url = null; + try { + url = URI.create("file://redkale/uri").toURL(); //涓嶈兘鏄痡ar缁撳熬锛屽惁鍒欎細瑙嗕负jar鏂囦欢url + } catch (MalformedURLException e) { + } + URL_NONE = url; + } + + private static final String[] buildClasses = {}; + + private static final String[] buildPackages = { + "org.redkaledyn", //鎵鏈夊姩鎬佺敓鎴愮被鐨勬牴package + "org.redkale.boot", "org.redkale.boot.watch", + "org.redkale.cluster", "org.redkale.convert", + "org.redkale.convert.bson", "org.redkale.convert.ext", + "org.redkale.convert.json", "org.redkale.mq", + "org.redkale.net", "org.redkale.net.client", + "org.redkale.net.http", "org.redkale.net.sncp", + "org.redkale.service", "org.redkale.source", + "org.redkale.util", "org.redkale.watch" + }; + + //redkale閲屾墍鏈変娇鐢ㄥ姩鎬佸瓧鑺傜爜鐢熸垚鐨勭被閮介渶瑕佸瓨浜庢澶 + private static final ConcurrentHashMap dynClassBytesMap = new ConcurrentHashMap<>(); + + private static final ConcurrentHashMap dynClassTypeMap = new ConcurrentHashMap<>(); + + private static final CopyOnWriteArraySet resourcePathSet = new CopyOnWriteArraySet<>(); + + private static final ConcurrentHashMap serviceLoaderMap = new ConcurrentHashMap<>(); + + private static final ConcurrentHashMap> bundleResourcesMap = new ConcurrentHashMap<>(); + + private static final ConcurrentHashMap> reflectionMap = new ConcurrentHashMap<>(); + + public RedkaleClassLoader(ClassLoader parent) { + super(new URL[0], parent); + } + + public RedkaleClassLoader(URL[] urls, ClassLoader parent) { + super(urls, parent); + } + + public static URI getConfResourceAsURI(String confURI, String file) { + if (confURI != null && !confURI.contains("!")) { //甯!鐨勬槸 /usr/xxx.jar!/META-INF/conf/xxx + File f = new File(URI.create(confURI).getPath(), file); + if (f.isFile() && f.canRead()) { + return f.toURI(); + } + } + URL url = RedkaleClassLoader.class.getResource(RESOURCE_CACHE_CONF_PATH + (file.startsWith("/") ? file : ("/" + file))); + return url == null ? null : URI.create(url.toString()); + } + + public static InputStream getConfResourceAsStream(String confURI, String file) { + if (confURI != null && !confURI.contains("!")) { //甯!鐨勬槸 /usr/xxx.jar!/META-INF/conf/xxx + File f = new File(URI.create(confURI).getPath(), file); + if (f.isFile() && f.canRead()) { + try { + return new FileInputStream(f); + } catch (FileNotFoundException e) { //鍑犱箮涓嶄細鍙戠敓 + throw new RuntimeException(e); + } + } + } + return RedkaleClassLoader.class.getResourceAsStream(RESOURCE_CACHE_CONF_PATH + (file.startsWith("/") ? file : ("/" + file))); + } + + public static void forEachBundleResource(BiConsumer> action) { + bundleResourcesMap.forEach(action); + } + + public static void putBundleResource(String name, String locale) { + bundleResourcesMap.computeIfAbsent(name, k -> new CopyOnWriteArraySet<>()).add(locale); + } + + public static void putResourcePath(String name) { + resourcePathSet.add(name); + } + + public static void forEachResourcePath(Consumer action) { + for (String name : resourcePathSet) { + action.accept(name); + } + } + + public static void forEachBuildClass(Consumer action) { + for (String name : buildClasses) { + action.accept(name); + } + } + + public static void forEachBuildPackage(Consumer action) { + for (String name : buildPackages) { + action.accept(name); + } + } + + public static byte[] putDynClass(String name, byte[] bs, Class clazz) { + Objects.requireNonNull(name); + Objects.requireNonNull(bs); + Objects.requireNonNull(clazz); + dynClassTypeMap.put(name, clazz); + return dynClassBytesMap.put(name, bs); + } + + public static Class findDynClass(String name) { + return dynClassTypeMap.get(name); + } + + public static void forEachDynClass(BiConsumer action) { + dynClassBytesMap.forEach(action); + } + + public static void putReflectionClass(String name) { + synchronized (reflectionMap) { + Map map = reflectionMap.get(name); + if (map == null) { + map = new LinkedHashMap<>(); + map.put("name", name); + reflectionMap.put(name, map); + } + } + } + + public static void putServiceLoader(Class clazz) { + serviceLoaderMap.put(clazz.getName(), clazz); + putReflectionClass(clazz.getName()); + } + + public static void forEachServiceLoader(BiConsumer action) { + serviceLoaderMap.forEach(action); + } + + public static void putReflectionField(String name, Field field) { + synchronized (reflectionMap) { + Map map = reflectionMap.get(name); + if (map == null) { + map = new LinkedHashMap(); + map.put("name", name); + reflectionMap.put(name, map); + } + List> list = (List) map.get("fields"); + if (list == null) { + list = new ArrayList<>(); + map.put("fields", list); + list.add((Map) Utility.ofMap("name", field.getName())); + } else { + boolean contains = false; + for (Map item : list) { + if (field.getName().equals(item.get("name"))) { + contains = true; + break; + } + } + if (!contains) list.add((Map) Utility.ofMap("name", field.getName())); + } + } + } + + public static void putReflectionMethod(String name, Method method) { + synchronized (reflectionMap) { + Map map = reflectionMap.get(name); + if (map == null) { + map = new LinkedHashMap(); + map.put("name", name); + reflectionMap.put(name, map); + } + List> list = (List) map.get("methods"); + if (list == null) { + list = new ArrayList<>(); + map.put("methods", list); + list.add(createMap(method.getName(), method.getParameterTypes())); + } else { + Class[] cts = method.getParameterTypes(); + String[] types = new String[cts.length]; + for (int i = 0; i < types.length; i++) { + types[i] = cts[i].getName(); + } + boolean contains = false; + for (Map item : list) { + if (method.getName().equals(item.get("name")) + && Arrays.equals(types, (String[]) item.get("parameterTypes"))) { + contains = true; + break; + } + } + if (!contains) list.add(createMap(method.getName(), method.getParameterTypes())); + } + } + } + + public static void putReflectionDeclaredConstructors(Class clazz, String name, Class... cts) { + synchronized (reflectionMap) { + Map map = reflectionMap.get(name); + if (map == null) { + map = new LinkedHashMap(); + map.put("name", name); + reflectionMap.put(name, map); + } + map.put("allDeclaredConstructors", true); + + if (clazz != null) { + if (clazz.isInterface()) return; + if (Modifier.isAbstract(clazz.getModifiers())) return; + try { + clazz.getDeclaredConstructor(cts); + } catch (Throwable t) { + return; + } + } + String[] types = new String[cts.length]; + for (int i = 0; i < types.length; i++) { + types[i] = cts[i].getName(); + } + List> list = (List) map.get("methods"); + if (list == null) { + list = new ArrayList<>(); + map.put("methods", list); + list.add((Map) Utility.ofMap("name", "", "parameterTypes", types)); + } else { + boolean contains = false; + for (Map item : list) { + if ("".equals(item.get("name")) && Arrays.equals(types, (String[]) item.get("parameterTypes"))) { + contains = true; + break; + } + } + if (!contains) list.add((Map) Utility.ofMap("name", "", "parameterTypes", types)); + } + } + } + + public static void putReflectionPublicConstructors(Class clazz, String name) { + synchronized (reflectionMap) { + Map map = reflectionMap.get(name); + if (map == null) { + map = new LinkedHashMap(); + map.put("name", name); + reflectionMap.put(name, map); + } + map.put("allPublicConstructors", true); + + if (clazz != null) { + if (clazz.isInterface()) return; + if (Modifier.isAbstract(clazz.getModifiers())) return; + try { + clazz.getConstructor(); + } catch (Throwable t) { + return; + } + } + List> list = (List) map.get("methods"); + if (list == null) { + list = new ArrayList<>(); + map.put("methods", list); + list.add((Map) Utility.ofMap("name", "", "parameterTypes", new String[0])); + } else { + boolean contains = false; + for (Map item : list) { + if ("".equals(item.get("name")) && ((String[]) item.get("parameterTypes")).length == 0) { + contains = true; + break; + } + } + if (!contains) list.add((Map) Utility.ofMap("name", "", "parameterTypes", new String[0])); + } + } + } + + public static void putReflectionDeclaredMethods(String name) { + synchronized (reflectionMap) { + Map map = reflectionMap.get(name); + if (map == null) { + map = new LinkedHashMap(); + map.put("name", name); + reflectionMap.put(name, map); + } + map.put("allDeclaredMethods", true); + } + } + + public static void putReflectionPublicMethods(String name) { + synchronized (reflectionMap) { + Map map = reflectionMap.get(name); + if (map == null) { + map = new LinkedHashMap(); + map.put("name", name); + reflectionMap.put(name, map); + } + map.put("allPublicMethods", true); + } + } + + public static void putReflectionDeclaredFields(String name) { + synchronized (reflectionMap) { + Map map = reflectionMap.get(name); + if (map == null) { + map = new LinkedHashMap(); + map.put("name", name); + reflectionMap.put(name, map); + } + map.put("allDeclaredFields", true); + } + } + + public static void putReflectionPublicFields(String name) { + synchronized (reflectionMap) { + Map map = reflectionMap.get(name); + if (map == null) { + map = new LinkedHashMap(); + map.put("name", name); + reflectionMap.put(name, map); + } + map.put("allPublicFields", true); + } + } + + public static void putReflectionDeclaredClasses(String name) { + synchronized (reflectionMap) { + Map map = reflectionMap.get(name); + if (map == null) { + map = new LinkedHashMap(); + map.put("name", name); + reflectionMap.put(name, map); + } + map.put("allDeclaredClasses", true); + } + } + + public static void putReflectionPublicClasses(String name) { + synchronized (reflectionMap) { + Map map = reflectionMap.get(name); + if (map == null) { + map = new LinkedHashMap(); + map.put("name", name); + reflectionMap.put(name, map); + } + map.put("allPublicClasses", true); + } + } + + //https://www.graalvm.org/reference-manual/native-image/Reflection/#manual-configuration + private static Map createMap(String name, Class... cts) { + Map map = new LinkedHashMap<>(); + map.put("name", name); + String[] types = new String[cts.length]; + for (int i = 0; i < types.length; i++) { + types[i] = cts[i].getName(); + } + map.put("parameterTypes", types); + return map; + } + + public static void forEachReflection(BiConsumer> action) { + reflectionMap.forEach(action); + } + + public Class loadClass(String name, byte[] b) { + return defineClass(name, b, 0, b.length); + } + + public void forEachCacheClass(Consumer action) { //getAllURLs杩斿洖URL_NONE鏃堕渶瑕侀噸杞芥鏂规硶 + if (this.getParent() instanceof RedkaleClassLoader) { + ((RedkaleClassLoader) getParent()).forEachCacheClass(action); + } + } + + @Override + public void addURL(URL url) { + super.addURL(url); + } + + @Override + public URL[] getURLs() { + return super.getURLs(); + } + + public URL[] getAllURLs() { + ClassLoader loader = this; + HashSet set = new HashSet<>(); + String appPath = System.getProperty("java.class.path"); + if (appPath != null && !appPath.isEmpty()) { + for (String path : appPath.replace("://", "&&").replace(":\\", "##").replace(':', ';').split(";")) { + try { + set.add(Paths.get(path.replace("&&", "://").replace("##", ":\\")).toRealPath().toFile().toURI().toURL()); + } catch (Exception e) { + } + } + } + do { + String loaderName = loader.getClass().getName(); + if (loaderName.startsWith("sun.") && loaderName.contains("ExtClassLoader")) continue; + if (loader instanceof URLClassLoader) { + for (URL url : ((URLClassLoader) loader).getURLs()) { + set.add(url); + } + } else { //鍙兘JDK9鍙婁互涓 + loader.getResource("org.redkale"); //蹇呴』瑕佽繍琛屼竴娆★紝纭繚URLClassPath鐨勫艰濉厖瀹屾瘯 + Class loaderClazz = loader.getClass(); + Object ucp = null; + do { //璇诲彇 java.base/jdk.internal.loader.BuiltinClassLoader鐨刄RLClassPath ucp鍊 + try { + //闇瑕佸湪鍛戒护琛岄噷鍔犲叆锛 --add-opens java.base/jdk.internal.loader=ALL-UNNAMED + Field field = loaderClazz.getDeclaredField("ucp"); + field.setAccessible(true); + ucp = field.get(loader); + break; + } catch (Throwable e) { + } + } while ((loaderClazz = loaderClazz.getSuperclass()) != Object.class); + if (ucp != null) { //URLClassPath + URL[] urls = null; + try { //璇诲彇 java.base/jdk.internal.loader.URLClassPath鐨剈rls鍊 + Method method = ucp.getClass().getMethod("getURLs"); + urls = (URL[]) method.invoke(ucp); + } catch (Exception e) { + } + if (urls != null) { + for (URL url : urls) { + set.add(url); + } + } + } + } + } while ((loader = loader.getParent()) != null); + return set.toArray(new URL[set.size()]); + } + + public static class RedkaleCacheClassLoader extends RedkaleClassLoader { + + protected final Set classes; + + public RedkaleCacheClassLoader(ClassLoader parent, Set classes) { + super(parent); + this.classes = classes; + } + + @Override + public URL[] getAllURLs() { + return new URL[]{URL_NONE}; + } + + @Override + public void forEachCacheClass(Consumer action) { + classes.forEach(action); + if (getParent() instanceof RedkaleClassLoader) { + ((RedkaleClassLoader) getParent()).forEachCacheClass(action); + } + } + } +} diff --git a/src/main/java/org/redkale/util/Reproduce.java b/src/main/java/org/redkale/util/Reproduce.java index bd00ede2f..cb8da999c 100644 --- a/src/main/java/org/redkale/util/Reproduce.java +++ b/src/main/java/org/redkale/util/Reproduce.java @@ -1,192 +1,192 @@ -package org.redkale.util; - -import java.lang.reflect.Modifier; -import java.util.Map; -import java.util.function.*; -import static org.redkale.asm.Opcodes.*; -import org.redkale.asm.*; -import static org.redkale.asm.ClassWriter.COMPUTE_FRAMES; - -/** - * JavaBean绫诲璞$殑鎷疯礉锛岀浉鍚岀殑瀛楁鍚嶄細琚嫹璐
- * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param 鐩爣瀵硅薄鐨勬暟鎹被鍨 - * @param 婧愬璞$殑鏁版嵁绫诲瀷 - */ -public interface Reproduce extends BiFunction { - - @Override - public D apply(D dest, S src); - - public static Reproduce create(final Class destClass, final Class srcClass) { - return create(destClass, srcClass, (BiPredicate) null, (Map) null); - } - - public static Reproduce create(final Class destClass, final Class srcClass, final Map names) { - return create(destClass, srcClass, (BiPredicate) null, names); - } - - @SuppressWarnings("unchecked") - public static Reproduce create(final Class destClass, final Class srcClass, final Predicate srcColumnPredicate) { - return create(destClass, srcClass, (sc, m) -> srcColumnPredicate.test(m), (Map) null); - } - - @SuppressWarnings("unchecked") - public static Reproduce create(final Class destClass, final Class srcClass, final Predicate srcColumnPredicate, final Map names) { - return create(destClass, srcClass, (sc, m) -> srcColumnPredicate.test(m), names); - } - - @SuppressWarnings("unchecked") - public static Reproduce create(final Class destClass, final Class srcClass, final BiPredicate srcColumnPredicate) { - return create(destClass, srcClass, srcColumnPredicate, (Map) null); - } - - @SuppressWarnings("unchecked") - public static Reproduce create(final Class destClass, final Class srcClass, final BiPredicate srcColumnPredicate, final Map names) { - // ------------------------------------------------------------------------------ - final String supDynName = Reproduce.class.getName().replace('.', '/'); - final String destClassName = destClass.getName().replace('.', '/'); - final String srcClassName = srcClass.getName().replace('.', '/'); - final String destDesc = Type.getDescriptor(destClass); - final String srcDesc = Type.getDescriptor(srcClass); - final ClassLoader loader = Thread.currentThread().getContextClassLoader(); - final String newDynName = "org/redkaledyn/reproduce/_Dyn" + Reproduce.class.getSimpleName() - + "__" + destClass.getName().replace('.', '_').replace('$', '_') - + "__" + srcClass.getName().replace('.', '_').replace('$', '_'); - try { - Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); - return (Reproduce) (clz == null ? loader.loadClass(newDynName.replace('/', '.')) : clz).getDeclaredConstructor().newInstance(); - } catch (Throwable ex) { - } - // ------------------------------------------------------------------------------ - ClassWriter cw = new ClassWriter(COMPUTE_FRAMES); - FieldVisitor fv; - MethodVisitor mv; - AnnotationVisitor av0; - - cw.visit(V11, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, "Ljava/lang/Object;L" + supDynName + "<" + destDesc + srcDesc + ">;", "java/lang/Object", new String[]{supDynName}); - - { // 鏋勯犲嚱鏁 - mv = (cw.visitMethod(ACC_PUBLIC, "", "()V", null, null)); - //mv.setDebug(true); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } - { - mv = (cw.visitMethod(ACC_PUBLIC, "apply", "(" + destDesc + srcDesc + ")" + destDesc, null, null)); - //mv.setDebug(true); - - for (java.lang.reflect.Field field : srcClass.getFields()) { - if (Modifier.isStatic(field.getModifiers())) continue; - if (Modifier.isFinal(field.getModifiers())) continue; - if (!Modifier.isPublic(field.getModifiers())) continue; - final String sfname = field.getName(); - if (srcColumnPredicate != null && !srcColumnPredicate.test(field, sfname)) continue; - - final String dfname = names == null ? sfname : names.getOrDefault(sfname, sfname); - java.lang.reflect.Method setter = null; - try { - if (!field.getType().equals(destClass.getField(dfname).getType())) continue; - } catch (Exception e) { - try { - char[] cs = dfname.toCharArray(); - cs[0] = Character.toUpperCase(cs[0]); - String dfname2 = new String(cs); - setter = destClass.getMethod("set" + dfname2, field.getType()); - } catch (Exception e2) { - continue; - } - } - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(ALOAD, 2); - String td = Type.getDescriptor(field.getType()); - mv.visitFieldInsn(GETFIELD, srcClassName, sfname, td); - if (setter == null) { - mv.visitFieldInsn(PUTFIELD, destClassName, dfname, td); - } else { - mv.visitMethodInsn(INVOKEVIRTUAL, destClassName, setter.getName(), Type.getMethodDescriptor(setter), false); - } - } - - for (java.lang.reflect.Method getter : srcClass.getMethods()) { - if (Modifier.isStatic(getter.getModifiers())) continue; - if (getter.getParameterTypes().length > 0) continue; - if ("getClass".equals(getter.getName())) continue; - if (!getter.getName().startsWith("get") && !getter.getName().startsWith("is")) continue; - final boolean is = getter.getName().startsWith("is"); - String sfname = getter.getName().substring(is ? 2 : 3); - if (sfname.length() < 2 || Character.isLowerCase(sfname.charAt(1))) { - char[] cs = sfname.toCharArray(); - cs[0] = Character.toLowerCase(cs[0]); - sfname = new String(cs); - } - if (srcColumnPredicate != null && !srcColumnPredicate.test(getter, sfname)) continue; - - final String dfname = names == null ? sfname : names.getOrDefault(sfname, sfname); - java.lang.reflect.Method setter = null; - java.lang.reflect.Field srcField = null; - char[] cs = dfname.toCharArray(); - cs[0] = Character.toUpperCase(cs[0]); - String dfname2 = new String(cs); - try { - setter = destClass.getMethod("set" + dfname2, getter.getReturnType()); - } catch (Exception e) { - try { - srcField = destClass.getField(dfname); - if (!getter.getReturnType().equals(srcField.getType())) continue; - } catch (Exception e2) { - continue; - } - } - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(ALOAD, 2); - mv.visitMethodInsn(INVOKEVIRTUAL, srcClassName, getter.getName(), Type.getMethodDescriptor(getter), false); - if (srcField == null) { - mv.visitMethodInsn(INVOKEVIRTUAL, destClassName, setter.getName(), Type.getMethodDescriptor(setter), false); - } else { - mv.visitFieldInsn(PUTFIELD, destClassName, dfname, Type.getDescriptor(getter.getReturnType())); - } - } - mv.visitVarInsn(ALOAD, 1); - mv.visitInsn(ARETURN); - mv.visitMaxs(3, 3); - mv.visitEnd(); - } - { - mv = (cw.visitMethod(ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, "apply", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", null, null)); - //mv.setDebug(true); - mv.visitVarInsn(ALOAD, 0); - mv.visitVarInsn(ALOAD, 1); - mv.visitTypeInsn(CHECKCAST, destClassName); - mv.visitVarInsn(ALOAD, 2); - mv.visitTypeInsn(CHECKCAST, srcClassName); - mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "apply", "(" + destDesc + srcDesc + ")" + destDesc, false); - mv.visitInsn(ARETURN); - mv.visitMaxs(3, 3); - mv.visitEnd(); - } - 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); - RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, newClazz); - RedkaleClassLoader.putReflectionDeclaredConstructors(newClazz, newDynName.replace('/', '.')); - try { - return (Reproduce) newClazz.getDeclaredConstructor().newInstance(); - } catch (Exception ex) { - throw new RuntimeException(ex); - } - } - -} +package org.redkale.util; + +import java.lang.reflect.Modifier; +import java.util.Map; +import java.util.function.*; +import static org.redkale.asm.Opcodes.*; +import org.redkale.asm.*; +import static org.redkale.asm.ClassWriter.COMPUTE_FRAMES; + +/** + * JavaBean绫诲璞$殑鎷疯礉锛岀浉鍚岀殑瀛楁鍚嶄細琚嫹璐
+ * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param 鐩爣瀵硅薄鐨勬暟鎹被鍨 + * @param 婧愬璞$殑鏁版嵁绫诲瀷 + */ +public interface Reproduce extends BiFunction { + + @Override + public D apply(D dest, S src); + + public static Reproduce create(final Class destClass, final Class srcClass) { + return create(destClass, srcClass, (BiPredicate) null, (Map) null); + } + + public static Reproduce create(final Class destClass, final Class srcClass, final Map names) { + return create(destClass, srcClass, (BiPredicate) null, names); + } + + @SuppressWarnings("unchecked") + public static Reproduce create(final Class destClass, final Class srcClass, final Predicate srcColumnPredicate) { + return create(destClass, srcClass, (sc, m) -> srcColumnPredicate.test(m), (Map) null); + } + + @SuppressWarnings("unchecked") + public static Reproduce create(final Class destClass, final Class srcClass, final Predicate srcColumnPredicate, final Map names) { + return create(destClass, srcClass, (sc, m) -> srcColumnPredicate.test(m), names); + } + + @SuppressWarnings("unchecked") + public static Reproduce create(final Class destClass, final Class srcClass, final BiPredicate srcColumnPredicate) { + return create(destClass, srcClass, srcColumnPredicate, (Map) null); + } + + @SuppressWarnings("unchecked") + public static Reproduce create(final Class destClass, final Class srcClass, final BiPredicate srcColumnPredicate, final Map names) { + // ------------------------------------------------------------------------------ + final String supDynName = Reproduce.class.getName().replace('.', '/'); + final String destClassName = destClass.getName().replace('.', '/'); + final String srcClassName = srcClass.getName().replace('.', '/'); + final String destDesc = Type.getDescriptor(destClass); + final String srcDesc = Type.getDescriptor(srcClass); + final ClassLoader loader = Thread.currentThread().getContextClassLoader(); + final String newDynName = "org/redkaledyn/reproduce/_Dyn" + Reproduce.class.getSimpleName() + + "__" + destClass.getName().replace('.', '_').replace('$', '_') + + "__" + srcClass.getName().replace('.', '_').replace('$', '_'); + try { + Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); + return (Reproduce) (clz == null ? loader.loadClass(newDynName.replace('/', '.')) : clz).getDeclaredConstructor().newInstance(); + } catch (Throwable ex) { + } + // ------------------------------------------------------------------------------ + ClassWriter cw = new ClassWriter(COMPUTE_FRAMES); + FieldVisitor fv; + MethodVisitor mv; + AnnotationVisitor av0; + + cw.visit(V11, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, "Ljava/lang/Object;L" + supDynName + "<" + destDesc + srcDesc + ">;", "java/lang/Object", new String[]{supDynName}); + + { // 鏋勯犲嚱鏁 + mv = (cw.visitMethod(ACC_PUBLIC, "", "()V", null, null)); + //mv.setDebug(true); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + { + mv = (cw.visitMethod(ACC_PUBLIC, "apply", "(" + destDesc + srcDesc + ")" + destDesc, null, null)); + //mv.setDebug(true); + + for (java.lang.reflect.Field field : srcClass.getFields()) { + if (Modifier.isStatic(field.getModifiers())) continue; + if (Modifier.isFinal(field.getModifiers())) continue; + if (!Modifier.isPublic(field.getModifiers())) continue; + final String sfname = field.getName(); + if (srcColumnPredicate != null && !srcColumnPredicate.test(field, sfname)) continue; + + final String dfname = names == null ? sfname : names.getOrDefault(sfname, sfname); + java.lang.reflect.Method setter = null; + try { + if (!field.getType().equals(destClass.getField(dfname).getType())) continue; + } catch (Exception e) { + try { + char[] cs = dfname.toCharArray(); + cs[0] = Character.toUpperCase(cs[0]); + String dfname2 = new String(cs); + setter = destClass.getMethod("set" + dfname2, field.getType()); + } catch (Exception e2) { + continue; + } + } + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 2); + String td = Type.getDescriptor(field.getType()); + mv.visitFieldInsn(GETFIELD, srcClassName, sfname, td); + if (setter == null) { + mv.visitFieldInsn(PUTFIELD, destClassName, dfname, td); + } else { + mv.visitMethodInsn(INVOKEVIRTUAL, destClassName, setter.getName(), Type.getMethodDescriptor(setter), false); + } + } + + for (java.lang.reflect.Method getter : srcClass.getMethods()) { + if (Modifier.isStatic(getter.getModifiers())) continue; + if (getter.getParameterTypes().length > 0) continue; + if ("getClass".equals(getter.getName())) continue; + if (!getter.getName().startsWith("get") && !getter.getName().startsWith("is")) continue; + final boolean is = getter.getName().startsWith("is"); + String sfname = getter.getName().substring(is ? 2 : 3); + if (sfname.length() < 2 || Character.isLowerCase(sfname.charAt(1))) { + char[] cs = sfname.toCharArray(); + cs[0] = Character.toLowerCase(cs[0]); + sfname = new String(cs); + } + if (srcColumnPredicate != null && !srcColumnPredicate.test(getter, sfname)) continue; + + final String dfname = names == null ? sfname : names.getOrDefault(sfname, sfname); + java.lang.reflect.Method setter = null; + java.lang.reflect.Field srcField = null; + char[] cs = dfname.toCharArray(); + cs[0] = Character.toUpperCase(cs[0]); + String dfname2 = new String(cs); + try { + setter = destClass.getMethod("set" + dfname2, getter.getReturnType()); + } catch (Exception e) { + try { + srcField = destClass.getField(dfname); + if (!getter.getReturnType().equals(srcField.getType())) continue; + } catch (Exception e2) { + continue; + } + } + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 2); + mv.visitMethodInsn(INVOKEVIRTUAL, srcClassName, getter.getName(), Type.getMethodDescriptor(getter), false); + if (srcField == null) { + mv.visitMethodInsn(INVOKEVIRTUAL, destClassName, setter.getName(), Type.getMethodDescriptor(setter), false); + } else { + mv.visitFieldInsn(PUTFIELD, destClassName, dfname, Type.getDescriptor(getter.getReturnType())); + } + } + mv.visitVarInsn(ALOAD, 1); + mv.visitInsn(ARETURN); + mv.visitMaxs(3, 3); + mv.visitEnd(); + } + { + mv = (cw.visitMethod(ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, "apply", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", null, null)); + //mv.setDebug(true); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 1); + mv.visitTypeInsn(CHECKCAST, destClassName); + mv.visitVarInsn(ALOAD, 2); + mv.visitTypeInsn(CHECKCAST, srcClassName); + mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "apply", "(" + destDesc + srcDesc + ")" + destDesc, false); + mv.visitInsn(ARETURN); + mv.visitMaxs(3, 3); + mv.visitEnd(); + } + 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); + RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, newClazz); + RedkaleClassLoader.putReflectionDeclaredConstructors(newClazz, newDynName.replace('/', '.')); + try { + return (Reproduce) newClazz.getDeclaredConstructor().newInstance(); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + +} diff --git a/src/main/java/org/redkale/util/Resourcable.java b/src/main/java/org/redkale/util/Resourcable.java index 8553fbeb4..03e64f35a 100644 --- a/src/main/java/org/redkale/util/Resourcable.java +++ b/src/main/java/org/redkale/util/Resourcable.java @@ -1,19 +1,19 @@ -/* - * 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.util; - -/** - * 瀵硅薄鐨勭被娌℃湁鏍囪涓@Resource, 鍙互閫氳繃瀹炵幇Resourcable鎺ュ彛瀹炵幇鍔ㄦ佽幏鍙朢esource.name - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public interface Resourcable { - - public String resourceName(); -} +/* + * 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.util; + +/** + * 瀵硅薄鐨勭被娌℃湁鏍囪涓@Resource, 鍙互閫氳繃瀹炵幇Resourcable鎺ュ彛瀹炵幇鍔ㄦ佽幏鍙朢esource.name + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public interface Resourcable { + + public String resourceName(); +} diff --git a/src/main/java/org/redkale/util/ResourceFactory.java b/src/main/java/org/redkale/util/ResourceFactory.java index 2d0d3c920..e4266331e 100644 --- a/src/main/java/org/redkale/util/ResourceFactory.java +++ b/src/main/java/org/redkale/util/ResourceFactory.java @@ -1,877 +1,877 @@ -/* - * 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.util; - -import java.lang.annotation.Annotation; -import java.lang.ref.WeakReference; -import java.lang.reflect.*; -import java.util.*; -import java.util.concurrent.*; -import java.util.function.*; -import java.util.logging.*; -import javax.annotation.Resource; -import org.redkale.convert.*; - -/** - * - * 渚濊禆娉ㄥ叆鍔熻兘涓荤被
- * - * 濡傛灉@Resource(name = "$") 琛ㄧず璧勬簮name閲囩敤鎵灞炲璞$殑name
- * 濡傛灉娌℃湁@Resource涓斿璞″疄鐜颁簡Resourcable, 鍒欎細鍙栧璞$殑resourceName()鏂规硶鍊 - *

- * name瑙勫垯:
- *    1: "$"鏈夌壒娈婂惈涔, 涓嶈兘琛ㄧず"$"璧勬簮鏈韩
- *    2: 鍙兘鏄瓧姣嶃佹暟瀛椼(鐭í)-銆(涓嬪垝绾)_銆佺偣(.)鐨勭粍鍚
- * 
- *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@SuppressWarnings("unchecked") -public final class ResourceFactory { - - public static final String RESOURCE_PARENT_NAME = "$"; - - private static final Logger logger = Logger.getLogger(ResourceFactory.class.getSimpleName()); - - private final ResourceFactory parent; - - private final List> chidren = new CopyOnWriteArrayList<>(); - - private final ConcurrentHashMap injectLoaderMap = new ConcurrentHashMap(); - - private final ConcurrentHashMap resLoaderMap = new ConcurrentHashMap(); - - private final ConcurrentHashMap> store = new ConcurrentHashMap(); - - private ResourceFactory(ResourceFactory parent) { - this.parent = parent; - if (parent == null) { - ServiceLoader loaders = ServiceLoader.load(ResourceInjectLoader.class); - RedkaleClassLoader.putServiceLoader(ResourceInjectLoader.class); - Iterator it = loaders.iterator(); - while (it.hasNext()) { - ResourceInjectLoader ril = it.next(); - RedkaleClassLoader.putReflectionPublicConstructors(ril.getClass(), ril.getClass().getName()); - this.injectLoaderMap.put(ril.annotationType(), ril); - } - } - } - - /** - * 鍒涘缓涓涓牴ResourceFactory - * - * @return ResourceFactory - */ - public static ResourceFactory create() { - return new ResourceFactory(null); - } - - /** - * 鍒涘缓ResourceFactory瀛愯妭鐐 - * - * @return ResourceFactory - */ - public ResourceFactory createChild() { - ResourceFactory child = new ResourceFactory(this); - this.chidren.add(new WeakReference<>(child)); - return child; - } - - /** - * 鑾峰彇鎵鏈塕esourceFactory瀛愯妭鐐 - * - * @return List - */ - public List getChildren() { - List result = new ArrayList<>(); - for (WeakReference ref : chidren) { - ResourceFactory rf = ref.get(); - if (rf != null) result.add(rf); - } - return result; - } - - /** - * 娓呯┖褰撳墠ResourceFactory娉ㄥ叆璧勬簮 - * - */ - public void release() { - this.store.clear(); - } - - /** - * 妫鏌ヨ祫婧愬悕鏄惁鍚堟硶 - *

-     * name瑙勫垯:
-     *    1: "$"鏈夌壒娈婂惈涔, 琛ㄧず璧勬簮鏈韩锛"$"涓嶈兘鍗曠嫭浣跨敤
-     *    2: 鍙兘鏄瓧姣嶃佹暟瀛椼(鐭í)-銆(涓嬪垝绾)_銆佺偣(.)鐨勭粍鍚
-     * 
- * - * @param name String - */ - public static void checkResourceName(String name) { - if (name == null || (!name.isEmpty() && !name.matches("^[a-zA-Z0-9_;\\-\\.\\[\\]\\(\\)]+$"))) { - throw new IllegalArgumentException("name(" + name + ") contains illegal character, must be (a-z,A-Z,0-9,_,.,(,),-,[,])"); - } - } - - /** - * 灏嗗璞℃寚瀹氱被鍨嬩笖name=""娉ㄥ叆鍒拌祫婧愭睜涓紝骞跺悓姝ュ凡琚敞鍏ョ殑璧勬簮 - * - * @param 娉涘瀷 - * @param clazz 璧勬簮绫诲瀷 - * @param rs 璧勬簮瀵硅薄 - * - * @return 鏃ц祫婧愬璞 - */ - public A register(final Class clazz, final A rs) { - return register(true, clazz, rs); - } - - /** - * 灏嗗璞℃寚瀹氱被鍨嬩笖name=""娉ㄥ叆鍒拌祫婧愭睜涓 - * - * @param 娉涘瀷 - * @param autoSync 鏄惁鍚屾宸茶娉ㄥ叆鐨勮祫婧 - * @param clazz 璧勬簮绫诲瀷 - * @param rs 璧勬簮瀵硅薄 - * - * @return 鏃ц祫婧愬璞 - */ - public A register(final boolean autoSync, final Class clazz, final A rs) { - return register(autoSync, "", clazz, rs); - } - - /** - * 灏嗗璞′互name=""娉ㄥ叆鍒拌祫婧愭睜涓紝骞跺悓姝ュ凡琚敞鍏ョ殑璧勬簮 - * - * @param 娉涘瀷 - * @param rs 璧勬簮瀵硅薄 - * - * @return 鏃ц祫婧愬璞 - */ - public A register(final A rs) { - return register(true, rs); - } - - /** - * 灏嗗璞′互name=""娉ㄥ叆鍒拌祫婧愭睜涓紝骞跺悓姝ュ凡琚敞鍏ョ殑璧勬簮 - * - * @param 娉涘瀷 - * @param autoSync 鏄惁鍚屾宸茶娉ㄥ叆鐨勮祫婧 - * @param rs 璧勬簮瀵硅薄 - * - * @return 鏃ц祫婧愬璞 - */ - public A register(final boolean autoSync, final A rs) { - if (rs == null) return null; - return (A) register(autoSync, "", rs); - } - - /** - * 灏哹oolean瀵硅薄浠ユ寚瀹氳祫婧愬悕娉ㄥ叆鍒拌祫婧愭睜涓紝骞跺悓姝ュ凡琚敞鍏ョ殑璧勬簮 - * - * @param name 璧勬簮鍚 - * @param value 璧勬簮鍊 - * - */ - public void register(final String name, final boolean value) { - register(true, name, boolean.class, value); - } - - /** - * 灏哹oolean瀵硅薄浠ユ寚瀹氳祫婧愬悕娉ㄥ叆鍒拌祫婧愭睜涓 - * - * @param autoSync 鏄惁鍚屾宸茶娉ㄥ叆鐨勮祫婧 - * @param name 璧勬簮鍚 - * @param value 璧勬簮鍊 - * - */ - public void register(final boolean autoSync, final String name, final boolean value) { - register(autoSync, name, boolean.class, value); - } - - /** - * 灏哹yte瀵硅薄浠ユ寚瀹氳祫婧愬悕娉ㄥ叆鍒拌祫婧愭睜涓紝骞跺悓姝ュ凡琚敞鍏ョ殑璧勬簮 - * - * @param name 璧勬簮鍚 - * @param value 璧勬簮鍊 - * - */ - public void register(final String name, final byte value) { - register(true, name, byte.class, value); - } - - /** - * 灏哹yte瀵硅薄浠ユ寚瀹氳祫婧愬悕娉ㄥ叆鍒拌祫婧愭睜涓 - * - * @param autoSync 鏄惁鍚屾宸茶娉ㄥ叆鐨勮祫婧 - * @param name 璧勬簮鍚 - * @param value 璧勬簮鍊 - * - */ - public void register(final boolean autoSync, final String name, final byte value) { - register(autoSync, name, byte.class, value); - } - - /** - * 灏唖hort瀵硅薄浠ユ寚瀹氳祫婧愬悕娉ㄥ叆鍒拌祫婧愭睜涓紝骞跺悓姝ュ凡琚敞鍏ョ殑璧勬簮 - * - * @param name 璧勬簮鍚 - * @param value 璧勬簮鍊 - * - */ - public void register(final String name, final short value) { - register(true, name, short.class, value); - } - - /** - * 灏唖hort瀵硅薄浠ユ寚瀹氳祫婧愬悕娉ㄥ叆鍒拌祫婧愭睜涓 - * - * @param autoSync 鏄惁鍚屾宸茶娉ㄥ叆鐨勮祫婧 - * @param name 璧勬簮鍚 - * @param value 璧勬簮鍊 - * - */ - public void register(final boolean autoSync, final String name, final short value) { - register(autoSync, name, short.class, value); - } - - /** - * 灏唅nt瀵硅薄浠ユ寚瀹氳祫婧愬悕娉ㄥ叆鍒拌祫婧愭睜涓紝骞跺悓姝ュ凡琚敞鍏ョ殑璧勬簮 - * - * @param name 璧勬簮鍚 - * @param value 璧勬簮鍊 - * - */ - public void register(final String name, final int value) { - register(true, name, int.class, value); - } - - /** - * 灏唅nt瀵硅薄浠ユ寚瀹氳祫婧愬悕娉ㄥ叆鍒拌祫婧愭睜涓 - * - * @param autoSync 鏄惁鍚屾宸茶娉ㄥ叆鐨勮祫婧 - * @param name 璧勬簮鍚 - * @param value 璧勬簮鍊 - * - */ - public void register(final boolean autoSync, final String name, final int value) { - register(autoSync, name, int.class, value); - } - - /** - * 灏唂loat瀵硅薄浠ユ寚瀹氳祫婧愬悕娉ㄥ叆鍒拌祫婧愭睜涓紝骞跺悓姝ュ凡琚敞鍏ョ殑璧勬簮 - * - * @param name 璧勬簮鍚 - * @param value 璧勬簮鍊 - * - */ - public void register(final String name, final float value) { - register(true, name, float.class, value); - } - - /** - * 灏唂loat瀵硅薄浠ユ寚瀹氳祫婧愬悕娉ㄥ叆鍒拌祫婧愭睜涓 - * - * @param autoSync 鏄惁鍚屾宸茶娉ㄥ叆鐨勮祫婧 - * @param name 璧勬簮鍚 - * @param value 璧勬簮鍊 - * - */ - public void register(final boolean autoSync, final String name, final float value) { - register(autoSync, name, float.class, value); - } - - /** - * 灏唋ong瀵硅薄浠ユ寚瀹氳祫婧愬悕娉ㄥ叆鍒拌祫婧愭睜涓紝骞跺悓姝ュ凡琚敞鍏ョ殑璧勬簮 - * - * @param name 璧勬簮鍚 - * @param value 璧勬簮鍊 - * - */ - public void register(final String name, final long value) { - register(true, name, long.class, value); - } - - /** - * 灏唋ong瀵硅薄浠ユ寚瀹氳祫婧愬悕娉ㄥ叆鍒拌祫婧愭睜涓 - * - * @param autoSync 鏄惁鍚屾宸茶娉ㄥ叆鐨勮祫婧 - * @param name 璧勬簮鍚 - * @param value 璧勬簮鍊 - * - */ - public void register(final boolean autoSync, final String name, final long value) { - register(autoSync, name, long.class, value); - } - - /** - * 灏哾ouble瀵硅薄浠ユ寚瀹氳祫婧愬悕娉ㄥ叆鍒拌祫婧愭睜涓紝骞跺悓姝ュ凡琚敞鍏ョ殑璧勬簮 - * - * @param name 璧勬簮鍚 - * @param value 璧勬簮鍊 - * - */ - public void register(final String name, final double value) { - register(true, name, double.class, value); - } - - /** - * 灏哾ouble瀵硅薄浠ユ寚瀹氳祫婧愬悕娉ㄥ叆鍒拌祫婧愭睜涓 - * - * @param autoSync 鏄惁鍚屾宸茶娉ㄥ叆鐨勮祫婧 - * @param name 璧勬簮鍚 - * @param value 璧勬簮鍊 - * - */ - public void register(final boolean autoSync, final String name, final double value) { - register(autoSync, name, double.class, value); - } - - /** - * 灏嗗璞′互鎸囧畾璧勬簮鍚嶆敞鍏ュ埌璧勬簮姹犱腑锛屽苟鍚屾宸茶娉ㄥ叆鐨勮祫婧 - * - * @param 娉涘瀷 - * @param name 璧勬簮鍚 - * @param rs 璧勬簮瀵硅薄 - * - * @return 鏃ц祫婧愬璞 - */ - public A register(final String name, final A rs) { - return register(true, name, rs); - } - - /** - * 灏嗗璞′互鎸囧畾璧勬簮鍚嶆敞鍏ュ埌璧勬簮姹犱腑 - * - * @param 娉涘瀷 - * @param autoSync 鏄惁鍚屾宸茶娉ㄥ叆鐨勮祫婧 - * @param name 璧勬簮鍚 - * @param rs 璧勬簮瀵硅薄 - * - * @return 鏃ц祫婧愬璞 - */ - public A register(final boolean autoSync, final String name, final A rs) { - checkResourceName(name); - final Class claz = rs.getClass(); - ResourceType rtype = claz.getAnnotation(ResourceType.class); - if (rtype == null) { - return (A) register(autoSync, name, claz, rs); - } else { - A old = null; - A t = (A) register(autoSync, name, rtype.value(), rs); - if (t != null) old = t; - return old; - } - } - - /** - * 灏嗗璞′互鎸囧畾璧勬簮鍚嶅拰绫诲瀷娉ㄥ叆鍒拌祫婧愭睜涓紝骞跺悓姝ュ凡琚敞鍏ョ殑璧勬簮 - * - * @param 娉涘瀷 - * @param name 璧勬簮鍚 - * @param clazz 璧勬簮绫诲瀷 - * @param rs 璧勬簮瀵硅薄 - * - * @return 鏃ц祫婧愬璞 - */ - public A register(final String name, final Class clazz, final A rs) { - return register(true, name, clazz, rs); - } - - /** - * 灏嗗璞′互鎸囧畾璧勬簮鍚嶅拰绫诲瀷娉ㄥ叆鍒拌祫婧愭睜涓紝骞跺悓姝ュ凡琚敞鍏ョ殑璧勬簮 - * - * @param 娉涘瀷 - * @param name 璧勬簮鍚 - * @param clazz 璧勬簮绫诲瀷 - * @param rs 璧勬簮瀵硅薄 - * - * @return 鏃ц祫婧愬璞 - */ - public A register(final String name, final Type clazz, final A rs) { - return register(true, name, clazz, rs); - } - - /** - * 灏嗗璞′互鎸囧畾璧勬簮鍚嶅拰绫诲瀷娉ㄥ叆鍒拌祫婧愭睜涓 - * - * @param 娉涘瀷 - * @param autoSync 鏄惁鍚屾宸茶娉ㄥ叆鐨勮祫婧 - * @param name 璧勬簮鍚 - * @param clazz 璧勬簮绫诲瀷 - * @param rs 璧勬簮瀵硅薄 - * - * @return 鏃ц祫婧愬璞 - */ - public A register(final boolean autoSync, final String name, final Type clazz, final A rs) { - checkResourceName(name); - ConcurrentHashMap map = this.store.get(clazz); - if (map == null) { - synchronized (clazz) { - map = this.store.get(clazz); - if (map == null) { - map = new ConcurrentHashMap(); - store.put(clazz, map); - } - } - } - ResourceEntry re = map.get(name); - if (re == null) { - map.put(name, new ResourceEntry(rs)); - } else { - map.put(name, new ResourceEntry(rs, name, re.elements, autoSync)); - } - return re == null ? null : (A) re.value; - } - - /** - * 鍒ゆ柇鏄惁鍖呭惈鎸囧畾璧勬簮鍚嶅拰璧勬簮绫诲瀷鐨勮祫婧愬璞 - * - * @param 娉涘瀷 - * @param recursive 鏄惁閬嶅巻鐖惰妭鐐 - * @param name 璧勬簮鍚 - * @param clazz 璧勬簮绫诲瀷 - * - * @return 鏄惁瀛樺湪 - */ - public boolean contains(boolean recursive, String name, Class clazz) { - Map map = this.store.get(clazz); - return map == null ? ((recursive && parent != null) ? parent.contains(recursive, name, clazz) : false) : map.containsKey(name); - } - - /** - * 鏌ユ壘鎸囧畾璧勬簮鍚嶅拰璧勬簮绫诲瀷鐨勮祫婧愬璞℃墍鍦ㄧ殑ResourceFactory锛 娌℃湁鍒欒繑鍥瀗ull - * - * @param name 璧勬簮鍚 - * @param clazz 璧勬簮绫诲瀷 - * - * @return ResourceFactory - */ - public ResourceFactory findResourceFactory(String name, Type clazz) { - Map map = this.store.get(clazz); - if (map != null && map.containsKey(name)) return this; - if (parent != null) return parent.findResourceFactory(name, clazz); - return null; - } - - public A find(Class clazz) { - return find("", clazz); - } - - public A find(String name, Type clazz) { - ResourceEntry re = findEntry(name, clazz); - return re == null ? null : (A) re.value; - } - - public A find(String name, Class clazz) { - ResourceEntry re = findEntry(name, clazz); - return re == null ? null : re.value; - } - - public A findChild(final String name, final Class clazz) { - A rs = find(name, clazz); - if (rs != null) return rs; - for (Map.Entry> en : this.store.entrySet()) { - if (!(en.getKey() instanceof Class)) continue; - if (!clazz.isAssignableFrom((Class) en.getKey())) continue; - ResourceEntry v = en.getValue().get(name); - if (v != null) return (A) v.value; - } - return null; - } - - private ResourceEntry findEntry(String name, Type clazz) { - Map map = this.store.get(clazz); - if (map != null) { - ResourceEntry re = map.get(name); - if (re != null) return re; - } - if (parent != null) return parent.findEntry(name, clazz); - return null; - } - - public List query(Class clazz) { - return query(new ArrayList<>(), clazz); - } - - public List query(Type clazz) { - return query(new ArrayList<>(), clazz); - } - - private List query(final List list, Type clazz) { - Map map = this.store.get(clazz); - if (map != null) { - for (ResourceEntry re : map.values()) { - if (re.value != null) list.add((A) re.value); - } - } - if (parent != null) parent.query(list, clazz); - return list; - } - - public List query(final BiPredicate predicate) { - return query(new ArrayList<>(), predicate); - } - - private List query(final List list, final BiPredicate predicate) { - if (predicate == null) return list; - for (ConcurrentHashMap map : this.store.values()) { - for (Map.Entry en : map.entrySet()) { - if (predicate.test(en.getKey(), en.getValue().value)) { - list.add((A) en.getValue().value); - } - } - } - if (parent != null) parent.query(list, predicate); - return list; - } - - private ResourceEntry findEntry(String name, Class clazz) { - Map map = this.store.get(clazz); - if (map != null) { - ResourceEntry rs = map.get(name); - if (rs != null) return rs; - } - if (parent != null) return parent.findEntry(name, clazz); - return null; - } - - public boolean inject(final Object src) { - return inject(src, null); - } - - public boolean inject(final Object src, final T attachment) { - return inject(src, attachment, null); - } - - public boolean inject(final Object src, final BiConsumer consumer) { - return inject(src, null, consumer); - } - - public boolean inject(final Object src, final T attachment, final BiConsumer consumer) { - return inject(src, attachment, consumer, new ArrayList()); - } - - public static String formatResourceName(String name) { - if (name == null) return null; - int pos = name.indexOf("{system.property."); - if (pos < 0) return name; - String prefix = name.substring(0, pos); - String subname = name.substring(pos + "{system.property.".length()); - pos = subname.lastIndexOf('}'); - if (pos < 0) return name; - String postfix = subname.substring(pos + 1); - String property = subname.substring(0, pos); - return formatResourceName(prefix + System.getProperty(property, "") + postfix); - } - - private boolean inject(final Object src, final T attachment, final BiConsumer consumer, final List list) { - if (src == null) return false; - try { - list.add(src); - Class clazz = src.getClass(); - final boolean diyloaderflag = !parentRoot().injectLoaderMap.isEmpty(); - do { - if (java.lang.Enum.class.isAssignableFrom(clazz)) break; - final String cname = clazz.getName(); - if (cname.startsWith("java.") || cname.startsWith("javax.") - || cname.startsWith("jdk.") || cname.startsWith("sun.")) break; - if (cname.indexOf('/') < 0) {//鎺掗櫎鍐呴儴绫伙紝 濡:JsonConvert$$Lambda$87/0x0000000100197440- - RedkaleClassLoader.putReflectionDeclaredFields(cname); - } - for (Field field : clazz.getDeclaredFields()) { - if (Modifier.isStatic(field.getModifiers())) continue; - field.setAccessible(true); - final Class classtype = field.getType(); - Resource rc = field.getAnnotation(Resource.class); - if (rc == null) { //娣卞害娉ㄥ叆 - if (Convert.class.isAssignableFrom(classtype)) continue; - if (ConvertFactory.class.isAssignableFrom(classtype)) continue; - if (ResourceFactory.class.isAssignableFrom(classtype)) continue; - boolean flag = true; //鏄惁娌℃湁閲嶅 - Object ns = field.get(src); - for (Object o : list) { - if (o == ns) { - flag = false; - break; - } - } - if (flag && diyloaderflag) { - parentRoot().injectLoaderMap.values().stream().forEach(iloader -> { - Annotation ann = field.getAnnotation(iloader.annotationType()); - if (ann == null) return; - iloader.load(this, src, ann, field, attachment); - }); - } - if (ns == null) continue; - final String nsname = ns.getClass().getName(); - if (ns.getClass().isPrimitive() || ns.getClass().isArray() - || nsname.startsWith("java.") || nsname.startsWith("javax.") - || nsname.startsWith("jdk.") || nsname.startsWith("sun.")) continue; - if (flag) this.inject(ns, attachment, consumer, list); - continue; - } - if (Modifier.isFinal(field.getModifiers())) continue; - RedkaleClassLoader.putReflectionField(cname, field); - final Type genctype = TypeToken.containsUnknownType(field.getGenericType()) - ? TypeToken.getGenericType(field.getGenericType(), src.getClass()) : field.getGenericType(); - if (consumer != null) consumer.accept(src, field); - String tname = rc.name(); - if (tname.contains(RESOURCE_PARENT_NAME)) { - Resource res = src.getClass().getAnnotation(Resource.class); - if (res == null) { - if (src instanceof Resourcable) { - tname = tname.replace(RESOURCE_PARENT_NAME, ((Resourcable) src).resourceName()); - } else { - logger.log(Level.SEVERE, src.getClass().getName() + " not found @Resource on Class or not implements Resourcable"); - } - } else { - tname = tname.replace(RESOURCE_PARENT_NAME, res.name()); - } - - } - boolean autoregnull = true; - final String rcname = formatResourceName(tname); - Object rs; - if (rcname.startsWith("system.property.")) { - rs = System.getProperty(rcname.substring("system.property.".length())); - } else { - ResourceEntry re = findEntry(rcname, genctype); - if (re == null) { - if (rcname.startsWith("property.")) { - re = findEntry(rcname, String.class); - } else { - re = findEntry(rcname, classtype); - } - } - if (re == null) { - ResourceLoader it = findLoader(genctype, field); - if (it != null) { - it.load(this, src, rcname, field, attachment); - autoregnull = it.autoNone(); - re = findEntry(rcname, genctype); - } - } - if (re == null && genctype != classtype) { - re = findEntry(rcname, classtype); - if (re == null) { - if (rcname.startsWith("property.")) { - re = findEntry(rcname, String.class); - } else { - re = findEntry(rcname, classtype); - } - } - if (re == null) { - ResourceLoader it = findLoader(classtype, field); - if (it != null) { - it.load(this, src, rcname, field, attachment); - autoregnull = it.autoNone(); - re = findEntry(rcname, classtype); - } - } - } - if (re == null && autoregnull) { - register(rcname, genctype, null); //鑷姩娉ㄥ叆null鐨勫 - re = findEntry(rcname, genctype); - } - if (re == null) continue; - re.elements.add(new ResourceElement<>(src, field)); - rs = re.value; - } - if (rs != null && !rs.getClass().isPrimitive() && classtype.isPrimitive()) { - if (classtype == int.class) { - rs = Integer.decode(rs.toString()); - } else if (classtype == long.class) { - rs = Long.decode(rs.toString()); - } else if (classtype == short.class) { - rs = Short.decode(rs.toString()); - } else if (classtype == boolean.class) { - rs = "true".equalsIgnoreCase(rs.toString()); - } else if (classtype == byte.class) { - rs = Byte.decode(rs.toString()); - } else if (classtype == float.class) { - rs = Float.parseFloat(rs.toString()); - } else if (classtype == double.class) { - rs = Double.parseDouble(rs.toString()); - } - } - if (rs != null) field.set(src, rs); - } - } while ((clazz = clazz.getSuperclass()) != Object.class); - return true; - } catch (Exception ex) { - logger.log(Level.SEVERE, "inject " + src + " error", ex); - return false; - } - } - - public void register(final ResourceInjectLoader loader) { - if (loader == null) return; - parentRoot().injectLoaderMap.put(loader.annotationType(), loader); - } - - public void register(final ResourceLoader rs, final Type... clazzs) { - if (clazzs == null || rs == null) return; - for (Type clazz : clazzs) { - resLoaderMap.put(clazz, rs); - } - } - - private ResourceFactory parentRoot() { - if (parent == null) return this; - return parent.parentRoot(); - } - - private ResourceLoader findMatchLoader(Type ft, Field field) { - ResourceLoader it = this.resLoaderMap.get(ft); - if (it == null && field != null) it = this.resLoaderMap.get(field.getType()); - if (it != null) return it; - return parent == null ? null : parent.findMatchLoader(ft, field); - } - - private ResourceLoader findRegxLoader(Type ft, Field field) { - if (field == null) return null; - Class c = field.getType(); - for (Map.Entry en : this.resLoaderMap.entrySet()) { - Type t = en.getKey(); - if (t == ft) return en.getValue(); - if (t instanceof Class && (((Class) t)).isAssignableFrom(c)) return en.getValue(); - } - return parent == null ? null : parent.findRegxLoader(ft, field); - } - - public ResourceLoader findLoader(Type ft, Field field) { - ResourceLoader it = this.findMatchLoader(ft, field); - return it == null ? findRegxLoader(ft, field) : it; - } - - private static class ResourceEntry { - - public final T value; - - public final List elements; - - public ResourceEntry(T value) { - this.value = value; - this.elements = new CopyOnWriteArrayList<>(); - } - - public ResourceEntry(T value, final String name, final List elements, boolean sync) { - this.value = value; - this.elements = elements == null ? new CopyOnWriteArrayList<>() : elements; - if (sync && elements != null && !elements.isEmpty()) { - - for (ResourceElement element : elements) { - Object dest = element.dest.get(); - if (dest == null) continue; - Object rs = value; - final Class classtype = element.fieldType; - if (rs != null && !rs.getClass().isPrimitive() && classtype.isPrimitive()) { - if (classtype == int.class) { - rs = Integer.decode(rs.toString()); - } else if (classtype == long.class) { - rs = Long.decode(rs.toString()); - } else if (classtype == short.class) { - rs = Short.decode(rs.toString()); - } else if (classtype == boolean.class) { - rs = "true".equalsIgnoreCase(rs.toString()); - } else if (classtype == byte.class) { - rs = Byte.decode(rs.toString()); - } else if (classtype == float.class) { - rs = Float.parseFloat(rs.toString()); - } else if (classtype == double.class) { - rs = Double.parseDouble(rs.toString()); - } - } - if (rs == null && classtype.isPrimitive()) rs = Array.get(Array.newInstance(classtype, 1), 0); - Object oldVal = null; - if (element.listener != null) { - try { - oldVal = element.field.get(dest); - } catch (Exception e) { - e.printStackTrace(); - } - } - try { - element.field.set(dest, rs); - } catch (Exception e) { - e.printStackTrace(); - } - if (element.listener != null) { - try { - element.listener.invoke(dest, name, rs, oldVal); - } catch (Exception e) { - logger.log(Level.SEVERE, dest + " resource change listener error", e); - } - } - } - } - } - } - - private static class ResourceElement { - - private static final HashMap listenerMethods = new HashMap<>(); //涓嶄娇鐢–oncurrentHashMap鏄洜涓簐alue涓嶈兘瀛榥ull - - public final WeakReference dest; - - public final Field field; //Resource 瀛楁 - - public final Class fieldType; - - public final Method listener; - - public ResourceElement(T dest, Field field) { - this.dest = new WeakReference(dest); - this.field = field; - this.fieldType = field.getType(); - Class t = dest.getClass(); - String tn = t.getName(); - this.listener = tn.startsWith("java.") || tn.startsWith("javax.") ? null : findListener(t, field.getType()); - } - - private static Method findListener(Class clazz, Class fieldType) { - synchronized (listenerMethods) { - Class loop = clazz; - Method m = listenerMethods.get(clazz.getName() + "-" + fieldType.getName()); - if (m != null) return m; - do { - RedkaleClassLoader.putReflectionDeclaredMethods(loop.getName()); - for (Method method : loop.getDeclaredMethods()) { - if (method.getAnnotation(ResourceListener.class) != null - && method.getParameterCount() == 3 - && String.class.isAssignableFrom(method.getParameterTypes()[0]) - && method.getParameterTypes()[1] == method.getParameterTypes()[2] - && method.getParameterTypes()[1].isAssignableFrom(fieldType)) { - m = method; - m.setAccessible(true); - RedkaleClassLoader.putReflectionMethod(loop.getName(), method); - break; - } - } - } while ((loop = loop.getSuperclass()) != Object.class); - listenerMethods.put(clazz.getName() + "-" + fieldType.getName(), m); - return m; - } - } - } - - @FunctionalInterface - public static interface ResourceLoader { - - public void load(ResourceFactory factory, Object src, String resourceName, Field field, Object attachment); - - // 杩斿洖true 琛ㄧず璋冪敤ResourceLoader涔嬪悗璧勬簮浠嶄笉瀛樺湪锛屽垯浼氬湪ResourceFactory閲屾敞鍏ラ粯璁ゅ糿ull锛岃繑鍥瀎alse琛ㄧず璧勬簮涓嶅瓨鍦ㄤ笅娆′粛浼氳皟鐢≧esourceLoader鑷澶勭悊 - default boolean autoNone() { - return true; - } - } - -} +/* + * 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.util; + +import java.lang.annotation.Annotation; +import java.lang.ref.WeakReference; +import java.lang.reflect.*; +import java.util.*; +import java.util.concurrent.*; +import java.util.function.*; +import java.util.logging.*; +import javax.annotation.Resource; +import org.redkale.convert.*; + +/** + * + * 渚濊禆娉ㄥ叆鍔熻兘涓荤被
+ * + * 濡傛灉@Resource(name = "$") 琛ㄧず璧勬簮name閲囩敤鎵灞炲璞$殑name
+ * 濡傛灉娌℃湁@Resource涓斿璞″疄鐜颁簡Resourcable, 鍒欎細鍙栧璞$殑resourceName()鏂规硶鍊 + *
+ * name瑙勫垯:
+ *    1: "$"鏈夌壒娈婂惈涔, 涓嶈兘琛ㄧず"$"璧勬簮鏈韩
+ *    2: 鍙兘鏄瓧姣嶃佹暟瀛椼(鐭í)-銆(涓嬪垝绾)_銆佺偣(.)鐨勭粍鍚
+ * 
+ *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@SuppressWarnings("unchecked") +public final class ResourceFactory { + + public static final String RESOURCE_PARENT_NAME = "$"; + + private static final Logger logger = Logger.getLogger(ResourceFactory.class.getSimpleName()); + + private final ResourceFactory parent; + + private final List> chidren = new CopyOnWriteArrayList<>(); + + private final ConcurrentHashMap injectLoaderMap = new ConcurrentHashMap(); + + private final ConcurrentHashMap resLoaderMap = new ConcurrentHashMap(); + + private final ConcurrentHashMap> store = new ConcurrentHashMap(); + + private ResourceFactory(ResourceFactory parent) { + this.parent = parent; + if (parent == null) { + ServiceLoader loaders = ServiceLoader.load(ResourceInjectLoader.class); + RedkaleClassLoader.putServiceLoader(ResourceInjectLoader.class); + Iterator it = loaders.iterator(); + while (it.hasNext()) { + ResourceInjectLoader ril = it.next(); + RedkaleClassLoader.putReflectionPublicConstructors(ril.getClass(), ril.getClass().getName()); + this.injectLoaderMap.put(ril.annotationType(), ril); + } + } + } + + /** + * 鍒涘缓涓涓牴ResourceFactory + * + * @return ResourceFactory + */ + public static ResourceFactory create() { + return new ResourceFactory(null); + } + + /** + * 鍒涘缓ResourceFactory瀛愯妭鐐 + * + * @return ResourceFactory + */ + public ResourceFactory createChild() { + ResourceFactory child = new ResourceFactory(this); + this.chidren.add(new WeakReference<>(child)); + return child; + } + + /** + * 鑾峰彇鎵鏈塕esourceFactory瀛愯妭鐐 + * + * @return List + */ + public List getChildren() { + List result = new ArrayList<>(); + for (WeakReference ref : chidren) { + ResourceFactory rf = ref.get(); + if (rf != null) result.add(rf); + } + return result; + } + + /** + * 娓呯┖褰撳墠ResourceFactory娉ㄥ叆璧勬簮 + * + */ + public void release() { + this.store.clear(); + } + + /** + * 妫鏌ヨ祫婧愬悕鏄惁鍚堟硶 + *

+     * name瑙勫垯:
+     *    1: "$"鏈夌壒娈婂惈涔, 琛ㄧず璧勬簮鏈韩锛"$"涓嶈兘鍗曠嫭浣跨敤
+     *    2: 鍙兘鏄瓧姣嶃佹暟瀛椼(鐭í)-銆(涓嬪垝绾)_銆佺偣(.)鐨勭粍鍚
+     * 
+ * + * @param name String + */ + public static void checkResourceName(String name) { + if (name == null || (!name.isEmpty() && !name.matches("^[a-zA-Z0-9_;\\-\\.\\[\\]\\(\\)]+$"))) { + throw new IllegalArgumentException("name(" + name + ") contains illegal character, must be (a-z,A-Z,0-9,_,.,(,),-,[,])"); + } + } + + /** + * 灏嗗璞℃寚瀹氱被鍨嬩笖name=""娉ㄥ叆鍒拌祫婧愭睜涓紝骞跺悓姝ュ凡琚敞鍏ョ殑璧勬簮 + * + * @param 娉涘瀷 + * @param clazz 璧勬簮绫诲瀷 + * @param rs 璧勬簮瀵硅薄 + * + * @return 鏃ц祫婧愬璞 + */ + public A register(final Class clazz, final A rs) { + return register(true, clazz, rs); + } + + /** + * 灏嗗璞℃寚瀹氱被鍨嬩笖name=""娉ㄥ叆鍒拌祫婧愭睜涓 + * + * @param 娉涘瀷 + * @param autoSync 鏄惁鍚屾宸茶娉ㄥ叆鐨勮祫婧 + * @param clazz 璧勬簮绫诲瀷 + * @param rs 璧勬簮瀵硅薄 + * + * @return 鏃ц祫婧愬璞 + */ + public A register(final boolean autoSync, final Class clazz, final A rs) { + return register(autoSync, "", clazz, rs); + } + + /** + * 灏嗗璞′互name=""娉ㄥ叆鍒拌祫婧愭睜涓紝骞跺悓姝ュ凡琚敞鍏ョ殑璧勬簮 + * + * @param 娉涘瀷 + * @param rs 璧勬簮瀵硅薄 + * + * @return 鏃ц祫婧愬璞 + */ + public A register(final A rs) { + return register(true, rs); + } + + /** + * 灏嗗璞′互name=""娉ㄥ叆鍒拌祫婧愭睜涓紝骞跺悓姝ュ凡琚敞鍏ョ殑璧勬簮 + * + * @param 娉涘瀷 + * @param autoSync 鏄惁鍚屾宸茶娉ㄥ叆鐨勮祫婧 + * @param rs 璧勬簮瀵硅薄 + * + * @return 鏃ц祫婧愬璞 + */ + public A register(final boolean autoSync, final A rs) { + if (rs == null) return null; + return (A) register(autoSync, "", rs); + } + + /** + * 灏哹oolean瀵硅薄浠ユ寚瀹氳祫婧愬悕娉ㄥ叆鍒拌祫婧愭睜涓紝骞跺悓姝ュ凡琚敞鍏ョ殑璧勬簮 + * + * @param name 璧勬簮鍚 + * @param value 璧勬簮鍊 + * + */ + public void register(final String name, final boolean value) { + register(true, name, boolean.class, value); + } + + /** + * 灏哹oolean瀵硅薄浠ユ寚瀹氳祫婧愬悕娉ㄥ叆鍒拌祫婧愭睜涓 + * + * @param autoSync 鏄惁鍚屾宸茶娉ㄥ叆鐨勮祫婧 + * @param name 璧勬簮鍚 + * @param value 璧勬簮鍊 + * + */ + public void register(final boolean autoSync, final String name, final boolean value) { + register(autoSync, name, boolean.class, value); + } + + /** + * 灏哹yte瀵硅薄浠ユ寚瀹氳祫婧愬悕娉ㄥ叆鍒拌祫婧愭睜涓紝骞跺悓姝ュ凡琚敞鍏ョ殑璧勬簮 + * + * @param name 璧勬簮鍚 + * @param value 璧勬簮鍊 + * + */ + public void register(final String name, final byte value) { + register(true, name, byte.class, value); + } + + /** + * 灏哹yte瀵硅薄浠ユ寚瀹氳祫婧愬悕娉ㄥ叆鍒拌祫婧愭睜涓 + * + * @param autoSync 鏄惁鍚屾宸茶娉ㄥ叆鐨勮祫婧 + * @param name 璧勬簮鍚 + * @param value 璧勬簮鍊 + * + */ + public void register(final boolean autoSync, final String name, final byte value) { + register(autoSync, name, byte.class, value); + } + + /** + * 灏唖hort瀵硅薄浠ユ寚瀹氳祫婧愬悕娉ㄥ叆鍒拌祫婧愭睜涓紝骞跺悓姝ュ凡琚敞鍏ョ殑璧勬簮 + * + * @param name 璧勬簮鍚 + * @param value 璧勬簮鍊 + * + */ + public void register(final String name, final short value) { + register(true, name, short.class, value); + } + + /** + * 灏唖hort瀵硅薄浠ユ寚瀹氳祫婧愬悕娉ㄥ叆鍒拌祫婧愭睜涓 + * + * @param autoSync 鏄惁鍚屾宸茶娉ㄥ叆鐨勮祫婧 + * @param name 璧勬簮鍚 + * @param value 璧勬簮鍊 + * + */ + public void register(final boolean autoSync, final String name, final short value) { + register(autoSync, name, short.class, value); + } + + /** + * 灏唅nt瀵硅薄浠ユ寚瀹氳祫婧愬悕娉ㄥ叆鍒拌祫婧愭睜涓紝骞跺悓姝ュ凡琚敞鍏ョ殑璧勬簮 + * + * @param name 璧勬簮鍚 + * @param value 璧勬簮鍊 + * + */ + public void register(final String name, final int value) { + register(true, name, int.class, value); + } + + /** + * 灏唅nt瀵硅薄浠ユ寚瀹氳祫婧愬悕娉ㄥ叆鍒拌祫婧愭睜涓 + * + * @param autoSync 鏄惁鍚屾宸茶娉ㄥ叆鐨勮祫婧 + * @param name 璧勬簮鍚 + * @param value 璧勬簮鍊 + * + */ + public void register(final boolean autoSync, final String name, final int value) { + register(autoSync, name, int.class, value); + } + + /** + * 灏唂loat瀵硅薄浠ユ寚瀹氳祫婧愬悕娉ㄥ叆鍒拌祫婧愭睜涓紝骞跺悓姝ュ凡琚敞鍏ョ殑璧勬簮 + * + * @param name 璧勬簮鍚 + * @param value 璧勬簮鍊 + * + */ + public void register(final String name, final float value) { + register(true, name, float.class, value); + } + + /** + * 灏唂loat瀵硅薄浠ユ寚瀹氳祫婧愬悕娉ㄥ叆鍒拌祫婧愭睜涓 + * + * @param autoSync 鏄惁鍚屾宸茶娉ㄥ叆鐨勮祫婧 + * @param name 璧勬簮鍚 + * @param value 璧勬簮鍊 + * + */ + public void register(final boolean autoSync, final String name, final float value) { + register(autoSync, name, float.class, value); + } + + /** + * 灏唋ong瀵硅薄浠ユ寚瀹氳祫婧愬悕娉ㄥ叆鍒拌祫婧愭睜涓紝骞跺悓姝ュ凡琚敞鍏ョ殑璧勬簮 + * + * @param name 璧勬簮鍚 + * @param value 璧勬簮鍊 + * + */ + public void register(final String name, final long value) { + register(true, name, long.class, value); + } + + /** + * 灏唋ong瀵硅薄浠ユ寚瀹氳祫婧愬悕娉ㄥ叆鍒拌祫婧愭睜涓 + * + * @param autoSync 鏄惁鍚屾宸茶娉ㄥ叆鐨勮祫婧 + * @param name 璧勬簮鍚 + * @param value 璧勬簮鍊 + * + */ + public void register(final boolean autoSync, final String name, final long value) { + register(autoSync, name, long.class, value); + } + + /** + * 灏哾ouble瀵硅薄浠ユ寚瀹氳祫婧愬悕娉ㄥ叆鍒拌祫婧愭睜涓紝骞跺悓姝ュ凡琚敞鍏ョ殑璧勬簮 + * + * @param name 璧勬簮鍚 + * @param value 璧勬簮鍊 + * + */ + public void register(final String name, final double value) { + register(true, name, double.class, value); + } + + /** + * 灏哾ouble瀵硅薄浠ユ寚瀹氳祫婧愬悕娉ㄥ叆鍒拌祫婧愭睜涓 + * + * @param autoSync 鏄惁鍚屾宸茶娉ㄥ叆鐨勮祫婧 + * @param name 璧勬簮鍚 + * @param value 璧勬簮鍊 + * + */ + public void register(final boolean autoSync, final String name, final double value) { + register(autoSync, name, double.class, value); + } + + /** + * 灏嗗璞′互鎸囧畾璧勬簮鍚嶆敞鍏ュ埌璧勬簮姹犱腑锛屽苟鍚屾宸茶娉ㄥ叆鐨勮祫婧 + * + * @param 娉涘瀷 + * @param name 璧勬簮鍚 + * @param rs 璧勬簮瀵硅薄 + * + * @return 鏃ц祫婧愬璞 + */ + public A register(final String name, final A rs) { + return register(true, name, rs); + } + + /** + * 灏嗗璞′互鎸囧畾璧勬簮鍚嶆敞鍏ュ埌璧勬簮姹犱腑 + * + * @param 娉涘瀷 + * @param autoSync 鏄惁鍚屾宸茶娉ㄥ叆鐨勮祫婧 + * @param name 璧勬簮鍚 + * @param rs 璧勬簮瀵硅薄 + * + * @return 鏃ц祫婧愬璞 + */ + public A register(final boolean autoSync, final String name, final A rs) { + checkResourceName(name); + final Class claz = rs.getClass(); + ResourceType rtype = claz.getAnnotation(ResourceType.class); + if (rtype == null) { + return (A) register(autoSync, name, claz, rs); + } else { + A old = null; + A t = (A) register(autoSync, name, rtype.value(), rs); + if (t != null) old = t; + return old; + } + } + + /** + * 灏嗗璞′互鎸囧畾璧勬簮鍚嶅拰绫诲瀷娉ㄥ叆鍒拌祫婧愭睜涓紝骞跺悓姝ュ凡琚敞鍏ョ殑璧勬簮 + * + * @param 娉涘瀷 + * @param name 璧勬簮鍚 + * @param clazz 璧勬簮绫诲瀷 + * @param rs 璧勬簮瀵硅薄 + * + * @return 鏃ц祫婧愬璞 + */ + public A register(final String name, final Class clazz, final A rs) { + return register(true, name, clazz, rs); + } + + /** + * 灏嗗璞′互鎸囧畾璧勬簮鍚嶅拰绫诲瀷娉ㄥ叆鍒拌祫婧愭睜涓紝骞跺悓姝ュ凡琚敞鍏ョ殑璧勬簮 + * + * @param 娉涘瀷 + * @param name 璧勬簮鍚 + * @param clazz 璧勬簮绫诲瀷 + * @param rs 璧勬簮瀵硅薄 + * + * @return 鏃ц祫婧愬璞 + */ + public A register(final String name, final Type clazz, final A rs) { + return register(true, name, clazz, rs); + } + + /** + * 灏嗗璞′互鎸囧畾璧勬簮鍚嶅拰绫诲瀷娉ㄥ叆鍒拌祫婧愭睜涓 + * + * @param 娉涘瀷 + * @param autoSync 鏄惁鍚屾宸茶娉ㄥ叆鐨勮祫婧 + * @param name 璧勬簮鍚 + * @param clazz 璧勬簮绫诲瀷 + * @param rs 璧勬簮瀵硅薄 + * + * @return 鏃ц祫婧愬璞 + */ + public A register(final boolean autoSync, final String name, final Type clazz, final A rs) { + checkResourceName(name); + ConcurrentHashMap map = this.store.get(clazz); + if (map == null) { + synchronized (clazz) { + map = this.store.get(clazz); + if (map == null) { + map = new ConcurrentHashMap(); + store.put(clazz, map); + } + } + } + ResourceEntry re = map.get(name); + if (re == null) { + map.put(name, new ResourceEntry(rs)); + } else { + map.put(name, new ResourceEntry(rs, name, re.elements, autoSync)); + } + return re == null ? null : (A) re.value; + } + + /** + * 鍒ゆ柇鏄惁鍖呭惈鎸囧畾璧勬簮鍚嶅拰璧勬簮绫诲瀷鐨勮祫婧愬璞 + * + * @param 娉涘瀷 + * @param recursive 鏄惁閬嶅巻鐖惰妭鐐 + * @param name 璧勬簮鍚 + * @param clazz 璧勬簮绫诲瀷 + * + * @return 鏄惁瀛樺湪 + */ + public boolean contains(boolean recursive, String name, Class clazz) { + Map map = this.store.get(clazz); + return map == null ? ((recursive && parent != null) ? parent.contains(recursive, name, clazz) : false) : map.containsKey(name); + } + + /** + * 鏌ユ壘鎸囧畾璧勬簮鍚嶅拰璧勬簮绫诲瀷鐨勮祫婧愬璞℃墍鍦ㄧ殑ResourceFactory锛 娌℃湁鍒欒繑鍥瀗ull + * + * @param name 璧勬簮鍚 + * @param clazz 璧勬簮绫诲瀷 + * + * @return ResourceFactory + */ + public ResourceFactory findResourceFactory(String name, Type clazz) { + Map map = this.store.get(clazz); + if (map != null && map.containsKey(name)) return this; + if (parent != null) return parent.findResourceFactory(name, clazz); + return null; + } + + public A find(Class clazz) { + return find("", clazz); + } + + public A find(String name, Type clazz) { + ResourceEntry re = findEntry(name, clazz); + return re == null ? null : (A) re.value; + } + + public A find(String name, Class clazz) { + ResourceEntry re = findEntry(name, clazz); + return re == null ? null : re.value; + } + + public A findChild(final String name, final Class clazz) { + A rs = find(name, clazz); + if (rs != null) return rs; + for (Map.Entry> en : this.store.entrySet()) { + if (!(en.getKey() instanceof Class)) continue; + if (!clazz.isAssignableFrom((Class) en.getKey())) continue; + ResourceEntry v = en.getValue().get(name); + if (v != null) return (A) v.value; + } + return null; + } + + private ResourceEntry findEntry(String name, Type clazz) { + Map map = this.store.get(clazz); + if (map != null) { + ResourceEntry re = map.get(name); + if (re != null) return re; + } + if (parent != null) return parent.findEntry(name, clazz); + return null; + } + + public List query(Class clazz) { + return query(new ArrayList<>(), clazz); + } + + public List query(Type clazz) { + return query(new ArrayList<>(), clazz); + } + + private List query(final List list, Type clazz) { + Map map = this.store.get(clazz); + if (map != null) { + for (ResourceEntry re : map.values()) { + if (re.value != null) list.add((A) re.value); + } + } + if (parent != null) parent.query(list, clazz); + return list; + } + + public List query(final BiPredicate predicate) { + return query(new ArrayList<>(), predicate); + } + + private List query(final List list, final BiPredicate predicate) { + if (predicate == null) return list; + for (ConcurrentHashMap map : this.store.values()) { + for (Map.Entry en : map.entrySet()) { + if (predicate.test(en.getKey(), en.getValue().value)) { + list.add((A) en.getValue().value); + } + } + } + if (parent != null) parent.query(list, predicate); + return list; + } + + private ResourceEntry findEntry(String name, Class clazz) { + Map map = this.store.get(clazz); + if (map != null) { + ResourceEntry rs = map.get(name); + if (rs != null) return rs; + } + if (parent != null) return parent.findEntry(name, clazz); + return null; + } + + public boolean inject(final Object src) { + return inject(src, null); + } + + public boolean inject(final Object src, final T attachment) { + return inject(src, attachment, null); + } + + public boolean inject(final Object src, final BiConsumer consumer) { + return inject(src, null, consumer); + } + + public boolean inject(final Object src, final T attachment, final BiConsumer consumer) { + return inject(src, attachment, consumer, new ArrayList()); + } + + public static String formatResourceName(String name) { + if (name == null) return null; + int pos = name.indexOf("{system.property."); + if (pos < 0) return name; + String prefix = name.substring(0, pos); + String subname = name.substring(pos + "{system.property.".length()); + pos = subname.lastIndexOf('}'); + if (pos < 0) return name; + String postfix = subname.substring(pos + 1); + String property = subname.substring(0, pos); + return formatResourceName(prefix + System.getProperty(property, "") + postfix); + } + + private boolean inject(final Object src, final T attachment, final BiConsumer consumer, final List list) { + if (src == null) return false; + try { + list.add(src); + Class clazz = src.getClass(); + final boolean diyloaderflag = !parentRoot().injectLoaderMap.isEmpty(); + do { + if (java.lang.Enum.class.isAssignableFrom(clazz)) break; + final String cname = clazz.getName(); + if (cname.startsWith("java.") || cname.startsWith("javax.") + || cname.startsWith("jdk.") || cname.startsWith("sun.")) break; + if (cname.indexOf('/') < 0) {//鎺掗櫎鍐呴儴绫伙紝 濡:JsonConvert$$Lambda$87/0x0000000100197440- + RedkaleClassLoader.putReflectionDeclaredFields(cname); + } + for (Field field : clazz.getDeclaredFields()) { + if (Modifier.isStatic(field.getModifiers())) continue; + field.setAccessible(true); + final Class classtype = field.getType(); + Resource rc = field.getAnnotation(Resource.class); + if (rc == null) { //娣卞害娉ㄥ叆 + if (Convert.class.isAssignableFrom(classtype)) continue; + if (ConvertFactory.class.isAssignableFrom(classtype)) continue; + if (ResourceFactory.class.isAssignableFrom(classtype)) continue; + boolean flag = true; //鏄惁娌℃湁閲嶅 + Object ns = field.get(src); + for (Object o : list) { + if (o == ns) { + flag = false; + break; + } + } + if (flag && diyloaderflag) { + parentRoot().injectLoaderMap.values().stream().forEach(iloader -> { + Annotation ann = field.getAnnotation(iloader.annotationType()); + if (ann == null) return; + iloader.load(this, src, ann, field, attachment); + }); + } + if (ns == null) continue; + final String nsname = ns.getClass().getName(); + if (ns.getClass().isPrimitive() || ns.getClass().isArray() + || nsname.startsWith("java.") || nsname.startsWith("javax.") + || nsname.startsWith("jdk.") || nsname.startsWith("sun.")) continue; + if (flag) this.inject(ns, attachment, consumer, list); + continue; + } + if (Modifier.isFinal(field.getModifiers())) continue; + RedkaleClassLoader.putReflectionField(cname, field); + final Type genctype = TypeToken.containsUnknownType(field.getGenericType()) + ? TypeToken.getGenericType(field.getGenericType(), src.getClass()) : field.getGenericType(); + if (consumer != null) consumer.accept(src, field); + String tname = rc.name(); + if (tname.contains(RESOURCE_PARENT_NAME)) { + Resource res = src.getClass().getAnnotation(Resource.class); + if (res == null) { + if (src instanceof Resourcable) { + tname = tname.replace(RESOURCE_PARENT_NAME, ((Resourcable) src).resourceName()); + } else { + logger.log(Level.SEVERE, src.getClass().getName() + " not found @Resource on Class or not implements Resourcable"); + } + } else { + tname = tname.replace(RESOURCE_PARENT_NAME, res.name()); + } + + } + boolean autoregnull = true; + final String rcname = formatResourceName(tname); + Object rs; + if (rcname.startsWith("system.property.")) { + rs = System.getProperty(rcname.substring("system.property.".length())); + } else { + ResourceEntry re = findEntry(rcname, genctype); + if (re == null) { + if (rcname.startsWith("property.")) { + re = findEntry(rcname, String.class); + } else { + re = findEntry(rcname, classtype); + } + } + if (re == null) { + ResourceLoader it = findLoader(genctype, field); + if (it != null) { + it.load(this, src, rcname, field, attachment); + autoregnull = it.autoNone(); + re = findEntry(rcname, genctype); + } + } + if (re == null && genctype != classtype) { + re = findEntry(rcname, classtype); + if (re == null) { + if (rcname.startsWith("property.")) { + re = findEntry(rcname, String.class); + } else { + re = findEntry(rcname, classtype); + } + } + if (re == null) { + ResourceLoader it = findLoader(classtype, field); + if (it != null) { + it.load(this, src, rcname, field, attachment); + autoregnull = it.autoNone(); + re = findEntry(rcname, classtype); + } + } + } + if (re == null && autoregnull) { + register(rcname, genctype, null); //鑷姩娉ㄥ叆null鐨勫 + re = findEntry(rcname, genctype); + } + if (re == null) continue; + re.elements.add(new ResourceElement<>(src, field)); + rs = re.value; + } + if (rs != null && !rs.getClass().isPrimitive() && classtype.isPrimitive()) { + if (classtype == int.class) { + rs = Integer.decode(rs.toString()); + } else if (classtype == long.class) { + rs = Long.decode(rs.toString()); + } else if (classtype == short.class) { + rs = Short.decode(rs.toString()); + } else if (classtype == boolean.class) { + rs = "true".equalsIgnoreCase(rs.toString()); + } else if (classtype == byte.class) { + rs = Byte.decode(rs.toString()); + } else if (classtype == float.class) { + rs = Float.parseFloat(rs.toString()); + } else if (classtype == double.class) { + rs = Double.parseDouble(rs.toString()); + } + } + if (rs != null) field.set(src, rs); + } + } while ((clazz = clazz.getSuperclass()) != Object.class); + return true; + } catch (Exception ex) { + logger.log(Level.SEVERE, "inject " + src + " error", ex); + return false; + } + } + + public void register(final ResourceInjectLoader loader) { + if (loader == null) return; + parentRoot().injectLoaderMap.put(loader.annotationType(), loader); + } + + public void register(final ResourceLoader rs, final Type... clazzs) { + if (clazzs == null || rs == null) return; + for (Type clazz : clazzs) { + resLoaderMap.put(clazz, rs); + } + } + + private ResourceFactory parentRoot() { + if (parent == null) return this; + return parent.parentRoot(); + } + + private ResourceLoader findMatchLoader(Type ft, Field field) { + ResourceLoader it = this.resLoaderMap.get(ft); + if (it == null && field != null) it = this.resLoaderMap.get(field.getType()); + if (it != null) return it; + return parent == null ? null : parent.findMatchLoader(ft, field); + } + + private ResourceLoader findRegxLoader(Type ft, Field field) { + if (field == null) return null; + Class c = field.getType(); + for (Map.Entry en : this.resLoaderMap.entrySet()) { + Type t = en.getKey(); + if (t == ft) return en.getValue(); + if (t instanceof Class && (((Class) t)).isAssignableFrom(c)) return en.getValue(); + } + return parent == null ? null : parent.findRegxLoader(ft, field); + } + + public ResourceLoader findLoader(Type ft, Field field) { + ResourceLoader it = this.findMatchLoader(ft, field); + return it == null ? findRegxLoader(ft, field) : it; + } + + private static class ResourceEntry { + + public final T value; + + public final List elements; + + public ResourceEntry(T value) { + this.value = value; + this.elements = new CopyOnWriteArrayList<>(); + } + + public ResourceEntry(T value, final String name, final List elements, boolean sync) { + this.value = value; + this.elements = elements == null ? new CopyOnWriteArrayList<>() : elements; + if (sync && elements != null && !elements.isEmpty()) { + + for (ResourceElement element : elements) { + Object dest = element.dest.get(); + if (dest == null) continue; + Object rs = value; + final Class classtype = element.fieldType; + if (rs != null && !rs.getClass().isPrimitive() && classtype.isPrimitive()) { + if (classtype == int.class) { + rs = Integer.decode(rs.toString()); + } else if (classtype == long.class) { + rs = Long.decode(rs.toString()); + } else if (classtype == short.class) { + rs = Short.decode(rs.toString()); + } else if (classtype == boolean.class) { + rs = "true".equalsIgnoreCase(rs.toString()); + } else if (classtype == byte.class) { + rs = Byte.decode(rs.toString()); + } else if (classtype == float.class) { + rs = Float.parseFloat(rs.toString()); + } else if (classtype == double.class) { + rs = Double.parseDouble(rs.toString()); + } + } + if (rs == null && classtype.isPrimitive()) rs = Array.get(Array.newInstance(classtype, 1), 0); + Object oldVal = null; + if (element.listener != null) { + try { + oldVal = element.field.get(dest); + } catch (Exception e) { + e.printStackTrace(); + } + } + try { + element.field.set(dest, rs); + } catch (Exception e) { + e.printStackTrace(); + } + if (element.listener != null) { + try { + element.listener.invoke(dest, name, rs, oldVal); + } catch (Exception e) { + logger.log(Level.SEVERE, dest + " resource change listener error", e); + } + } + } + } + } + } + + private static class ResourceElement { + + private static final HashMap listenerMethods = new HashMap<>(); //涓嶄娇鐢–oncurrentHashMap鏄洜涓簐alue涓嶈兘瀛榥ull + + public final WeakReference dest; + + public final Field field; //Resource 瀛楁 + + public final Class fieldType; + + public final Method listener; + + public ResourceElement(T dest, Field field) { + this.dest = new WeakReference(dest); + this.field = field; + this.fieldType = field.getType(); + Class t = dest.getClass(); + String tn = t.getName(); + this.listener = tn.startsWith("java.") || tn.startsWith("javax.") ? null : findListener(t, field.getType()); + } + + private static Method findListener(Class clazz, Class fieldType) { + synchronized (listenerMethods) { + Class loop = clazz; + Method m = listenerMethods.get(clazz.getName() + "-" + fieldType.getName()); + if (m != null) return m; + do { + RedkaleClassLoader.putReflectionDeclaredMethods(loop.getName()); + for (Method method : loop.getDeclaredMethods()) { + if (method.getAnnotation(ResourceListener.class) != null + && method.getParameterCount() == 3 + && String.class.isAssignableFrom(method.getParameterTypes()[0]) + && method.getParameterTypes()[1] == method.getParameterTypes()[2] + && method.getParameterTypes()[1].isAssignableFrom(fieldType)) { + m = method; + m.setAccessible(true); + RedkaleClassLoader.putReflectionMethod(loop.getName(), method); + break; + } + } + } while ((loop = loop.getSuperclass()) != Object.class); + listenerMethods.put(clazz.getName() + "-" + fieldType.getName(), m); + return m; + } + } + } + + @FunctionalInterface + public static interface ResourceLoader { + + public void load(ResourceFactory factory, Object src, String resourceName, Field field, Object attachment); + + // 杩斿洖true 琛ㄧず璋冪敤ResourceLoader涔嬪悗璧勬簮浠嶄笉瀛樺湪锛屽垯浼氬湪ResourceFactory閲屾敞鍏ラ粯璁ゅ糿ull锛岃繑鍥瀎alse琛ㄧず璧勬簮涓嶅瓨鍦ㄤ笅娆′粛浼氳皟鐢≧esourceLoader鑷澶勭悊 + default boolean autoNone() { + return true; + } + } + +} diff --git a/src/main/java/org/redkale/util/ResourceInjectLoader.java b/src/main/java/org/redkale/util/ResourceInjectLoader.java index d97f95ae8..26cd4ab54 100644 --- a/src/main/java/org/redkale/util/ResourceInjectLoader.java +++ b/src/main/java/org/redkale/util/ResourceInjectLoader.java @@ -1,25 +1,25 @@ -/* - * 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.util; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Field; - -/** - * 鑷畾涔夋敞鍏ュ姞杞藉櫒 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param Annotation - */ -public interface ResourceInjectLoader { - - public void load(ResourceFactory factory, Object src, T annotation, Field field, Object attachment); - - public Class annotationType(); -} +/* + * 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.util; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; + +/** + * 鑷畾涔夋敞鍏ュ姞杞藉櫒 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Annotation + */ +public interface ResourceInjectLoader { + + public void load(ResourceFactory factory, Object src, T annotation, Field field, Object attachment); + + public Class annotationType(); +} diff --git a/src/main/java/org/redkale/util/ResourceListener.java b/src/main/java/org/redkale/util/ResourceListener.java index dfdfaf654..e559baf0a 100644 --- a/src/main/java/org/redkale/util/ResourceListener.java +++ b/src/main/java/org/redkale/util/ResourceListener.java @@ -1,52 +1,52 @@ -/* - * 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.util; - -import java.lang.annotation.*; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * @Resource璧勬簮琚洿鏂版椂鐨勭洃鍚簨浠躲傛湰娉ㄨВ鍙兘鏍囪鍦ㄦ柟娉曞弬鏁颁负(String name, T newVal, T oldVal)涓娿 - * 鏂规硶鍦ㄨ祫婧愯鏇存柊浠ュ悗璋冪敤銆 - * - *

- * public class RecordService implements Service {
- *
- *    @Resource(name = "record.id")
- *    private int id;
- *
- *    @Resource(name = "record.name")
- *    private String name;
- *
- *    @ResourceListener
- *    private void changeResource(String name, Object newVal, Object oldVal) {
- *        System.out.println("@Resource = " + name + " 璧勬簮鍙樻洿:  newVal = " + newVal + ", oldVal = " + oldVal);
- *    }
- *
- *    public static void main(String[] args) throws Exception {
- *        ResourceFactory factory = ResourceFactory.root();
- *        factory.register("record.id", "2345"); 
- *        factory.register("record.name", "my old name"); 
- *        Record record = new Record();
- *        factory.inject(record);
- *        factory.register("record.name", "my new name"); 
- *   }
- * 
- * }
- * 
- * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@Documented -@Target({METHOD}) -@Retention(RUNTIME) -public @interface ResourceListener { - -} +/* + * 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.util; + +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * @Resource璧勬簮琚洿鏂版椂鐨勭洃鍚簨浠躲傛湰娉ㄨВ鍙兘鏍囪鍦ㄦ柟娉曞弬鏁颁负(String name, T newVal, T oldVal)涓娿 + * 鏂规硶鍦ㄨ祫婧愯鏇存柊浠ュ悗璋冪敤銆 + * + *

+ * public class RecordService implements Service {
+ *
+ *    @Resource(name = "record.id")
+ *    private int id;
+ *
+ *    @Resource(name = "record.name")
+ *    private String name;
+ *
+ *    @ResourceListener
+ *    private void changeResource(String name, Object newVal, Object oldVal) {
+ *        System.out.println("@Resource = " + name + " 璧勬簮鍙樻洿:  newVal = " + newVal + ", oldVal = " + oldVal);
+ *    }
+ *
+ *    public static void main(String[] args) throws Exception {
+ *        ResourceFactory factory = ResourceFactory.root();
+ *        factory.register("record.id", "2345"); 
+ *        factory.register("record.name", "my old name"); 
+ *        Record record = new Record();
+ *        factory.inject(record);
+ *        factory.register("record.name", "my new name"); 
+ *   }
+ * 
+ * }
+ * 
+ * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@Documented +@Target({METHOD}) +@Retention(RUNTIME) +public @interface ResourceListener { + +} diff --git a/src/main/java/org/redkale/util/ResourceType.java b/src/main/java/org/redkale/util/ResourceType.java index 7bc9f8a46..4c95150a2 100644 --- a/src/main/java/org/redkale/util/ResourceType.java +++ b/src/main/java/org/redkale/util/ResourceType.java @@ -1,29 +1,29 @@ -/* - * 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.util; - -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; -import java.lang.annotation.*; - -/** - * 鏄惧紡鐨勬寚鏄庤祫婧愮被鍨嬨 - * 璋冪敤ResourceFactory.register(Object rs)鏃堕氬父鎵ц鐨勬槸ResourceFactory.register(rs.getClass(), Object rs); - * 鑻s.getClass()鐨勭被鏍囪浜@ResourceType, 鍒欎娇鐢@ResourceType.value()鐨刢lass鍊艰繘琛屾敞鍏ャ - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -@Inherited -@Documented -@Target({TYPE}) -@Retention(RUNTIME) -public @interface ResourceType { - - Class value(); -} +/* + * 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.util; + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import java.lang.annotation.*; + +/** + * 鏄惧紡鐨勬寚鏄庤祫婧愮被鍨嬨 + * 璋冪敤ResourceFactory.register(Object rs)鏃堕氬父鎵ц鐨勬槸ResourceFactory.register(rs.getClass(), Object rs); + * 鑻s.getClass()鐨勭被鏍囪浜@ResourceType, 鍒欎娇鐢@ResourceType.value()鐨刢lass鍊艰繘琛屾敞鍏ャ + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +@Inherited +@Documented +@Target({TYPE}) +@Retention(RUNTIME) +public @interface ResourceType { + + Class value(); +} diff --git a/src/main/java/org/redkale/util/SelectColumn.java b/src/main/java/org/redkale/util/SelectColumn.java index ee6e4efef..c819e0449 100644 --- a/src/main/java/org/redkale/util/SelectColumn.java +++ b/src/main/java/org/redkale/util/SelectColumn.java @@ -1,222 +1,222 @@ -/* - * 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.util; - -import java.util.*; -import java.util.function.*; -import java.util.regex.*; - -/** - * 鍒ゆ柇瀛楃涓叉暟缁勬槸鍚﹀寘鍚垨鎺掗櫎鎸囧畾瀛楃涓茬殑鎿嶄綔绫 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public class SelectColumn implements Predicate { - - private Pattern[] patterns; - - private String[] columns; - - private boolean excludable; //鏄惁鎺掗櫎 - - public SelectColumn() { - } - - protected SelectColumn(final String[] columns0, final boolean excludable) { - this.excludable = excludable; - final int len = columns0.length; - if (len < 1) return; - Pattern[] regs = null; - String[] cols = null; - int regcount = 0; - int colcount = 0; - for (String col : columns0) { - boolean reg = false; - for (int i = 0; i < col.length(); i++) { - char ch = col.charAt(i); - if (ch == '^' || ch == '$' || ch == '*' || ch == '?' || ch == '+' || ch == '[' || ch == '(') { - reg = true; - break; - } - } - if (reg) { - if (regs == null) regs = new Pattern[len]; - regs[regcount++] = Pattern.compile(col); - } else { - if (cols == null) cols = new String[len]; - cols[colcount++] = col; - } - } - if (regs != null) { - if (regcount == len) { - this.patterns = regs; - } else { - this.patterns = Arrays.copyOf(regs, regcount); - } - } - if (cols != null) { - if (colcount == len) { - this.columns = cols; - } else { - this.columns = Arrays.copyOf(cols, colcount); - } - } - } - - /** - * class涓殑瀛楁鍚 - * - * @param columns 鍖呭惈鐨勫瓧娈靛悕闆嗗悎 - * - * @return SelectColumn - */ -// @Deprecated -// public static SelectColumn createIncludes(String... columns) { -// return new SelectColumn(columns, false); -// } - - /** - * class涓殑瀛楁鍚 - * - * @param columns 鍖呭惈鐨勫瓧娈靛悕闆嗗悎 - * - * @return SelectColumn - */ - public static SelectColumn includes(String... columns) { - return new SelectColumn(columns, false); - } - - /** - * class涓殑瀛楁鍚 - * - * @param cols 鍖呭惈鐨勫瓧娈靛悕闆嗗悎 - * @param columns 鍖呭惈鐨勫瓧娈靛悕闆嗗悎 - * - * @return SelectColumn - */ -// @Deprecated -// public static SelectColumn createIncludes(String[] cols, String... columns) { -// return new SelectColumn(Utility.append(cols, columns), false); -// } - - /** - * class涓殑瀛楁鍚 - * - * @param cols 鍖呭惈鐨勫瓧娈靛悕闆嗗悎 - * @param columns 鍖呭惈鐨勫瓧娈靛悕闆嗗悎 - * - * @return SelectColumn - */ - public static SelectColumn includes(String[] cols, String... columns) { - return new SelectColumn(Utility.append(cols, columns), false); - } - - /** - * - * class涓殑瀛楁鍚 - * - * @param columns 鎺掗櫎鐨勫瓧娈靛悕闆嗗悎 - * - * @return SelectColumn - */ -// @Deprecated -// public static SelectColumn createExcludes(String... columns) { -// return new SelectColumn(columns, true); -// } - - /** - * class涓殑瀛楁鍚 - * - * @param columns 鎺掗櫎鐨勫瓧娈靛悕闆嗗悎 - * - * @return SelectColumn - */ - public static SelectColumn excludes(String... columns) { - return new SelectColumn(columns, true); - } - - /** - * class涓殑瀛楁鍚 - * - * @param cols 鎺掗櫎鐨勫瓧娈靛悕闆嗗悎 - * @param columns 鎺掗櫎鐨勫瓧娈靛悕闆嗗悎 - * - * @return SelectColumn - */ -// @Deprecated -// public static SelectColumn createExcludes(String[] cols, String... columns) { -// return new SelectColumn(Utility.append(cols, columns), true); -// } - - /** - * - * class涓殑瀛楁鍚 - * - * @param cols 鎺掗櫎鐨勫瓧娈靛悕闆嗗悎 - * @param columns 鎺掗櫎鐨勫瓧娈靛悕闆嗗悎 - * - * @return SelectColumn - */ - public static SelectColumn excludes(String[] cols, String... columns) { - return new SelectColumn(Utility.append(cols, columns), true); - } - - public boolean isOnlyOneColumn() { - return !excludable && columns != null && columns.length == 1; - } - - @Override - public boolean test(final String column) { - if (this.columns != null) { - for (String col : this.columns) { - if (col.equalsIgnoreCase(column)) return !excludable; - } - } - if (this.patterns != null) { - for (Pattern reg : this.patterns) { - if (reg.matcher(column).find()) return !excludable; - } - } - return excludable; - } - - public String[] getColumns() { - return columns; - } - - public void setColumns(String[] columns) { - this.columns = columns; - } - - public boolean isExcludable() { - return excludable; - } - - public void setExcludable(boolean excludable) { - this.excludable = excludable; - } - - public Pattern[] getPatterns() { - return patterns; - } - - public void setPatterns(Pattern[] patterns) { - this.patterns = patterns; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append(getClass().getSimpleName()).append("{excludable=").append(excludable); - if (columns != null) sb.append(", columns=").append(Arrays.toString(columns)); - if (patterns != null) sb.append(", patterns=").append(Arrays.toString(patterns)); - return sb.append('}').toString(); - } - -} +/* + * 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.util; + +import java.util.*; +import java.util.function.*; +import java.util.regex.*; + +/** + * 鍒ゆ柇瀛楃涓叉暟缁勬槸鍚﹀寘鍚垨鎺掗櫎鎸囧畾瀛楃涓茬殑鎿嶄綔绫 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public class SelectColumn implements Predicate { + + private Pattern[] patterns; + + private String[] columns; + + private boolean excludable; //鏄惁鎺掗櫎 + + public SelectColumn() { + } + + protected SelectColumn(final String[] columns0, final boolean excludable) { + this.excludable = excludable; + final int len = columns0.length; + if (len < 1) return; + Pattern[] regs = null; + String[] cols = null; + int regcount = 0; + int colcount = 0; + for (String col : columns0) { + boolean reg = false; + for (int i = 0; i < col.length(); i++) { + char ch = col.charAt(i); + if (ch == '^' || ch == '$' || ch == '*' || ch == '?' || ch == '+' || ch == '[' || ch == '(') { + reg = true; + break; + } + } + if (reg) { + if (regs == null) regs = new Pattern[len]; + regs[regcount++] = Pattern.compile(col); + } else { + if (cols == null) cols = new String[len]; + cols[colcount++] = col; + } + } + if (regs != null) { + if (regcount == len) { + this.patterns = regs; + } else { + this.patterns = Arrays.copyOf(regs, regcount); + } + } + if (cols != null) { + if (colcount == len) { + this.columns = cols; + } else { + this.columns = Arrays.copyOf(cols, colcount); + } + } + } + + /** + * class涓殑瀛楁鍚 + * + * @param columns 鍖呭惈鐨勫瓧娈靛悕闆嗗悎 + * + * @return SelectColumn + */ +// @Deprecated +// public static SelectColumn createIncludes(String... columns) { +// return new SelectColumn(columns, false); +// } + + /** + * class涓殑瀛楁鍚 + * + * @param columns 鍖呭惈鐨勫瓧娈靛悕闆嗗悎 + * + * @return SelectColumn + */ + public static SelectColumn includes(String... columns) { + return new SelectColumn(columns, false); + } + + /** + * class涓殑瀛楁鍚 + * + * @param cols 鍖呭惈鐨勫瓧娈靛悕闆嗗悎 + * @param columns 鍖呭惈鐨勫瓧娈靛悕闆嗗悎 + * + * @return SelectColumn + */ +// @Deprecated +// public static SelectColumn createIncludes(String[] cols, String... columns) { +// return new SelectColumn(Utility.append(cols, columns), false); +// } + + /** + * class涓殑瀛楁鍚 + * + * @param cols 鍖呭惈鐨勫瓧娈靛悕闆嗗悎 + * @param columns 鍖呭惈鐨勫瓧娈靛悕闆嗗悎 + * + * @return SelectColumn + */ + public static SelectColumn includes(String[] cols, String... columns) { + return new SelectColumn(Utility.append(cols, columns), false); + } + + /** + * + * class涓殑瀛楁鍚 + * + * @param columns 鎺掗櫎鐨勫瓧娈靛悕闆嗗悎 + * + * @return SelectColumn + */ +// @Deprecated +// public static SelectColumn createExcludes(String... columns) { +// return new SelectColumn(columns, true); +// } + + /** + * class涓殑瀛楁鍚 + * + * @param columns 鎺掗櫎鐨勫瓧娈靛悕闆嗗悎 + * + * @return SelectColumn + */ + public static SelectColumn excludes(String... columns) { + return new SelectColumn(columns, true); + } + + /** + * class涓殑瀛楁鍚 + * + * @param cols 鎺掗櫎鐨勫瓧娈靛悕闆嗗悎 + * @param columns 鎺掗櫎鐨勫瓧娈靛悕闆嗗悎 + * + * @return SelectColumn + */ +// @Deprecated +// public static SelectColumn createExcludes(String[] cols, String... columns) { +// return new SelectColumn(Utility.append(cols, columns), true); +// } + + /** + * + * class涓殑瀛楁鍚 + * + * @param cols 鎺掗櫎鐨勫瓧娈靛悕闆嗗悎 + * @param columns 鎺掗櫎鐨勫瓧娈靛悕闆嗗悎 + * + * @return SelectColumn + */ + public static SelectColumn excludes(String[] cols, String... columns) { + return new SelectColumn(Utility.append(cols, columns), true); + } + + public boolean isOnlyOneColumn() { + return !excludable && columns != null && columns.length == 1; + } + + @Override + public boolean test(final String column) { + if (this.columns != null) { + for (String col : this.columns) { + if (col.equalsIgnoreCase(column)) return !excludable; + } + } + if (this.patterns != null) { + for (Pattern reg : this.patterns) { + if (reg.matcher(column).find()) return !excludable; + } + } + return excludable; + } + + public String[] getColumns() { + return columns; + } + + public void setColumns(String[] columns) { + this.columns = columns; + } + + public boolean isExcludable() { + return excludable; + } + + public void setExcludable(boolean excludable) { + this.excludable = excludable; + } + + public Pattern[] getPatterns() { + return patterns; + } + + public void setPatterns(Pattern[] patterns) { + this.patterns = patterns; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(getClass().getSimpleName()).append("{excludable=").append(excludable); + if (columns != null) sb.append(", columns=").append(Arrays.toString(columns)); + if (patterns != null) sb.append(", patterns=").append(Arrays.toString(patterns)); + return sb.append('}').toString(); + } + +} diff --git a/src/main/java/org/redkale/util/Sheet.java b/src/main/java/org/redkale/util/Sheet.java index 8c22d4d81..484a6bff0 100644 --- a/src/main/java/org/redkale/util/Sheet.java +++ b/src/main/java/org/redkale/util/Sheet.java @@ -1,154 +1,154 @@ -/* - * 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.util; - -import java.util.*; -import java.util.function.*; -import java.util.stream.*; -import org.redkale.convert.ConvertColumn; - -/** - * 椤甸泦鍚堛 缁撴瀯鐢变竴涓猼otal鎬绘暟鍜屼竴涓狶ist鍒楄〃缁勫悎鑰屾垚銆 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param 闆嗗悎鍏冪礌鐨勬暟鎹被鍨 - */ -@SuppressWarnings("unchecked") -public class Sheet implements java.io.Serializable, Iterable { - - @ConvertColumn(index = 1) - private long total = -1; - - @ConvertColumn(index = 2) - private Collection rows; - - public Sheet() { - super(); - } - - public Sheet(int total, Collection data) { - this((long) total, data); - } - - public Sheet(long total, Collection data) { - this.total = total; - this.rows = (Collection) data; - } - - public static Sheet asSheet(Collection data) { - return data == null ? new Sheet() : new Sheet(data.size(), data); - } - - public static Sheet empty() { - return new Sheet<>(); - } - - public Sheet copyTo(Sheet copy) { - if (copy == null) return copy; - copy.total = this.total; - if (this.getRows() != null) { - copy.setRows(new ArrayList(this.getRows())); - } else { - copy.rows = null; - } - return copy; - } - - /** - * 鍒ゆ柇鏁版嵁鍒楄〃鏄惁涓虹┖ - * - * @return 鏄惁涓虹┖ - */ - @ConvertColumn(index = 3) - public boolean isEmpty() { - return this.rows == null || this.rows.isEmpty(); - } - - @Override - public String toString() { - return "{\"total\":" + this.total + ", \"rows\":" + this.rows + "}"; - } - - public long getTotal() { - return this.total; - } - - public void setTotal(long total) { - this.total = total; - } - - public Collection getRows() { - return this.rows; - } - - public List list() { - return list(false); - } - - public List list(boolean created) { - if (this.rows == null) return created ? new ArrayList() : null; - return (this.rows instanceof List) ? (List) this.rows : new ArrayList(this.rows); - } - - public void setRows(Collection data) { - this.rows = (Collection) data; - } - - @Override - public Iterator iterator() { - return (this.rows == null) ? new ArrayList().iterator() : this.rows.iterator(); - } - - @Override - public void forEach(final Consumer consumer) { - if (consumer != null && this.rows != null && !this.rows.isEmpty()) { - this.rows.forEach(consumer); - } - } - - public Sheet map(Function mapper) { - if (this.isEmpty()) return (Sheet) this; - final List list = new ArrayList<>(); - for (T item : this.rows) { - list.add(mapper.apply(item)); - } - return new Sheet<>(getTotal(), list); - } - - public void forEachParallel(final Consumer consumer) { - if (consumer != null && this.rows != null && !this.rows.isEmpty()) { - this.rows.parallelStream().forEach(consumer); - } - } - - @Override - public Spliterator spliterator() { - return (this.rows == null) ? new ArrayList().spliterator() : this.rows.spliterator(); - } - - public Stream stream() { - return (this.rows == null) ? new ArrayList().stream() : this.rows.stream(); - } - - public Stream parallelStream() { - return (this.rows == null) ? new ArrayList().parallelStream() : this.rows.parallelStream(); - } - - public Object[] toArray() { - return (this.rows == null) ? new ArrayList().toArray() : this.rows.toArray(); - } - - public E[] toArray(E[] a) { - return (this.rows == null) ? new ArrayList().toArray(a) : this.rows.toArray(a); - } - - public E[] toArray(IntFunction generator) { - return (this.rows == null) ? new ArrayList().toArray(generator.apply(0)) : this.rows.toArray(generator.apply(this.rows.size())); - } -} +/* + * 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.util; + +import java.util.*; +import java.util.function.*; +import java.util.stream.*; +import org.redkale.convert.ConvertColumn; + +/** + * 椤甸泦鍚堛 缁撴瀯鐢变竴涓猼otal鎬绘暟鍜屼竴涓狶ist鍒楄〃缁勫悎鑰屾垚銆 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param 闆嗗悎鍏冪礌鐨勬暟鎹被鍨 + */ +@SuppressWarnings("unchecked") +public class Sheet implements java.io.Serializable, Iterable { + + @ConvertColumn(index = 1) + private long total = -1; + + @ConvertColumn(index = 2) + private Collection rows; + + public Sheet() { + super(); + } + + public Sheet(int total, Collection data) { + this((long) total, data); + } + + public Sheet(long total, Collection data) { + this.total = total; + this.rows = (Collection) data; + } + + public static Sheet asSheet(Collection data) { + return data == null ? new Sheet() : new Sheet(data.size(), data); + } + + public static Sheet empty() { + return new Sheet<>(); + } + + public Sheet copyTo(Sheet copy) { + if (copy == null) return copy; + copy.total = this.total; + if (this.getRows() != null) { + copy.setRows(new ArrayList(this.getRows())); + } else { + copy.rows = null; + } + return copy; + } + + /** + * 鍒ゆ柇鏁版嵁鍒楄〃鏄惁涓虹┖ + * + * @return 鏄惁涓虹┖ + */ + @ConvertColumn(index = 3) + public boolean isEmpty() { + return this.rows == null || this.rows.isEmpty(); + } + + @Override + public String toString() { + return "{\"total\":" + this.total + ", \"rows\":" + this.rows + "}"; + } + + public long getTotal() { + return this.total; + } + + public void setTotal(long total) { + this.total = total; + } + + public Collection getRows() { + return this.rows; + } + + public List list() { + return list(false); + } + + public List list(boolean created) { + if (this.rows == null) return created ? new ArrayList() : null; + return (this.rows instanceof List) ? (List) this.rows : new ArrayList(this.rows); + } + + public void setRows(Collection data) { + this.rows = (Collection) data; + } + + @Override + public Iterator iterator() { + return (this.rows == null) ? new ArrayList().iterator() : this.rows.iterator(); + } + + @Override + public void forEach(final Consumer consumer) { + if (consumer != null && this.rows != null && !this.rows.isEmpty()) { + this.rows.forEach(consumer); + } + } + + public Sheet map(Function mapper) { + if (this.isEmpty()) return (Sheet) this; + final List list = new ArrayList<>(); + for (T item : this.rows) { + list.add(mapper.apply(item)); + } + return new Sheet<>(getTotal(), list); + } + + public void forEachParallel(final Consumer consumer) { + if (consumer != null && this.rows != null && !this.rows.isEmpty()) { + this.rows.parallelStream().forEach(consumer); + } + } + + @Override + public Spliterator spliterator() { + return (this.rows == null) ? new ArrayList().spliterator() : this.rows.spliterator(); + } + + public Stream stream() { + return (this.rows == null) ? new ArrayList().stream() : this.rows.stream(); + } + + public Stream parallelStream() { + return (this.rows == null) ? new ArrayList().parallelStream() : this.rows.parallelStream(); + } + + public Object[] toArray() { + return (this.rows == null) ? new ArrayList().toArray() : this.rows.toArray(); + } + + public E[] toArray(E[] a) { + return (this.rows == null) ? new ArrayList().toArray(a) : this.rows.toArray(a); + } + + public E[] toArray(IntFunction generator) { + return (this.rows == null) ? new ArrayList().toArray(generator.apply(0)) : this.rows.toArray(generator.apply(this.rows.size())); + } +} diff --git a/src/main/java/org/redkale/util/StringWrapper.java b/src/main/java/org/redkale/util/StringWrapper.java index adf4c9728..207877f59 100644 --- a/src/main/java/org/redkale/util/StringWrapper.java +++ b/src/main/java/org/redkale/util/StringWrapper.java @@ -1,44 +1,44 @@ -/* - * 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.util; - -import java.io.Serializable; -import org.redkale.convert.ConvertColumn; - -/** - * 涓昏渚 JsonConvert.writeWrapper 浣跨敤 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public class StringWrapper implements Serializable { - - @ConvertColumn(index = 1) - protected String value; - - public StringWrapper() { - } - - public StringWrapper(String value) { - this.value = value; - } - - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } - - @Override - public String toString() { - return value; - } - -} +/* + * 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.util; + +import java.io.Serializable; +import org.redkale.convert.ConvertColumn; + +/** + * 涓昏渚 JsonConvert.writeWrapper 浣跨敤 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public class StringWrapper implements Serializable { + + @ConvertColumn(index = 1) + protected String value; + + public StringWrapper() { + } + + public StringWrapper(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } + +} diff --git a/src/main/java/org/redkale/util/ThreadHashExecutor.java b/src/main/java/org/redkale/util/ThreadHashExecutor.java index 257a13041..809ef4e54 100644 --- a/src/main/java/org/redkale/util/ThreadHashExecutor.java +++ b/src/main/java/org/redkale/util/ThreadHashExecutor.java @@ -1,177 +1,177 @@ -/* - * 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.util; - -import java.util.*; -import java.util.concurrent.*; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * 绾跨▼姹 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * - * @since 2.1.0 - */ -public class ThreadHashExecutor extends AbstractExecutorService { - - private final LinkedBlockingQueue[] queues; - - private final ThreadPoolExecutor[] executors; - - public ThreadHashExecutor() { - this(Utility.cpus(), null); - } - - public ThreadHashExecutor(int size) { - this(size, null); - } - - public ThreadHashExecutor(int size, ThreadFactory factory) { - ThreadPoolExecutor[] array = new ThreadPoolExecutor[size]; - LinkedBlockingQueue[] ques = new LinkedBlockingQueue[size]; - final AtomicInteger counter = new AtomicInteger(); - for (int i = 0; i < array.length; i++) { - LinkedBlockingQueue queue = new LinkedBlockingQueue<>(); - ques[i] = queue; - array[i] = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, queue, - factory == null ? (Runnable r) -> { - Thread t = new Thread(r); - t.setDaemon(true); - int c = counter.incrementAndGet(); - t.setName("Redkale-HashThread-" + (c > 9 ? c : ("0" + c))); - return t; - } : factory); - } - this.queues = ques; - this.executors = array; - } - - private ExecutorService hashExecutor(int hash) { - if (hash == 0) { - int k = 0; - int minsize = queues[0].size(); - for (int i = 1; i < queues.length; i++) { - int size = queues[i].size(); - if (size < minsize) { - minsize = size; - k = i; - } - } - return this.executors[k]; - } else { - return this.executors[(hash < 0 ? -hash : hash) % this.executors.length]; - } - } - - public void setThreadFactory(ThreadFactory factory) { - for (ThreadPoolExecutor executor : this.executors) { - executor.setThreadFactory(factory); - } - } - - public int size() { - return executors.length; - } - - @Override - public void execute(Runnable command) { - hashExecutor(0).execute(command); - } - - public void execute(int hash, Runnable command) { - hashExecutor(hash).execute(command); - } - - @Override - public Future submit(Runnable task) { - return hashExecutor(0).submit(task); - } - - public Future submit(int hash, Runnable task) { - return hashExecutor(hash).submit(task); - } - - @Override - public Future submit(Runnable task, T result) { - return hashExecutor(0).submit(task, result); - } - - public Future submit(int hash, Runnable task, T result) { - return hashExecutor(hash).submit(task, result); - } - - @Override - public Future submit(Callable task) { - return hashExecutor(0).submit(task); - } - - public Future submit(int hash, Callable task) { - return hashExecutor(hash).submit(task); - } - - public int waitingSize() { - int wsize = queues[0].size(); - for (int i = 1; i < queues.length; i++) { - wsize += queues[i].size(); - } - return wsize; - } - - @Override - public void shutdown() { - for (ExecutorService executor : this.executors) { - executor.shutdown(); - } - } - - @Override - public List shutdownNow() { - List list = new ArrayList<>(); - for (ExecutorService executor : this.executors) { - list.addAll(executor.shutdownNow()); - } - return list; - } - - @Override - public boolean isShutdown() { - return this.executors[0].isShutdown(); - } - - @Override - public boolean isTerminated() { - return this.executors[0].isTerminated(); - } - - @Override - public boolean awaitTermination(long l, TimeUnit tu) throws InterruptedException { - return this.executors[0].awaitTermination(l, tu); - } - - @Override - public T invokeAny(Collection> tasks) throws InterruptedException, ExecutionException { - return hashExecutor(0).invokeAny(tasks); - } - - @Override - public T invokeAny(Collection> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { - return hashExecutor(0).invokeAny(tasks, timeout, unit); - } - - @Override - public List> invokeAll(Collection> tasks) throws InterruptedException { - return hashExecutor(0).invokeAll(tasks); - } - - @Override - public List> invokeAll(Collection> tasks, long timeout, TimeUnit unit) throws InterruptedException { - return hashExecutor(0).invokeAll(tasks, timeout, unit); - } -} +/* + * 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.util; + +import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * 绾跨▼姹 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.1.0 + */ +public class ThreadHashExecutor extends AbstractExecutorService { + + private final LinkedBlockingQueue[] queues; + + private final ThreadPoolExecutor[] executors; + + public ThreadHashExecutor() { + this(Utility.cpus(), null); + } + + public ThreadHashExecutor(int size) { + this(size, null); + } + + public ThreadHashExecutor(int size, ThreadFactory factory) { + ThreadPoolExecutor[] array = new ThreadPoolExecutor[size]; + LinkedBlockingQueue[] ques = new LinkedBlockingQueue[size]; + final AtomicInteger counter = new AtomicInteger(); + for (int i = 0; i < array.length; i++) { + LinkedBlockingQueue queue = new LinkedBlockingQueue<>(); + ques[i] = queue; + array[i] = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, queue, + factory == null ? (Runnable r) -> { + Thread t = new Thread(r); + t.setDaemon(true); + int c = counter.incrementAndGet(); + t.setName("Redkale-HashThread-" + (c > 9 ? c : ("0" + c))); + return t; + } : factory); + } + this.queues = ques; + this.executors = array; + } + + private ExecutorService hashExecutor(int hash) { + if (hash == 0) { + int k = 0; + int minsize = queues[0].size(); + for (int i = 1; i < queues.length; i++) { + int size = queues[i].size(); + if (size < minsize) { + minsize = size; + k = i; + } + } + return this.executors[k]; + } else { + return this.executors[(hash < 0 ? -hash : hash) % this.executors.length]; + } + } + + public void setThreadFactory(ThreadFactory factory) { + for (ThreadPoolExecutor executor : this.executors) { + executor.setThreadFactory(factory); + } + } + + public int size() { + return executors.length; + } + + @Override + public void execute(Runnable command) { + hashExecutor(0).execute(command); + } + + public void execute(int hash, Runnable command) { + hashExecutor(hash).execute(command); + } + + @Override + public Future submit(Runnable task) { + return hashExecutor(0).submit(task); + } + + public Future submit(int hash, Runnable task) { + return hashExecutor(hash).submit(task); + } + + @Override + public Future submit(Runnable task, T result) { + return hashExecutor(0).submit(task, result); + } + + public Future submit(int hash, Runnable task, T result) { + return hashExecutor(hash).submit(task, result); + } + + @Override + public Future submit(Callable task) { + return hashExecutor(0).submit(task); + } + + public Future submit(int hash, Callable task) { + return hashExecutor(hash).submit(task); + } + + public int waitingSize() { + int wsize = queues[0].size(); + for (int i = 1; i < queues.length; i++) { + wsize += queues[i].size(); + } + return wsize; + } + + @Override + public void shutdown() { + for (ExecutorService executor : this.executors) { + executor.shutdown(); + } + } + + @Override + public List shutdownNow() { + List list = new ArrayList<>(); + for (ExecutorService executor : this.executors) { + list.addAll(executor.shutdownNow()); + } + return list; + } + + @Override + public boolean isShutdown() { + return this.executors[0].isShutdown(); + } + + @Override + public boolean isTerminated() { + return this.executors[0].isTerminated(); + } + + @Override + public boolean awaitTermination(long l, TimeUnit tu) throws InterruptedException { + return this.executors[0].awaitTermination(l, tu); + } + + @Override + public T invokeAny(Collection> tasks) throws InterruptedException, ExecutionException { + return hashExecutor(0).invokeAny(tasks); + } + + @Override + public T invokeAny(Collection> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { + return hashExecutor(0).invokeAny(tasks, timeout, unit); + } + + @Override + public List> invokeAll(Collection> tasks) throws InterruptedException { + return hashExecutor(0).invokeAll(tasks); + } + + @Override + public List> invokeAll(Collection> tasks, long timeout, TimeUnit unit) throws InterruptedException { + return hashExecutor(0).invokeAll(tasks, timeout, unit); + } +} diff --git a/src/main/java/org/redkale/util/TypeToken.java b/src/main/java/org/redkale/util/TypeToken.java index d8d0670b1..c370ec95e 100644 --- a/src/main/java/org/redkale/util/TypeToken.java +++ b/src/main/java/org/redkale/util/TypeToken.java @@ -1,543 +1,543 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ -package org.redkale.util; - -import java.lang.reflect.Type; -import java.lang.reflect.*; -import java.util.*; -import org.redkale.asm.*; -import static org.redkale.asm.ClassWriter.COMPUTE_FRAMES; -import static org.redkale.asm.Opcodes.*; - -/** - * - * 鑾峰彇娉涘瀷鐨凾ype绫 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - * @param 娉涘瀷 - */ -@SuppressWarnings("unchecked") -public abstract class TypeToken { - - private final Type type; - - public TypeToken() { - type = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; - } - - public final Type getType() { - return type; - } - - /** - * 鍒ゆ柇Type鏄惁鑳界‘瀹氭渶缁堢殑class锛 鏄垯杩斿洖true锛屽瓨鍦ㄩ氶厤绗︽垨鑰呬笉纭畾绫诲瀷鍒欒繑鍥瀎alse銆 - * 渚嬪: Map< String, String > 杩斿洖 ture; Map< ? extends Serializable, String > 杩斿洖false; - * - * @param type Type瀵硅薄 - * - * @return 鏄惁鍙弽瑙f瀽 - */ - public final static boolean isClassType(final Type type) { - if (type instanceof Class) return true; - if (type instanceof WildcardType) return false; - if (type instanceof TypeVariable) return false; - if (type instanceof GenericArrayType) return isClassType(((GenericArrayType) type).getGenericComponentType()); - if (!(type instanceof ParameterizedType)) return false; //鍙兘鏄痭ull浜 - final ParameterizedType ptype = (ParameterizedType) type; - if (ptype.getOwnerType() != null && !isClassType(ptype.getOwnerType())) return false; - if (!isClassType(ptype.getRawType())) return false; - for (Type t : ptype.getActualTypeArguments()) { - if (!isClassType(t)) return false; - } - return true; - } - - public final static boolean containsUnknownType(final Type type) { - if (type == null) return false; - if (type instanceof Class) return false; - if (type instanceof WildcardType) return true; - if (type instanceof TypeVariable) return true; - if (type instanceof GenericArrayType) return containsUnknownType(((GenericArrayType) type).getGenericComponentType()); - if (type instanceof ParameterizedType) { - ParameterizedType pt = (ParameterizedType) type; - if (containsUnknownType(pt.getRawType())) return true; - if (containsUnknownType(pt.getOwnerType())) return true; - Type[] ts = pt.getActualTypeArguments(); - if (ts != null) { - for (Type t : ts) { - if (containsUnknownType(t)) return true; - } - } - return false; - } - return true; - } - - public final static Class typeToClass(final Type type) { - if (type instanceof Class) return (Class) type; - if (type instanceof WildcardType) return null; - if (type instanceof TypeVariable) return null; - if (type instanceof GenericArrayType) return Array.newInstance(typeToClass(((GenericArrayType) type).getGenericComponentType()), 0).getClass(); - if (!(type instanceof ParameterizedType)) return null; //鍙兘鏄痭ull浜 - Type owner = ((ParameterizedType) type).getOwnerType(); - Type raw = ((ParameterizedType) type).getRawType(); - //A$B owner=A raw=A$B, 鎵浠ュ唴閮ㄧ被鎯呭喌涓嬩娇鐢╫wner鏄敊璇殑 - return typeToClass(raw != null ? raw : owner); - } - - public final static Class typeToClassOrElse(final Type type, final Class defClass) { - Class clazz = typeToClass(type); - return clazz == null ? defClass : clazz; - } - - public static Type[] getGenericType(final Type[] types, final Type declaringClass) { - Type[] newTypes = new Type[types.length]; - for (int i = 0; i < newTypes.length; i++) { - newTypes[i] = getGenericType(types[i], declaringClass); - } - return newTypes; - } -// -// public static void main(String[] args) throws Throwable { -// Method tt0 = C.class.getMethod("getValue"); -// System.out.println("tt0.type=" + tt0.getReturnType() + "======" + tt0.getGenericReturnType() + "======" + getGenericType(tt0.getGenericReturnType(), C.class)); -// -// Method tt3 = C.class.getMethod("getValue3"); -// System.out.println("tt3.type=" + tt3.getReturnType() + "======" + tt3.getGenericReturnType() + "======" + getGenericType(tt3.getGenericReturnType(), C.class)); -// -// Method ttr = AGameService.class.getMethod("getResult"); -// System.out.println("ttr.type=" + ttr.getReturnType() + "======" + ttr.getGenericReturnType() + "======" + getGenericType(ttr.getGenericReturnType(), AGameService.class)); -// System.out.println("ttr.搴旇鏄: List, 缁撴灉鏄: " + getGenericType(ttr.getGenericReturnType(), AGameService.class)); -// } -// -// public static class GamePlayer { -// } -// -// public static class GameTable

{ -// } -// -// public static class GameService { -// -// } -// -// public static class AbstractGamePlayer extends GamePlayer { -// } -// -// public static class AbstractGameTable

extends GameTable

{ -// } -// -// public static class AbstractGameService, P extends AbstractGamePlayer> extends GameService { -// -// public List getResult() { -// return null; -// } -// } -// -// public static class IGamePlayer extends AbstractGamePlayer { -// } -// -// public static class IGameTable

extends AbstractGameTable

{ -// } -// -// public static class IGameService, P extends IGamePlayer> extends AbstractGameService { -// -// } -// -// public static class AGamePlayer extends IGamePlayer { -// } -// -// public static class AGameTable extends IGameTable { -// } -// -// public static class AGameService extends IGameService { -// -// } -// -// public static class A { -// -// public List getValue() { -// return null; -// } -// -// public T getValue3() { -// return null; -// } -// } -// -// public static class B extends A { -// } -// -// public static class C extends B { -// } - - /** - * 鑾峰彇TypeVariable瀵瑰簲鐨勫疄闄匱ype, 濡傛灉type涓嶆槸TypeVariable 鐩存帴杩斿洖type銆 - *

-     *  public abstract class Key {
-     *  }
-     *  public abstract class Val {
-     *  }
-     *  public abstract class AService <K extends Key, V extends Val> {
-     *       public abstract V findValue(K key);
-     *       public abstract Sheet<V> queryValue(K key);
-     *  }
-     *  public class Key2 extends Key {
-     *  }
-     *  public class Val2 extends Val {
-     *  }
-     *  public class Service2 extends Service <Key2, Val2> {
-     *       public Val2 findValue(Key2 key){
-     *          return new Val2();
-     *       }
-     *       public Sheet<Val2> queryValue(Key2 key){
-     *          return new Sheet();
-     *       }
-     *  }
-     * 
- * - * - * @param type 娉涘瀷 - * @param declaringClass 娉涘瀷渚濋檮绫 - * - * @return Type - */ - public static Type getGenericType(final Type type, final Type declaringClass) { - if (type == null || declaringClass == null) return type; - if (type instanceof TypeVariable) { - Type superType = null; - Class declaringClass0 = null; - if (declaringClass instanceof Class) { - declaringClass0 = (Class) declaringClass; - superType = declaringClass0.getGenericSuperclass(); - if (superType instanceof ParameterizedType) { - Map map = new HashMap<>(); - parseType(map, declaringClass0); - Type rstype = getType(map, type); - if (rstype instanceof Class) return rstype; - } - while (superType instanceof Class && superType != Object.class) superType = ((Class) superType).getGenericSuperclass(); - } else if (declaringClass instanceof ParameterizedType) { - superType = declaringClass; - Type rawType = ((ParameterizedType) declaringClass).getRawType(); - if (rawType instanceof Class) declaringClass0 = (Class) rawType; - } - if (declaringClass0 != null && superType instanceof ParameterizedType) { - ParameterizedType superPT = (ParameterizedType) superType; - Type[] atas = superPT.getActualTypeArguments(); - Class ss = declaringClass0; - TypeVariable[] asts = ss.getTypeParameters(); - while (atas.length != asts.length && ss != Object.class) { - ss = ss.getSuperclass(); - asts = ss.getTypeParameters(); - } - - if (atas.length == asts.length) { - for (int i = 0; i < asts.length; i++) { - Type currt = asts[i]; - if (asts[i] != type && superPT.getRawType() instanceof Class) { - if (asts[i] instanceof TypeVariable) { - - Class raw = (Class) superPT.getRawType(); - do { - Type rawsuper = raw.getGenericSuperclass(); - if (!(rawsuper instanceof ParameterizedType)) break; - ParameterizedType rpt = (ParameterizedType) rawsuper; - Type supraw = rpt.getRawType(); - if (!(supraw instanceof Class)) break; - Type[] tps = ((Class) supraw).getTypeParameters(); - if (rpt.getActualTypeArguments().length == tps.length) { - for (int k = 0; k < rpt.getActualTypeArguments().length; k++) { - if (rpt.getActualTypeArguments()[k] == currt) { - currt = tps[k]; - break; - } - } - } - Type rtrt = rpt.getRawType(); - if (!(rtrt instanceof Class)) break; - raw = (Class) rtrt; - } while (raw != Object.class); - } - } - if (currt == type) { - if (atas[i] instanceof Class - && ((TypeVariable) type).getBounds().length == 1 - && ((TypeVariable) type).getBounds()[0] instanceof Class - && ((Class) ((TypeVariable) type).getBounds()[0]).isAssignableFrom((Class) atas[i])) - return atas[i]; - if (atas[i] instanceof Class - && ((TypeVariable) type).getBounds().length == 1 - && ((TypeVariable) type).getBounds()[0] instanceof ParameterizedType) { - ParameterizedType pt = (ParameterizedType) ((TypeVariable) type).getBounds()[0]; - if (pt.getRawType() instanceof Class && ((Class) pt.getRawType()).isAssignableFrom((Class) atas[i])) { - return atas[i]; - } - } - if (atas[i] instanceof ParameterizedType - && ((TypeVariable) type).getBounds().length == 1 - && ((TypeVariable) type).getBounds()[0] == Object.class) - return atas[i]; - } - } - ParameterizedType cycType = superPT; - if (cycType.getRawType() instanceof Class) { - TypeVariable[] argTypes = ((Class) cycType.getRawType()).getTypeParameters(); - if (argTypes.length == asts.length) { - for (int i = 0; i < argTypes.length; i++) { - if (argTypes[i] == type) { - if (atas[i] instanceof TypeVariable - && ((TypeVariable) atas[i]).getBounds().length == 1 - && ((TypeVariable) atas[i]).getBounds()[0] instanceof Class) - return ((Class) ((TypeVariable) atas[i]).getBounds()[0]); - } - } - } - } - } - Type moreType = ((ParameterizedType) superType).getRawType(); - if (moreType != Object.class) return getGenericType(type, moreType); - } - TypeVariable tv = (TypeVariable) type; - if (tv.getBounds().length == 1) return tv.getBounds()[0]; - } else if (type instanceof GenericArrayType) { - final Type rst = getGenericType(((GenericArrayType) type).getGenericComponentType(), declaringClass); - return (GenericArrayType) () -> rst; - } - if (type instanceof ParameterizedType) { - ParameterizedType pt = (ParameterizedType) type; - return createParameterizedType(getGenericType(pt.getOwnerType(), declaringClass), - getGenericType(pt.getRawType(), declaringClass), - getGenericType(pt.getActualTypeArguments(), declaringClass)); - } - return type; - } - - private static Type getType(Map map, Type type) { - Type one = map.get(type); - if (one == null) return type; - return getType(map, one); - } - - private static Map parseType(Map map, Class clzz) { - if (clzz == Object.class) return map; - Type superType = clzz.getGenericSuperclass(); - if (!(superType instanceof ParameterizedType)) return map; - ParameterizedType pt = (ParameterizedType) superType; - Type[] ptt = pt.getActualTypeArguments(); - Type superRaw = pt.getRawType(); - if (!(superRaw instanceof Class)) return map; - Class superClazz = (Class) superRaw; - TypeVariable[] scs = superClazz.getTypeParameters(); - if (scs.length != ptt.length) return map; - for (int i = 0; i < scs.length; i++) { - if (scs[i] == ptt[i]) continue; - map.put(scs[i], ptt[i]); - } - return parseType(map, clzz.getSuperclass()); - } - - /** - * 鍔ㄦ佸垱寤虹被鍨嬩负ParameterizedType鎴朇lass鐨凾ype - * - * @param type 褰撳墠娉涘瀷 - * @param declaringType0 瀛愮被 - * - * @return Type - */ - public static Type createClassType(final Type type, final Type declaringType0) { - if (isClassType(type)) return type; - if (type instanceof ParameterizedType) { // e.g. Map - final ParameterizedType pt = (ParameterizedType) type; - final Type[] paramTypes = pt.getActualTypeArguments(); - for (int i = 0; i < paramTypes.length; i++) { - paramTypes[i] = createClassType(paramTypes[i], declaringType0); - } - return createParameterizedType(pt.getOwnerType(), pt.getRawType(), paramTypes); - } - Type declaringType = declaringType0; - if (declaringType instanceof Class) { - do { - declaringType = ((Class) declaringType).getGenericSuperclass(); - if (declaringType == Object.class) return Object.class; - } while (declaringType instanceof Class); - } - //瀛樺湪閫氶厤绗﹀垯declaringType 蹇呴』鏄 ParameterizedType - if (!(declaringType instanceof ParameterizedType)) return Object.class; - final ParameterizedType declaringPType = (ParameterizedType) declaringType; - final Type[] virTypes = ((Class) declaringPType.getRawType()).getTypeParameters(); - final Type[] desTypes = declaringPType.getActualTypeArguments(); - if (type instanceof WildcardType) { // e.g. - final WildcardType wt = (WildcardType) type; - for (Type f : wt.getUpperBounds()) { - for (int i = 0; i < virTypes.length; i++) { - if (virTypes[i].equals(f)) return desTypes.length <= i ? Object.class : desTypes[i]; - } - } - } else if (type instanceof TypeVariable) { // e.g. - for (int i = 0; i < virTypes.length; i++) { - if (virTypes[i].equals(type)) return desTypes.length <= i ? Object.class : desTypes[i]; - } - } - return type; - } - - /** - * 鍔ㄦ佸垱寤 ParameterizedType - * - * @param ownerType0 ParameterizedType 鐨 ownerType - * @param rawType0 ParameterizedType 鐨 rawType - * @param actualTypeArguments0 ParameterizedType 鐨 actualTypeArguments - * - * @return Type - */ - public static Type createParameterizedType(final Type ownerType0, final Type rawType0, final Type... actualTypeArguments0) { - if (ownerType0 == null && rawType0 instanceof Class) { - int count = 0; - for (Type t : actualTypeArguments0) { - if (isClassType(t)) count++; - } - if (count == actualTypeArguments0.length) return createParameterizedType0((Class) rawType0, actualTypeArguments0); - } - return new ParameterizedType() { - private final Class rawType = (Class) rawType0; - - private final Type ownerType = ownerType0; - - private final Type[] actualTypeArguments = actualTypeArguments0; - - @Override - public Type[] getActualTypeArguments() { - return actualTypeArguments.clone(); - } - - @Override - public Type getRawType() { - return rawType; - } - - @Override - public Type getOwnerType() { - return ownerType; - } - - @Override - public int hashCode() { - return Arrays.hashCode(actualTypeArguments) ^ Objects.hashCode(rawType) ^ Objects.hashCode(ownerType); - } - - @Override - public boolean equals(Object o) { - if (!(o instanceof ParameterizedType)) return false; - final ParameterizedType that = (ParameterizedType) o; - if (this == that) return true; - return Objects.equals(ownerType, that.getOwnerType()) - && Objects.equals(rawType, that.getRawType()) - && Arrays.equals(actualTypeArguments, that.getActualTypeArguments()); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - if (ownerType != null) sb.append((ownerType instanceof Class) ? (((Class) ownerType).getName()) : ownerType.toString()).append("."); - sb.append(rawType.getName()); - - if (actualTypeArguments != null && actualTypeArguments.length > 0) { - sb.append("<"); - boolean first = true; - for (Type t : actualTypeArguments) { - if (!first) sb.append(", "); - sb.append(t); - first = false; - } - sb.append(">"); - } - return sb.toString(); - } - }; - } - - // 娉ㄦ剰: RetResult[]> 杩欑娉涘瀷甯]鐨勫皻鏈疄鐜版敮鎸 - private static synchronized Type createParameterizedType0(final Class rawType, final Type... actualTypeArguments) { - ClassLoader loader = Thread.currentThread().getContextClassLoader(); - StringBuilder tmpps = new StringBuilder(getClassTypeDescriptor(rawType)); - for (Type cz : actualTypeArguments) { - tmpps.append(" ").append(getClassTypeDescriptor(cz)); - } - StringBuilder nsb = new StringBuilder(); - for (char ch : tmpps.toString().toCharArray()) { - if (ch >= '0' && ch <= '9') { - nsb.append(ch); - } else if (ch >= 'a' && ch <= 'z') { - nsb.append(ch); - } else if (ch >= 'A' && ch <= 'Z') { - nsb.append(ch); - } else { - nsb.append('_'); - } - } - nsb.append("_GenericType"); - final String newDynName = "org/redkaledyn/typetoken/_Dyn" + TypeToken.class.getSimpleName() + "_" + nsb.toString(); - try { - return loader.loadClass(newDynName.replace('/', '.')).getField("field").getGenericType(); - } catch (Throwable ex) { - } - // ------------------------------------------------------------------------------ - ClassWriter cw = new ClassWriter(COMPUTE_FRAMES); - FieldVisitor fv; - MethodVisitor mv; - cw.visit(V11, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, null, "java/lang/Object", null); - String rawTypeDesc = org.redkale.asm.Type.getDescriptor(rawType); - StringBuilder sb = new StringBuilder(); - sb.append(rawTypeDesc.substring(0, rawTypeDesc.length() - 1)).append('<'); - for (Type c : actualTypeArguments) { - sb.append(getClassTypeDescriptor(c)); - } - sb.append(">;"); - { - fv = cw.visitField(ACC_PUBLIC, "field", rawTypeDesc, sb.toString(), null); - fv.visitEnd(); - } - {//鏋勯犳柟娉 - mv = cw.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(); - } - 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); - RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, newClazz); - RedkaleClassLoader.putReflectionPublicFields(newDynName.replace('/', '.')); - try { - return newClazz.getField("field").getGenericType(); - } catch (Exception ex) { - throw new RuntimeException(ex); - } - } - - private static CharSequence getClassTypeDescriptor(Type type) { - if (!isClassType(type)) throw new IllegalArgumentException(type + " not a class type"); - if (type instanceof Class) return org.redkale.asm.Type.getDescriptor((Class) type); - if (type instanceof GenericArrayType) return getClassTypeDescriptor(((GenericArrayType) type).getGenericComponentType()) + "[]"; - final ParameterizedType pt = (ParameterizedType) type; - CharSequence rawTypeDesc = getClassTypeDescriptor(pt.getRawType()); - StringBuilder sb = new StringBuilder(); - sb.append(rawTypeDesc.subSequence(0, rawTypeDesc.length() - 1)).append('<'); - for (Type c : pt.getActualTypeArguments()) { - sb.append(getClassTypeDescriptor(c)); - } - sb.append(">;"); - return sb; - } -} +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.util; + +import java.lang.reflect.Type; +import java.lang.reflect.*; +import java.util.*; +import org.redkale.asm.*; +import static org.redkale.asm.ClassWriter.COMPUTE_FRAMES; +import static org.redkale.asm.Opcodes.*; + +/** + * + * 鑾峰彇娉涘瀷鐨凾ype绫 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param 娉涘瀷 + */ +@SuppressWarnings("unchecked") +public abstract class TypeToken { + + private final Type type; + + public TypeToken() { + type = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; + } + + public final Type getType() { + return type; + } + + /** + * 鍒ゆ柇Type鏄惁鑳界‘瀹氭渶缁堢殑class锛 鏄垯杩斿洖true锛屽瓨鍦ㄩ氶厤绗︽垨鑰呬笉纭畾绫诲瀷鍒欒繑鍥瀎alse銆 + * 渚嬪: Map< String, String > 杩斿洖 ture; Map< ? extends Serializable, String > 杩斿洖false; + * + * @param type Type瀵硅薄 + * + * @return 鏄惁鍙弽瑙f瀽 + */ + public final static boolean isClassType(final Type type) { + if (type instanceof Class) return true; + if (type instanceof WildcardType) return false; + if (type instanceof TypeVariable) return false; + if (type instanceof GenericArrayType) return isClassType(((GenericArrayType) type).getGenericComponentType()); + if (!(type instanceof ParameterizedType)) return false; //鍙兘鏄痭ull浜 + final ParameterizedType ptype = (ParameterizedType) type; + if (ptype.getOwnerType() != null && !isClassType(ptype.getOwnerType())) return false; + if (!isClassType(ptype.getRawType())) return false; + for (Type t : ptype.getActualTypeArguments()) { + if (!isClassType(t)) return false; + } + return true; + } + + public final static boolean containsUnknownType(final Type type) { + if (type == null) return false; + if (type instanceof Class) return false; + if (type instanceof WildcardType) return true; + if (type instanceof TypeVariable) return true; + if (type instanceof GenericArrayType) return containsUnknownType(((GenericArrayType) type).getGenericComponentType()); + if (type instanceof ParameterizedType) { + ParameterizedType pt = (ParameterizedType) type; + if (containsUnknownType(pt.getRawType())) return true; + if (containsUnknownType(pt.getOwnerType())) return true; + Type[] ts = pt.getActualTypeArguments(); + if (ts != null) { + for (Type t : ts) { + if (containsUnknownType(t)) return true; + } + } + return false; + } + return true; + } + + public final static Class typeToClass(final Type type) { + if (type instanceof Class) return (Class) type; + if (type instanceof WildcardType) return null; + if (type instanceof TypeVariable) return null; + if (type instanceof GenericArrayType) return Array.newInstance(typeToClass(((GenericArrayType) type).getGenericComponentType()), 0).getClass(); + if (!(type instanceof ParameterizedType)) return null; //鍙兘鏄痭ull浜 + Type owner = ((ParameterizedType) type).getOwnerType(); + Type raw = ((ParameterizedType) type).getRawType(); + //A$B owner=A raw=A$B, 鎵浠ュ唴閮ㄧ被鎯呭喌涓嬩娇鐢╫wner鏄敊璇殑 + return typeToClass(raw != null ? raw : owner); + } + + public final static Class typeToClassOrElse(final Type type, final Class defClass) { + Class clazz = typeToClass(type); + return clazz == null ? defClass : clazz; + } + + public static Type[] getGenericType(final Type[] types, final Type declaringClass) { + Type[] newTypes = new Type[types.length]; + for (int i = 0; i < newTypes.length; i++) { + newTypes[i] = getGenericType(types[i], declaringClass); + } + return newTypes; + } +// +// public static void main(String[] args) throws Throwable { +// Method tt0 = C.class.getMethod("getValue"); +// System.out.println("tt0.type=" + tt0.getReturnType() + "======" + tt0.getGenericReturnType() + "======" + getGenericType(tt0.getGenericReturnType(), C.class)); +// +// Method tt3 = C.class.getMethod("getValue3"); +// System.out.println("tt3.type=" + tt3.getReturnType() + "======" + tt3.getGenericReturnType() + "======" + getGenericType(tt3.getGenericReturnType(), C.class)); +// +// Method ttr = AGameService.class.getMethod("getResult"); +// System.out.println("ttr.type=" + ttr.getReturnType() + "======" + ttr.getGenericReturnType() + "======" + getGenericType(ttr.getGenericReturnType(), AGameService.class)); +// System.out.println("ttr.搴旇鏄: List, 缁撴灉鏄: " + getGenericType(ttr.getGenericReturnType(), AGameService.class)); +// } +// +// public static class GamePlayer { +// } +// +// public static class GameTable

{ +// } +// +// public static class GameService { +// +// } +// +// public static class AbstractGamePlayer extends GamePlayer { +// } +// +// public static class AbstractGameTable

extends GameTable

{ +// } +// +// public static class AbstractGameService, P extends AbstractGamePlayer> extends GameService { +// +// public List getResult() { +// return null; +// } +// } +// +// public static class IGamePlayer extends AbstractGamePlayer { +// } +// +// public static class IGameTable

extends AbstractGameTable

{ +// } +// +// public static class IGameService, P extends IGamePlayer> extends AbstractGameService { +// +// } +// +// public static class AGamePlayer extends IGamePlayer { +// } +// +// public static class AGameTable extends IGameTable { +// } +// +// public static class AGameService extends IGameService { +// +// } +// +// public static class A { +// +// public List getValue() { +// return null; +// } +// +// public T getValue3() { +// return null; +// } +// } +// +// public static class B extends A { +// } +// +// public static class C extends B { +// } + + /** + * 鑾峰彇TypeVariable瀵瑰簲鐨勫疄闄匱ype, 濡傛灉type涓嶆槸TypeVariable 鐩存帴杩斿洖type銆 + *

+     *  public abstract class Key {
+     *  }
+     *  public abstract class Val {
+     *  }
+     *  public abstract class AService <K extends Key, V extends Val> {
+     *       public abstract V findValue(K key);
+     *       public abstract Sheet<V> queryValue(K key);
+     *  }
+     *  public class Key2 extends Key {
+     *  }
+     *  public class Val2 extends Val {
+     *  }
+     *  public class Service2 extends Service <Key2, Val2> {
+     *       public Val2 findValue(Key2 key){
+     *          return new Val2();
+     *       }
+     *       public Sheet<Val2> queryValue(Key2 key){
+     *          return new Sheet();
+     *       }
+     *  }
+     * 
+ * + * + * @param type 娉涘瀷 + * @param declaringClass 娉涘瀷渚濋檮绫 + * + * @return Type + */ + public static Type getGenericType(final Type type, final Type declaringClass) { + if (type == null || declaringClass == null) return type; + if (type instanceof TypeVariable) { + Type superType = null; + Class declaringClass0 = null; + if (declaringClass instanceof Class) { + declaringClass0 = (Class) declaringClass; + superType = declaringClass0.getGenericSuperclass(); + if (superType instanceof ParameterizedType) { + Map map = new HashMap<>(); + parseType(map, declaringClass0); + Type rstype = getType(map, type); + if (rstype instanceof Class) return rstype; + } + while (superType instanceof Class && superType != Object.class) superType = ((Class) superType).getGenericSuperclass(); + } else if (declaringClass instanceof ParameterizedType) { + superType = declaringClass; + Type rawType = ((ParameterizedType) declaringClass).getRawType(); + if (rawType instanceof Class) declaringClass0 = (Class) rawType; + } + if (declaringClass0 != null && superType instanceof ParameterizedType) { + ParameterizedType superPT = (ParameterizedType) superType; + Type[] atas = superPT.getActualTypeArguments(); + Class ss = declaringClass0; + TypeVariable[] asts = ss.getTypeParameters(); + while (atas.length != asts.length && ss != Object.class) { + ss = ss.getSuperclass(); + asts = ss.getTypeParameters(); + } + + if (atas.length == asts.length) { + for (int i = 0; i < asts.length; i++) { + Type currt = asts[i]; + if (asts[i] != type && superPT.getRawType() instanceof Class) { + if (asts[i] instanceof TypeVariable) { + + Class raw = (Class) superPT.getRawType(); + do { + Type rawsuper = raw.getGenericSuperclass(); + if (!(rawsuper instanceof ParameterizedType)) break; + ParameterizedType rpt = (ParameterizedType) rawsuper; + Type supraw = rpt.getRawType(); + if (!(supraw instanceof Class)) break; + Type[] tps = ((Class) supraw).getTypeParameters(); + if (rpt.getActualTypeArguments().length == tps.length) { + for (int k = 0; k < rpt.getActualTypeArguments().length; k++) { + if (rpt.getActualTypeArguments()[k] == currt) { + currt = tps[k]; + break; + } + } + } + Type rtrt = rpt.getRawType(); + if (!(rtrt instanceof Class)) break; + raw = (Class) rtrt; + } while (raw != Object.class); + } + } + if (currt == type) { + if (atas[i] instanceof Class + && ((TypeVariable) type).getBounds().length == 1 + && ((TypeVariable) type).getBounds()[0] instanceof Class + && ((Class) ((TypeVariable) type).getBounds()[0]).isAssignableFrom((Class) atas[i])) + return atas[i]; + if (atas[i] instanceof Class + && ((TypeVariable) type).getBounds().length == 1 + && ((TypeVariable) type).getBounds()[0] instanceof ParameterizedType) { + ParameterizedType pt = (ParameterizedType) ((TypeVariable) type).getBounds()[0]; + if (pt.getRawType() instanceof Class && ((Class) pt.getRawType()).isAssignableFrom((Class) atas[i])) { + return atas[i]; + } + } + if (atas[i] instanceof ParameterizedType + && ((TypeVariable) type).getBounds().length == 1 + && ((TypeVariable) type).getBounds()[0] == Object.class) + return atas[i]; + } + } + ParameterizedType cycType = superPT; + if (cycType.getRawType() instanceof Class) { + TypeVariable[] argTypes = ((Class) cycType.getRawType()).getTypeParameters(); + if (argTypes.length == asts.length) { + for (int i = 0; i < argTypes.length; i++) { + if (argTypes[i] == type) { + if (atas[i] instanceof TypeVariable + && ((TypeVariable) atas[i]).getBounds().length == 1 + && ((TypeVariable) atas[i]).getBounds()[0] instanceof Class) + return ((Class) ((TypeVariable) atas[i]).getBounds()[0]); + } + } + } + } + } + Type moreType = ((ParameterizedType) superType).getRawType(); + if (moreType != Object.class) return getGenericType(type, moreType); + } + TypeVariable tv = (TypeVariable) type; + if (tv.getBounds().length == 1) return tv.getBounds()[0]; + } else if (type instanceof GenericArrayType) { + final Type rst = getGenericType(((GenericArrayType) type).getGenericComponentType(), declaringClass); + return (GenericArrayType) () -> rst; + } + if (type instanceof ParameterizedType) { + ParameterizedType pt = (ParameterizedType) type; + return createParameterizedType(getGenericType(pt.getOwnerType(), declaringClass), + getGenericType(pt.getRawType(), declaringClass), + getGenericType(pt.getActualTypeArguments(), declaringClass)); + } + return type; + } + + private static Type getType(Map map, Type type) { + Type one = map.get(type); + if (one == null) return type; + return getType(map, one); + } + + private static Map parseType(Map map, Class clzz) { + if (clzz == Object.class) return map; + Type superType = clzz.getGenericSuperclass(); + if (!(superType instanceof ParameterizedType)) return map; + ParameterizedType pt = (ParameterizedType) superType; + Type[] ptt = pt.getActualTypeArguments(); + Type superRaw = pt.getRawType(); + if (!(superRaw instanceof Class)) return map; + Class superClazz = (Class) superRaw; + TypeVariable[] scs = superClazz.getTypeParameters(); + if (scs.length != ptt.length) return map; + for (int i = 0; i < scs.length; i++) { + if (scs[i] == ptt[i]) continue; + map.put(scs[i], ptt[i]); + } + return parseType(map, clzz.getSuperclass()); + } + + /** + * 鍔ㄦ佸垱寤虹被鍨嬩负ParameterizedType鎴朇lass鐨凾ype + * + * @param type 褰撳墠娉涘瀷 + * @param declaringType0 瀛愮被 + * + * @return Type + */ + public static Type createClassType(final Type type, final Type declaringType0) { + if (isClassType(type)) return type; + if (type instanceof ParameterizedType) { // e.g. Map + final ParameterizedType pt = (ParameterizedType) type; + final Type[] paramTypes = pt.getActualTypeArguments(); + for (int i = 0; i < paramTypes.length; i++) { + paramTypes[i] = createClassType(paramTypes[i], declaringType0); + } + return createParameterizedType(pt.getOwnerType(), pt.getRawType(), paramTypes); + } + Type declaringType = declaringType0; + if (declaringType instanceof Class) { + do { + declaringType = ((Class) declaringType).getGenericSuperclass(); + if (declaringType == Object.class) return Object.class; + } while (declaringType instanceof Class); + } + //瀛樺湪閫氶厤绗﹀垯declaringType 蹇呴』鏄 ParameterizedType + if (!(declaringType instanceof ParameterizedType)) return Object.class; + final ParameterizedType declaringPType = (ParameterizedType) declaringType; + final Type[] virTypes = ((Class) declaringPType.getRawType()).getTypeParameters(); + final Type[] desTypes = declaringPType.getActualTypeArguments(); + if (type instanceof WildcardType) { // e.g. + final WildcardType wt = (WildcardType) type; + for (Type f : wt.getUpperBounds()) { + for (int i = 0; i < virTypes.length; i++) { + if (virTypes[i].equals(f)) return desTypes.length <= i ? Object.class : desTypes[i]; + } + } + } else if (type instanceof TypeVariable) { // e.g. + for (int i = 0; i < virTypes.length; i++) { + if (virTypes[i].equals(type)) return desTypes.length <= i ? Object.class : desTypes[i]; + } + } + return type; + } + + /** + * 鍔ㄦ佸垱寤 ParameterizedType + * + * @param ownerType0 ParameterizedType 鐨 ownerType + * @param rawType0 ParameterizedType 鐨 rawType + * @param actualTypeArguments0 ParameterizedType 鐨 actualTypeArguments + * + * @return Type + */ + public static Type createParameterizedType(final Type ownerType0, final Type rawType0, final Type... actualTypeArguments0) { + if (ownerType0 == null && rawType0 instanceof Class) { + int count = 0; + for (Type t : actualTypeArguments0) { + if (isClassType(t)) count++; + } + if (count == actualTypeArguments0.length) return createParameterizedType0((Class) rawType0, actualTypeArguments0); + } + return new ParameterizedType() { + private final Class rawType = (Class) rawType0; + + private final Type ownerType = ownerType0; + + private final Type[] actualTypeArguments = actualTypeArguments0; + + @Override + public Type[] getActualTypeArguments() { + return actualTypeArguments.clone(); + } + + @Override + public Type getRawType() { + return rawType; + } + + @Override + public Type getOwnerType() { + return ownerType; + } + + @Override + public int hashCode() { + return Arrays.hashCode(actualTypeArguments) ^ Objects.hashCode(rawType) ^ Objects.hashCode(ownerType); + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof ParameterizedType)) return false; + final ParameterizedType that = (ParameterizedType) o; + if (this == that) return true; + return Objects.equals(ownerType, that.getOwnerType()) + && Objects.equals(rawType, that.getRawType()) + && Arrays.equals(actualTypeArguments, that.getActualTypeArguments()); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + if (ownerType != null) sb.append((ownerType instanceof Class) ? (((Class) ownerType).getName()) : ownerType.toString()).append("."); + sb.append(rawType.getName()); + + if (actualTypeArguments != null && actualTypeArguments.length > 0) { + sb.append("<"); + boolean first = true; + for (Type t : actualTypeArguments) { + if (!first) sb.append(", "); + sb.append(t); + first = false; + } + sb.append(">"); + } + return sb.toString(); + } + }; + } + + // 娉ㄦ剰: RetResult[]> 杩欑娉涘瀷甯]鐨勫皻鏈疄鐜版敮鎸 + private static synchronized Type createParameterizedType0(final Class rawType, final Type... actualTypeArguments) { + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + StringBuilder tmpps = new StringBuilder(getClassTypeDescriptor(rawType)); + for (Type cz : actualTypeArguments) { + tmpps.append(" ").append(getClassTypeDescriptor(cz)); + } + StringBuilder nsb = new StringBuilder(); + for (char ch : tmpps.toString().toCharArray()) { + if (ch >= '0' && ch <= '9') { + nsb.append(ch); + } else if (ch >= 'a' && ch <= 'z') { + nsb.append(ch); + } else if (ch >= 'A' && ch <= 'Z') { + nsb.append(ch); + } else { + nsb.append('_'); + } + } + nsb.append("_GenericType"); + final String newDynName = "org/redkaledyn/typetoken/_Dyn" + TypeToken.class.getSimpleName() + "_" + nsb.toString(); + try { + return loader.loadClass(newDynName.replace('/', '.')).getField("field").getGenericType(); + } catch (Throwable ex) { + } + // ------------------------------------------------------------------------------ + ClassWriter cw = new ClassWriter(COMPUTE_FRAMES); + FieldVisitor fv; + MethodVisitor mv; + cw.visit(V11, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, null, "java/lang/Object", null); + String rawTypeDesc = org.redkale.asm.Type.getDescriptor(rawType); + StringBuilder sb = new StringBuilder(); + sb.append(rawTypeDesc.substring(0, rawTypeDesc.length() - 1)).append('<'); + for (Type c : actualTypeArguments) { + sb.append(getClassTypeDescriptor(c)); + } + sb.append(">;"); + { + fv = cw.visitField(ACC_PUBLIC, "field", rawTypeDesc, sb.toString(), null); + fv.visitEnd(); + } + {//鏋勯犳柟娉 + mv = cw.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(); + } + 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); + RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, newClazz); + RedkaleClassLoader.putReflectionPublicFields(newDynName.replace('/', '.')); + try { + return newClazz.getField("field").getGenericType(); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + + private static CharSequence getClassTypeDescriptor(Type type) { + if (!isClassType(type)) throw new IllegalArgumentException(type + " not a class type"); + if (type instanceof Class) return org.redkale.asm.Type.getDescriptor((Class) type); + if (type instanceof GenericArrayType) return getClassTypeDescriptor(((GenericArrayType) type).getGenericComponentType()) + "[]"; + final ParameterizedType pt = (ParameterizedType) type; + CharSequence rawTypeDesc = getClassTypeDescriptor(pt.getRawType()); + StringBuilder sb = new StringBuilder(); + sb.append(rawTypeDesc.subSequence(0, rawTypeDesc.length() - 1)).append('<'); + for (Type c : pt.getActualTypeArguments()) { + sb.append(getClassTypeDescriptor(c)); + } + sb.append(">;"); + return sb; + } +} diff --git a/src/main/java/org/redkale/util/Utility.java b/src/main/java/org/redkale/util/Utility.java index c87127cdd..dc6e1b3a3 100644 --- a/src/main/java/org/redkale/util/Utility.java +++ b/src/main/java/org/redkale/util/Utility.java @@ -1,2880 +1,2880 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ -package org.redkale.util; - -import java.io.*; -import java.lang.reflect.*; -import java.net.*; -import java.net.http.HttpClient; -import java.nio.*; -import java.nio.channels.CompletionHandler; -import java.nio.charset.*; -import static java.nio.charset.StandardCharsets.UTF_8; -import java.security.*; -import java.time.*; -import java.util.*; -import java.util.concurrent.*; -import java.util.function.*; -import java.util.stream.Stream; -import java.util.zip.GZIPInputStream; - -/** - * - * 甯歌鎿嶄綔鐨勫伐鍏风被 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public final class Utility { - - private static final int zoneRawOffset = TimeZone.getDefault().getRawOffset(); - - static final String format1 = "%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS"; //yyyy-MM-dd HH:mm:ss - - static final String format2 = "%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%1$tL"; //yyyy-MM-dd HH:mm:ss.fff - - private static final char hex[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; - - private static final int MAX_POW2 = 1 << 30; - - private static final Class JAVA_RECORD_CLASS; - - private static final IntFunction futureArrayFunc = c -> new CompletableFuture[c]; - - static { - Class clz = null; - try { - clz = Thread.currentThread().getContextClassLoader().loadClass("java.lang.Record"); - } catch (Throwable t) { //JDK14浠ヤ笅鐗堟湰浼氬紓甯 - } - JAVA_RECORD_CLASS = clz; - } - - private static final String funcAnonymousUnsafeBinary = "cafebabe0000003701710a000200030700040c000500060100106a6176612f6c616e672f4f626a6563740100063c696e69743e01000328295607000801000f73756e2f6d6973632f556e7361666509000a000b07000c0c000d000e0100206f72672f7265646b616c652f7574696c2f416e6f6e796d6f7573556e73616665010006756e736166650100114c73756e2f6d6973632f556e736166653b0a000700100c00110012010006676574496e74010016284c6a6176612f6c616e672f4f626a6563743b4a29490a000700140c00150016010006707574496e74010017284c6a6176612f6c616e672f4f626a6563743b4a4929560a000700180c0019001a0100096765744f626a656374010027284c6a6176612f6c616e672f4f626a6563743b4a294c6a6176612f6c616e672f4f626a6563743b0a0007001c0c001d001e0100097075744f626a656374010028284c6a6176612f6c616e672f4f626a6563743b4a4c6a6176612f6c616e672f4f626a6563743b29560a000700200c0021002201000a676574426f6f6c65616e010016284c6a6176612f6c616e672f4f626a6563743b4a295a0a000700240c0025002601000a707574426f6f6c65616e010017284c6a6176612f6c616e672f4f626a6563743b4a5a29560a000700280c0029002a01000767657442797465010016284c6a6176612f6c616e672f4f626a6563743b4a29420a0007002c0c002d002e01000770757442797465010017284c6a6176612f6c616e672f4f626a6563743b4a4229560a000700300c0031003201000867657453686f7274010016284c6a6176612f6c616e672f4f626a6563743b4a29530a000700340c0035003601000870757453686f7274010017284c6a6176612f6c616e672f4f626a6563743b4a5329560a000700380c0039003a01000767657443686172010016284c6a6176612f6c616e672f4f626a6563743b4a29430a0007003c0c003d003e01000770757443686172010017284c6a6176612f6c616e672f4f626a6563743b4a4329560a000700400c004100420100076765744c6f6e67010016284c6a6176612f6c616e672f4f626a6563743b4a294a0a000700440c004500460100077075744c6f6e67010017284c6a6176612f6c616e672f4f626a6563743b4a4a29560a000700480c0049004a010008676574466c6f6174010016284c6a6176612f6c616e672f4f626a6563743b4a29460a0007004c0c004d004e010008707574466c6f6174010017284c6a6176612f6c616e672f4f626a6563743b4a4629560a000700500c00510052010009676574446f75626c65010016284c6a6176612f6c616e672f4f626a6563743b4a29440a000700540c00550056010009707574446f75626c65010017284c6a6176612f6c616e672f4f626a6563743b4a4429560a000700580c00290059010004284a29420a0007005b0c002d005c010005284a4229560a0007005e0c0031005f010004284a29530a000700610c00350062010005284a5329560a000700640c00390065010004284a29430a000700670c003d0068010005284a4329560a0007006a0c0011006b010004284a29490a0007006d0c0015006e010005284a4929560a000700700c00410071010004284a294a0a000700730c00450074010005284a4a29560a000700760c00490077010004284a29460a000700790c004d007a010005284a4629560a0007007c0c0051007d010004284a29440a0007007f0c00550080010005284a4429560a000700820c0083007101000a676574416464726573730a000700850c0086007401000a707574416464726573730a000700880c0089007101000e616c6c6f636174654d656d6f72790a0007008b0c008c008d0100107265616c6c6f636174654d656d6f7279010005284a4a294a0a0007008f0c009000910100097365744d656d6f7279010018284c6a6176612f6c616e672f4f626a6563743b4a4a4229560a000700930c00900094010006284a4a4229560a000700960c0097009801000a636f70794d656d6f727901002a284c6a6176612f6c616e672f4f626a6563743b4a4c6a6176612f6c616e672f4f626a6563743b4a4a29560a0007009a0c0097009b010006284a4a4a29560a0007009d0c009e009f01000a667265654d656d6f7279010004284a29560a000700a10c00a200a30100116f626a6563744669656c644f666673657401001c284c6a6176612f6c616e672f7265666c6563742f4669656c643b294a0a000700a50c00a600a30100117374617469634669656c644f66667365740a000700a80c00a900aa01000f7374617469634669656c644261736501002d284c6a6176612f6c616e672f7265666c6563742f4669656c643b294c6a6176612f6c616e672f4f626a6563743b0a000700ac0c00ad00ae01000f6172726179426173654f6666736574010014284c6a6176612f6c616e672f436c6173733b29490a000700b00c00b100ae01000f6172726179496e6465785363616c650a000700b30c00b400b501000b6164647265737353697a650100032829490a000700b70c00b800b50100087061676553697a650a000700ba0c00bb00bc010010616c6c6f63617465496e7374616e6365010025284c6a6176612f6c616e672f436c6173733b294c6a6176612f6c616e672f4f626a6563743b0a000700be0c00bf00c001000e7468726f77457863657074696f6e010018284c6a6176612f6c616e672f5468726f7761626c653b29560a000700c20c00c300c4010014636f6d70617265416e64537761704f626a65637401003a284c6a6176612f6c616e672f4f626a6563743b4a4c6a6176612f6c616e672f4f626a6563743b4c6a6176612f6c616e672f4f626a6563743b295a0a000700c60c00c700c8010011636f6d70617265416e6453776170496e74010018284c6a6176612f6c616e672f4f626a6563743b4a4949295a0a000700ca0c00cb00cc010012636f6d70617265416e64537761704c6f6e67010018284c6a6176612f6c616e672f4f626a6563743b4a4a4a295a0a000700ce0c00cf001a0100116765744f626a656374566f6c6174696c650a000700d10c00d2001e0100117075744f626a656374566f6c6174696c650a000700d40c00d5001201000e676574496e74566f6c6174696c650a000700d70c00d8001601000e707574496e74566f6c6174696c650a000700da0c00db0022010012676574426f6f6c65616e566f6c6174696c650a000700dd0c00de0026010012707574426f6f6c65616e566f6c6174696c650a000700e00c00e1002a01000f67657442797465566f6c6174696c650a000700e30c00e4002e01000f70757442797465566f6c6174696c650a000700e60c00e7003201001067657453686f7274566f6c6174696c650a000700e90c00ea003601001070757453686f7274566f6c6174696c650a000700ec0c00ed003a01000f67657443686172566f6c6174696c650a000700ef0c00f0003e01000f70757443686172566f6c6174696c650a000700f20c00f3004201000f6765744c6f6e67566f6c6174696c650a000700f50c00f6004601000f7075744c6f6e67566f6c6174696c650a000700f80c00f9004a010010676574466c6f6174566f6c6174696c650a000700fb0c00fc004e010010707574466c6f6174566f6c6174696c650a000700fe0c00ff0052010011676574446f75626c65566f6c6174696c650a000701010c01020056010011707574446f75626c65566f6c6174696c650a000701040c0105001e0100107075744f7264657265644f626a6563740a000701070c0108001601000d7075744f726465726564496e740a0007010a0c010b004601000e7075744f7264657265644c6f6e670a0007010d0c010e010f010006756e7061726b010015284c6a6176612f6c616e672f4f626a6563743b29560a000701110c011201130100047061726b010005285a4a29560a000701150c0116011701000e6765744c6f616441766572616765010006285b444929490a000701190c011a011b01000c676574416e64416464496e74010017284c6a6176612f6c616e672f4f626a6563743b4a4929490a0007011d0c011e011f01000d676574416e644164644c6f6e67010017284c6a6176612f6c616e672f4f626a6563743b4a4a294a0a000701210c0122011b01000c676574416e64536574496e740a000701240c0125011f01000d676574416e645365744c6f6e670a000701270c0128012901000f676574416e645365744f626a656374010039284c6a6176612f6c616e672f4f626a6563743b4a4c6a6176612f6c616e672f4f626a6563743b294c6a6176612f6c616e672f4f626a6563743b0a0007012b0c012c00060100096c6f616446656e63650a0007012e0c012f000601000a73746f726546656e63650a000701310c0132000601000966756c6c46656e63650a000701340c0135013601000d696e766f6b65436c65616e6572010018284c6a6176612f6e696f2f427974654275666665723b29560701380100176f72672f7265646b616c652f7574696c2f556e73616665010004436f646501000f4c696e654e756d6265725461626c650100124c6f63616c5661726961626c655461626c65010004746869730100224c6f72672f7265646b616c652f7574696c2f416e6f6e796d6f7573556e736166653b0100036f626a0100124c6a6176612f6c616e672f4f626a6563743b0100104d6574686f64506172616d65746572730100016f0100066f66667365740100014a01000178010001490100015a010001420100015301000143010001460100014401000761646472657373010005627974657301000576616c7565010007737263426173650100097372634f6666736574010008646573744261736501000a646573744f666673657401000a7372634164647265737301000b6465737441646472657373010001660100194c6a6176612f6c616e672f7265666c6563742f4669656c643b01000a6172726179436c6173730100114c6a6176612f6c616e672f436c6173733b0100164c6f63616c5661726961626c65547970655461626c650100144c6a6176612f6c616e672f436c6173733c2a3e3b0100095369676e6174757265010017284c6a6176612f6c616e672f436c6173733c2a3e3b2949010003636c7301000a457863657074696f6e730701600100206a6176612f6c616e672f496e7374616e74696174696f6e457863657074696f6e010028284c6a6176612f6c616e672f436c6173733c2a3e3b294c6a6176612f6c616e672f4f626a6563743b01000265650100154c6a6176612f6c616e672f5468726f7761626c653b010008657870656374656401000674687265616401000a69734162736f6c75746501000474696d650100076c6f61646176670100025b440100066e656c656d7301000564656c74610100086e657756616c756501000c6469726563744275666665720100154c6a6176612f6e696f2f427974654275666665723b01000a536f7572636546696c65010014416e6f6e796d6f7573556e736166652e6a6176610021000a00020001013700010012000d000e0000005700010005010f0002013900000049000200020000000d2ab700012a2bc00007b50009b100000002013a0000000e00030000000a0004000b000c000c013b0000001600020000000d013c013d00000000000d013e013f000101400000000501013e00000001001100120002013900000048000400040000000a2ab400092b20b6000fac00000002013a00000006000100000010013b0000002000030000000a013c013d00000000000a0141013f00010000000a0142014300020140000000090201410000014200000001001500160002013900000058000500050000000c2ab400092b201504b60013b100000002013a0000000a000200000015000b0016013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c01440145000401400000000d0301410000014200000144000000010019001a0002013900000048000400040000000a2ab400092b20b60017b000000002013a0000000600010000001a013b0000002000030000000a013c013d00000000000a0141013f00010000000a0142014300020140000000090201410000014200000001001d001e0002013900000058000500050000000c2ab400092b201904b6001bb100000002013a0000000a00020000001f000b0020013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c0144013f000401400000000d030141000001420000014400000001002100220002013900000048000400040000000a2ab400092b20b6001fac00000002013a00000006000100000024013b0000002000030000000a013c013d00000000000a0141013f00010000000a0142014300020140000000090201410000014200000001002500260002013900000058000500050000000c2ab400092b201504b60023b100000002013a0000000a000200000029000b002a013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c01440146000401400000000d0301410000014200000144000000010029002a0002013900000048000400040000000a2ab400092b20b60027ac00000002013a0000000600010000002e013b0000002000030000000a013c013d00000000000a0141013f00010000000a0142014300020140000000090201410000014200000001002d002e0002013900000058000500050000000c2ab400092b201504b6002bb100000002013a0000000a000200000033000b0034013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c01440147000401400000000d030141000001420000014400000001003100320002013900000048000400040000000a2ab400092b20b6002fac00000002013a00000006000100000038013b0000002000030000000a013c013d00000000000a0141013f00010000000a0142014300020140000000090201410000014200000001003500360002013900000058000500050000000c2ab400092b201504b60033b100000002013a0000000a00020000003d000b003e013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c01440148000401400000000d0301410000014200000144000000010039003a0002013900000048000400040000000a2ab400092b20b60037ac00000002013a00000006000100000042013b0000002000030000000a013c013d00000000000a0141013f00010000000a0142014300020140000000090201410000014200000001003d003e0002013900000058000500050000000c2ab400092b201504b6003bb100000002013a0000000a000200000047000b0048013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c01440149000401400000000d030141000001420000014400000001004100420002013900000048000400040000000a2ab400092b20b6003fad00000002013a0000000600010000004c013b0000002000030000000a013c013d00000000000a0141013f00010000000a0142014300020140000000090201410000014200000001004500460002013900000058000600060000000c2ab400092b201604b60043b100000002013a0000000a000200000051000b0052013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c01440143000401400000000d0301410000014200000144000000010049004a0002013900000048000400040000000a2ab400092b20b60047ae00000002013a00000006000100000056013b0000002000030000000a013c013d00000000000a0141013f00010000000a0142014300020140000000090201410000014200000001004d004e0002013900000058000500050000000c2ab400092b201704b6004bb100000002013a0000000a00020000005b000b005c013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c0144014a000401400000000d030141000001420000014400000001005100520002013900000048000400040000000a2ab400092b20b6004faf00000002013a00000006000100000060013b0000002000030000000a013c013d00000000000a0141013f00010000000a0142014300020140000000090201410000014200000001005500560002013900000058000600060000000c2ab400092b201804b60053b100000002013a0000000a000200000065000b0066013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c0144014b000401400000000d03014100000142000001440000000100290059000201390000003d00030003000000092ab400091fb60057ac00000002013a0000000600010000006a013b00000016000200000009013c013d000000000009014c0143000101400000000501014c00000001002d005c000201390000004c000400040000000a2ab400091f1db6005ab100000002013a0000000a00020000006f00090070013b0000002000030000000a013c013d00000000000a014c014300010000000a01440147000301400000000902014c00000144000000010031005f000201390000003d00030003000000092ab400091fb6005dac00000002013a00000006000100000074013b00000016000200000009013c013d000000000009014c0143000101400000000501014c0000000100350062000201390000004c000400040000000a2ab400091f1db60060b100000002013a0000000a0002000000790009007a013b0000002000030000000a013c013d00000000000a014c014300010000000a01440148000301400000000902014c000001440000000100390065000201390000003d00030003000000092ab400091fb60063ac00000002013a0000000600010000007e013b00000016000200000009013c013d000000000009014c0143000101400000000501014c00000001003d0068000201390000004c000400040000000a2ab400091f1db60066b100000002013a0000000a00020000008300090084013b0000002000030000000a013c013d00000000000a014c014300010000000a01440149000301400000000902014c00000144000000010011006b000201390000003d00030003000000092ab400091fb60069ac00000002013a00000006000100000088013b00000016000200000009013c013d000000000009014c0143000101400000000501014c000000010015006e000201390000004c000400040000000a2ab400091f1db6006cb100000002013a0000000a00020000008d0009008e013b0000002000030000000a013c013d00000000000a014c014300010000000a01440145000301400000000902014c000001440000000100410071000201390000003d00030003000000092ab400091fb6006fad00000002013a00000006000100000092013b00000016000200000009013c013d000000000009014c0143000101400000000501014c0000000100450074000201390000004c000500050000000a2ab400091f21b60072b100000002013a0000000a00020000009700090098013b0000002000030000000a013c013d00000000000a014c014300010000000a01440143000301400000000902014c000001440000000100490077000201390000003d00030003000000092ab400091fb60075ae00000002013a0000000600010000009c013b00000016000200000009013c013d000000000009014c0143000101400000000501014c00000001004d007a000201390000004c000400040000000a2ab400091f25b60078b100000002013a0000000a0002000000a1000900a2013b0000002000030000000a013c013d00000000000a014c014300010000000a0144014a000301400000000902014c00000144000000010051007d000201390000003d00030003000000092ab400091fb6007baf00000002013a000000060001000000a6013b00000016000200000009013c013d000000000009014c0143000101400000000501014c0000000100550080000201390000004c000500050000000a2ab400091f29b6007eb100000002013a0000000a0002000000ab000900ac013b0000002000030000000a013c013d00000000000a014c014300010000000a0144014b000301400000000902014c000001440000000100830071000201390000003d00030003000000092ab400091fb60081ad00000002013a000000060001000000b0013b00000016000200000009013c013d000000000009014c0143000101400000000501014c0000000100860074000201390000004c000500050000000a2ab400091f21b60084b100000002013a0000000a0002000000b5000900b6013b0000002000030000000a013c013d00000000000a014c014300010000000a01440143000301400000000902014c000001440000000100890071000201390000003d00030003000000092ab400091fb60087ad00000002013a000000060001000000ba013b00000016000200000009013c013d000000000009014d0143000101400000000501014d00000001008c008d0002013900000048000500050000000a2ab400091f21b6008aad00000002013a000000060001000000bf013b0000002000030000000a013c013d00000000000a014c014300010000000a014d0143000301400000000902014c0000014d00000001009000910002013900000064000700070000000e2ab400092b2016041506b6008eb100000002013a0000000a0002000000c4000d00c5013b0000003400050000000e013c013d00000000000e0141013f00010000000e0142014300020000000e014d014300040000000e014e01470006014000000011040141000001420000014d0000014e00000001009000940002013900000058000600060000000c2ab400091f211505b60092b100000002013a0000000a0002000000c9000b00ca013b0000002a00040000000c013c013d00000000000c014c014300010000000c014d014300030000000c014e0147000501400000000d03014c0000014d0000014e0000000100970098000201390000007000090009000000102ab400092b20190416051607b60095b100000002013a0000000a0002000000ce000f00cf013b0000003e000600000010013c013d000000000010014f013f000100000010015001430002000000100151013f00040000001001520143000500000010014d0143000701400000001505014f0000015000000151000001520000014d000000010097009b0002013900000058000700070000000c2ab400091f211605b60099b100000002013a0000000a0002000000d3000b00d4013b0000002a00040000000c013c013d00000000000c0153014300010000000c0154014300030000000c014d0143000501400000000d030153000001540000014d00000001009e009f000201390000004100030003000000092ab400091fb6009cb100000002013a0000000a0002000000d8000800d9013b00000016000200000009013c013d000000000009014c0143000101400000000501014c0000000100a200a3000201390000003d00020002000000092ab400092bb600a0ad00000002013a000000060001000000dd013b00000016000200000009013c013d0000000000090155015600010140000000050101550000000100a600a3000201390000003d00020002000000092ab400092bb600a4ad00000002013a000000060001000000e2013b00000016000200000009013c013d0000000000090155015600010140000000050101550000000100a900aa000201390000003d00020002000000092ab400092bb600a7b000000002013a000000060001000000e7013b00000016000200000009013c013d0000000000090155015600010140000000050101550000000100ad00ae000301390000004f00020002000000092ab400092bb600abac00000003013a000000060001000000ec013b00000016000200000009013c013d00000000000901570158000101590000000c0001000000090157015a00010140000000050101570000015b00000002015c000100b100ae000301390000004f00020002000000092ab400092bb600afac00000003013a000000060001000000f1013b00000016000200000009013c013d00000000000901570158000101590000000c0001000000090157015a00010140000000050101570000015b00000002015c000100b400b5000101390000003200010001000000082ab40009b600b2ac00000002013a000000060001000000f6013b0000000c000100000008013c013d0000000100b800b5000101390000003200010001000000082ab40009b600b6ac00000002013a000000060001000000fb013b0000000c000100000008013c013d0000000100bb00bc000401390000004f00020002000000092ab400092bb600b9b000000003013a00000006000100000100013b00000016000200000009013c013d000000000009015d0158000101590000000c000100000009015d015a0001015e000000040001015f01400000000501015d0000015b000000020161000100bf00c0000201390000004100020002000000092ab400092bb600bdb100000002013a0000000a00020000010500080106013b00000016000200000009013c013d0000000000090162016300010140000000050101620000000100c300c40002013900000060000600060000000e2ab400092b2019041905b600c1ac00000002013a0000000600010000010a013b0000003400050000000e013c013d00000000000e0141013f00010000000e0142014300020000000e0164013f00040000000e0144013f00050140000000110401410000014200000164000001440000000100c700c80002013900000060000600060000000e2ab400092b2015041505b600c5ac00000002013a0000000600010000010f013b0000003400050000000e013c013d00000000000e0141013f00010000000e0142014300020000000e0164014500040000000e0144014500050140000000110401410000014200000164000001440000000100cb00cc0002013900000060000800080000000e2ab400092b2016041606b600c9ac00000002013a00000006000100000114013b0000003400050000000e013c013d00000000000e0141013f00010000000e0142014300020000000e0164014300040000000e0144014300060140000000110401410000014200000164000001440000000100cf001a0002013900000048000400040000000a2ab400092b20b600cdb000000002013a00000006000100000119013b0000002000030000000a013c013d00000000000a0141013f00010000000a014201430002014000000009020141000001420000000100d2001e0002013900000058000500050000000c2ab400092b201904b600d0b100000002013a0000000a00020000011e000b011f013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c0144013f000401400000000d03014100000142000001440000000100d500120002013900000048000400040000000a2ab400092b20b600d3ac00000002013a00000006000100000123013b0000002000030000000a013c013d00000000000a0141013f00010000000a014201430002014000000009020141000001420000000100d800160002013900000058000500050000000c2ab400092b201504b600d6b100000002013a0000000a000200000128000b0129013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c01440145000401400000000d03014100000142000001440000000100db00220002013900000048000400040000000a2ab400092b20b600d9ac00000002013a0000000600010000012d013b0000002000030000000a013c013d00000000000a0141013f00010000000a014201430002014000000009020141000001420000000100de00260002013900000058000500050000000c2ab400092b201504b600dcb100000002013a0000000a000200000132000b0133013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c01440146000401400000000d03014100000142000001440000000100e1002a0002013900000048000400040000000a2ab400092b20b600dfac00000002013a00000006000100000137013b0000002000030000000a013c013d00000000000a0141013f00010000000a014201430002014000000009020141000001420000000100e4002e0002013900000058000500050000000c2ab400092b201504b600e2b100000002013a0000000a00020000013c000b013d013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c01440147000401400000000d03014100000142000001440000000100e700320002013900000048000400040000000a2ab400092b20b600e5ac00000002013a00000006000100000141013b0000002000030000000a013c013d00000000000a0141013f00010000000a014201430002014000000009020141000001420000000100ea00360002013900000058000500050000000c2ab400092b201504b600e8b100000002013a0000000a000200000146000b0147013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c01440148000401400000000d03014100000142000001440000000100ed003a0002013900000048000400040000000a2ab400092b20b600ebac00000002013a0000000600010000014b013b0000002000030000000a013c013d00000000000a0141013f00010000000a014201430002014000000009020141000001420000000100f0003e0002013900000058000500050000000c2ab400092b201504b600eeb100000002013a0000000a000200000150000b0151013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c01440149000401400000000d03014100000142000001440000000100f300420002013900000048000400040000000a2ab400092b20b600f1ad00000002013a00000006000100000155013b0000002000030000000a013c013d00000000000a0141013f00010000000a014201430002014000000009020141000001420000000100f600460002013900000058000600060000000c2ab400092b201604b600f4b100000002013a0000000a00020000015a000b015b013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c01440143000401400000000d03014100000142000001440000000100f9004a0002013900000048000400040000000a2ab400092b20b600f7ae00000002013a0000000600010000015f013b0000002000030000000a013c013d00000000000a0141013f00010000000a014201430002014000000009020141000001420000000100fc004e0002013900000058000500050000000c2ab400092b201704b600fab100000002013a0000000a000200000164000b0165013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c0144014a000401400000000d03014100000142000001440000000100ff00520002013900000048000400040000000a2ab400092b20b600fdaf00000002013a00000006000100000169013b0000002000030000000a013c013d00000000000a0141013f00010000000a0142014300020140000000090201410000014200000001010200560002013900000058000600060000000c2ab400092b201804b60100b100000002013a0000000a00020000016e000b016f013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c0144014b000401400000000d0301410000014200000144000000010105001e0002013900000058000500050000000c2ab400092b201904b60103b100000002013a0000000a000200000173000b0174013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c0144013f000401400000000d030141000001420000014400000001010800160002013900000058000500050000000c2ab400092b201504b60106b100000002013a0000000a000200000178000b0179013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c01440145000401400000000d030141000001420000014400000001010b00460002013900000058000600060000000c2ab400092b201604b60109b100000002013a0000000a00020000017d000b017e013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c01440143000401400000000d030141000001420000014400000001010e010f000201390000004100020002000000092ab400092bb6010cb100000002013a0000000a00020000018200080183013b00000016000200000009013c013d0000000000090165013f00010140000000050101650000000101120113000201390000004c000400040000000a2ab400091b20b60110b100000002013a0000000a00020000018700090188013b0000002000030000000a013c013d00000000000a0166014600010000000a0167014300020140000000090201660000016700000001011601170002013900000048000300030000000a2ab400092b1cb60114ac00000002013a0000000600010000018c013b0000002000030000000a013c013d00000000000a0168016900010000000a016a014500020140000000090201680000016a00000001011a011b0002013900000054000500050000000c2ab400092b201504b60118ac00000002013a00000006000100000191013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c016b0145000401400000000d030141000001420000016b00000001011e011f0002013900000054000600060000000c2ab400092b201604b6011cad00000002013a00000006000100000196013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c016b0143000401400000000d030141000001420000016b000000010122011b0002013900000054000500050000000c2ab400092b201504b60120ac00000002013a0000000600010000019b013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c016c0145000401400000000d030141000001420000016c000000010125011f0002013900000054000600060000000c2ab400092b201604b60123ad00000002013a000000060001000001a0013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c016c0143000401400000000d030141000001420000016c00000001012801290002013900000054000500050000000c2ab400092b201904b60126b000000002013a000000060001000001a5013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c016c013f000401400000000d030141000001420000016c00000001012c0006000101390000003600010001000000082ab40009b6012ab100000002013a0000000a0002000001aa000701ab013b0000000c000100000008013c013d00000001012f0006000101390000003600010001000000082ab40009b6012db100000002013a0000000a0002000001af000701b0013b0000000c000100000008013c013d0000000101320006000101390000003600010001000000082ab40009b60130b100000002013a0000000a0002000001b4000701b5013b0000000c000100000008013c013d0000000101350136000201390000004100020002000000092ab400092bb60133b100000002013a0000000a0002000001b9000801ba013b00000016000200000009013c013d000000000009016d016e000101400000000501016d00000001016f000000020170"; - - private static final Unsafe unsafeInstance; - - //------------------------------------------------------------------------------- - private static final Function strByteFunction; - - private static final Function sbByteFunction; - - private static final Function strCharFunction; - - private static final Function sbCharFunction; - - private static final Predicate strLatin1Function; - - private static final ToLongFunction bufferAddrFunction; - - private static final Object clientLock = new Object(); - - private static HttpClient httpClient; - - //private static final javax.net.ssl.SSLContext DEFAULTSSL_CONTEXT; - //private static final javax.net.ssl.HostnameVerifier defaultVerifier = (s, ss) -> true; - static { - Unsafe unsafe0 = null; - Function strCharFunction0 = null; - Function sbCharFunction0 = null; - Function strByteFunction0 = null; - Function sbByteFunction0 = null; - Predicate strLatin1Function0 = null; - ToLongFunction bufferAddrFunction0 = null; - - if (!"executable".equals(System.getProperty("org.graalvm.nativeimage.kind"))) { //not native-image - try { - Field f = String.class.getDeclaredField("value"); - final ClassLoader loader = Thread.currentThread().getContextClassLoader(); - final Class unsafeClass = loader.loadClass("sun.misc.Unsafe"); - final Field safeField = unsafeClass.getDeclaredField("theUnsafe"); - RedkaleClassLoader.putReflectionField("sun.misc.Unsafe", safeField); - safeField.setAccessible(true); - final Object usafe = safeField.get(null); - - Class unsafeClazz1 = null; - try { - unsafeClazz1 = (Class) loader.loadClass("org.re" + "dkale.util.AnonymousUnsafe"); - } catch (Throwable t) { - } - if (unsafeClazz1 == null) { - byte[] classBytes = hexToBin(funcAnonymousUnsafeBinary); - unsafeClazz1 = (Class) new ClassLoader(loader) { - public final Class loadClass(String name, byte[] b) { - return defineClass(name, b, 0, b.length); - } - }.loadClass("org.re" + "dkale.util.AnonymousUnsafe", classBytes); - RedkaleClassLoader.putDynClass(unsafeClazz1.getName(), classBytes, unsafeClazz1); - } - RedkaleClassLoader.putReflectionDeclaredConstructors(unsafeClazz1, unsafeClazz1.getName(), Object.class); - unsafe0 = unsafeClazz1.getConstructor(Object.class).newInstance(usafe); - - final Unsafe unsafe = unsafe0; - final long fd1 = unsafe0.objectFieldOffset(f); - final long fd2 = unsafe0.objectFieldOffset(StringBuilder.class.getSuperclass().getDeclaredField("value")); - final long fd3 = unsafe0.objectFieldOffset(String.class.getDeclaredField("coder")); - final long fd4 = unsafe0.objectFieldOffset(Buffer.class.getDeclaredField("address")); - - strByteFunction0 = new Function() { - public Object apply(Object t) { - return unsafe.getObject(t, fd1); - } - }; - sbByteFunction0 = new Function() { - public Object apply(Object t) { - return unsafe.getObject(t, fd2); - } - }; - strLatin1Function0 = new Predicate() { - public boolean test(Object t) { - return unsafe.getByte(t, fd3) == 0; //LATIN1:0 UTF16:1 - } - }; - bufferAddrFunction0 = new ToLongFunction() { - public long applyAsLong(Object t) { - return unsafe.getLong(t, fd4); - } - }; - } catch (Throwable e) { //涓嶄細鍙戠敓 - e.printStackTrace(); - } - - } - unsafeInstance = unsafe0; - strCharFunction = strCharFunction0; - sbCharFunction = sbCharFunction0; - strByteFunction = strByteFunction0; - sbByteFunction = sbByteFunction0; - strLatin1Function = strLatin1Function0; - bufferAddrFunction = bufferAddrFunction0; - -// try { -// DEFAULTSSL_CONTEXT = javax.net.ssl.SSLContext.getInstance("SSL"); -// DEFAULTSSL_CONTEXT.init(null, new javax.net.ssl.TrustManager[]{new javax.net.ssl.X509TrustManager() { -// @Override -// public java.security.cert.X509Certificate[] getAcceptedIssuers() { -// return null; -// } -// -// @Override -// public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) throws java.security.cert.CertificateException { -// } -// -// @Override -// public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) throws java.security.cert.CertificateException { -// } -// }}, null); -// } catch (Exception e) { -// throw new RuntimeException(e); //涓嶄細鍙戠敓 -// } - } - - private Utility() { - } - - public static Unsafe unsafe() { - return unsafeInstance; - } - - public static int cpus() { - return Runtime.getRuntime().availableProcessors(); - } - - /** - * @param value from which next positive power of two will be found. - * - * @return the next positive power of 2, this value if it is a power of 2. Negative values are mapped to 1. - * @throws IllegalArgumentException is value is more than MAX_POW2 or less than 0 - */ - public static int roundToPowerOfTwo(final int value) { - if (value > MAX_POW2) throw new IllegalArgumentException("There is no larger power of 2 int for value:" + value + " since it exceeds 2^31."); - if (value < 0) throw new IllegalArgumentException("Given value:" + value + ". Expecting value >= 0."); - return 1 << (32 - Integer.numberOfLeadingZeros(value - 1)); - } - - public static boolean isRecordGetter(Method method) { - return isRecordGetter(method.getDeclaringClass(), method); - } - - public static boolean isRecordGetter(Class clazz, Method method) { - if (JAVA_RECORD_CLASS == null) return false; - if (method.getReturnType() == void.class) return false; - if (method.getParameterCount() != 0) return false; - if (method.getName().equals("getClass")) return false; - Class clz = (clazz == null ? method.getDeclaringClass() : clazz); - if (!JAVA_RECORD_CLASS.isAssignableFrom(clz)) return false; - try { - return clz.getDeclaredField(method.getName()).getType() == method.getReturnType(); - } catch (Throwable t) { - return false; - } - } - - public static CompletableFuture orTimeout(CompletableFuture future, long timeout, TimeUnit unit) { - return future.orTimeout(timeout, unit); - } - - public static CompletableFuture completeOnTimeout(CompletableFuture future, T value, long timeout, TimeUnit unit) { - return future.completeOnTimeout(value, timeout, unit); - } - - public static CompletableFuture allOfFutures(Stream> stream, IntFunction func) { - CompletableFuture[] futures = stream.toArray(futureArrayFunc); - return CompletableFuture.allOf(futures).thenApply(v -> { - int size = futures.length; - T[] array = func.apply(size); - for (int i = 0; i < size; i++) { - array[i] = futures[i].join(); - } - return array; - }); - } - - public static CompletableFuture allOfFutures(CompletableFuture[] futures, IntFunction func) { - return CompletableFuture.allOf(futures).thenApply(v -> { - int size = futures.length; - T[] array = func.apply(size); - for (int i = 0; i < size; i++) { - array[i] = futures[i].join(); - } - return array; - }); - } - - public static CompletableFuture allOfFutures(Stream> stream, IntFunction func, BiConsumer consumer) { - CompletableFuture[] futures = stream.toArray(futureArrayFunc); - return CompletableFuture.allOf(futures).thenApply(v -> { - int size = futures.length; - T[] array = func.apply(size); - for (int i = 0; i < size; i++) { - T val = futures[i].join(); - consumer.accept(i, val); - array[i] = val; - } - return array; - }); - } - - public static CompletableFuture allOfFutures(CompletableFuture[] futures, IntFunction func, BiConsumer consumer) { - return CompletableFuture.allOf(futures).thenApply(v -> { - int size = futures.length; - T[] array = func.apply(size); - for (int i = 0; i < size; i++) { - T val = futures[i].join(); - consumer.accept(i, val); - array[i] = val; - } - return array; - }); - } - - /** - * 灏嗗涓猭ey:value鐨勫瓧绗︿覆閿煎缁勫悎鎴愪竴涓狹ap锛宨tems闀垮害蹇呴』鏄伓鏁, 鍙傛暟涓暟鑻ユ槸濂囨暟鐨勮瘽锛屾渶鍚庝竴涓細琚拷鐣 - * 绫讳技 JDK9涓殑 Map.of 鏂规硶 - * - * @param items 閿煎 - * - * @return Map - */ - public static HashMap ofMap(String... items) { - HashMap map = new LinkedHashMap<>(Math.max(1, items.length / 2)); - int len = items.length / 2; - for (int i = 0; i < len; i++) { - map.put(items[i * 2], items[i * 2 + 1]); - } - return map; - } - - /** - * 灏嗗涓猭ey:value瀵瑰簲鍊肩粍鍚堟垚涓涓狹ap锛宨tems闀垮害蹇呴』鏄伓鏁, 鍙傛暟涓暟鑻ユ槸濂囨暟鐨勮瘽锛屾渶鍚庝竴涓細琚拷鐣 - * 绫讳技 JDK9涓殑 Map.of 鏂规硶 - * - * @param 娉涘瀷 - * @param 娉涘瀷 - * @param items 閿煎 - * - * @return Map - */ - public static HashMap ofMap(Object... items) { - HashMap map = new LinkedHashMap<>(Math.max(1, items.length / 2)); - int len = items.length / 2; - for (int i = 0; i < len; i++) { - map.put((K) items[i * 2], (V) items[i * 2 + 1]); - } - return map; - } - - /** - * 灏嗗涓狹ap鍚堝苟鍒扮涓涓狹ap涓 - * - * @param 娉涘瀷 - * @param 娉涘瀷 - * @param maps Map - * - * @return Map - */ - public static Map merge(Map... maps) { - Map map = null; - for (Map m : maps) { - if (map == null) { - map = m; - } else if (m != null) { - map.putAll(m); - } - } - return map; - } - - /** - * 灏嗗涓厓绱犵粍鍚堟垚涓涓猄et - * - * @param 娉涘瀷 - * @param items 鍏冪礌 - * - * @return Set - */ - public static Set ofSet(T... items) { - Set set = new LinkedHashSet<>(items.length); - for (T item : items) set.add(item); - return set; - } - - /** - * 灏嗗涓厓绱犵粍鍚堟垚涓涓狶ist
- * 绫讳技 JDK9涓殑 List.of 鏂规硶 - * - * @param 娉涘瀷 - * @param items 鍏冪礌 - * - * @return List - */ - public static List ofList(T... items) { - List list = new ArrayList<>(items.length); - for (T item : items) list.add(item); - return list; - } - - /** - * 灏嗗涓厓绱犵粍鍚堟垚涓涓狝rray - * - * @param 娉涘瀷 - * @param items 鍏冪礌 - * - * @return Array - */ - public static T[] ofArray(T... items) { - return items; - } - - /** - * 瑁佸壀List锛屼娇鍏秙ize涓嶈秴杩噇imit澶у皬
- * - * @param 娉涘瀷 - * @param list 闆嗗悎 - * @param limit 澶у皬 - * - * @return List - */ - public static List limit(List list, int limit) { - if (list == null || list.isEmpty() || list.size() <= limit) return list; - return list.subList(0, limit); - } - - /** - * 鑾峰彇涓嶅甫"-"鐨刄UID鍊 - * - * @return 涓嶅甫"-"UUID鍊 - */ - public static String uuid() { - return UUID.randomUUID().toString().replace("-", ""); - } - - /** - * 灏嗕竴涓垨澶氫釜鏂板厓绱犳坊鍔犲埌鏁扮粍寮濮嬶紝鏁扮粍涓殑鍏冪礌鑷姩鍚庣Щ - * - * @param 娉涘瀷 - * @param array 鍘熸暟缁 - * @param objs 寰呰拷鍔犳暟鎹 - * - * @return 鏂版暟缁 - */ - public static T[] unshift(final T[] array, final T... objs) { - if (array == null || array.length == 0) return objs; - final T[] news = (T[]) Array.newInstance(array.getClass().getComponentType(), array.length + objs.length); - System.arraycopy(objs, 0, news, 0, objs.length); - System.arraycopy(array, 0, news, objs.length, array.length); - return news; - } - - /** - * 灏嗕竴涓垨澶氫釜鏂板厓绱犳坊鍔犲埌鏁扮粍寮濮嬶紝鏁扮粍涓殑鍏冪礌鑷姩鍚庣Щ - * - * @param 娉涘瀷 - * @param array 鍘熸暟缁 - * @param objs 寰呰拷鍔犳暟鎹 - * - * @return 鏂版暟缁 - */ - public static T[] unshift(final T[] array, final Collection objs) { - if (objs == null || objs.isEmpty()) return array; - if (array == null) { - T one = null; - for (T t : objs) { - if (t != null) one = t; - break; - } - if (one == null) return array; - T[] news = (T[]) Array.newInstance(one.getClass(), objs.size()); - return objs.toArray(news); - } - T[] news = (T[]) Array.newInstance(array.getClass().getComponentType(), array.length + objs.size()); - int index = -1; - for (T t : objs) { - news[(++index)] = t; - } - System.arraycopy(array, 0, news, objs.size(), array.length); - return news; - } - - /** - * 鑾峰彇int鏁扮粍涔嬪拰, 绌烘暟缁勮繑鍥0 - * - * @param array 鏁扮粍 - * - * @return int - */ - public static int sum(final int... array) { - return sum(false, array); - } - - /** - * 鑾峰彇int鏁扮粍涔嬪拰 - * - * @param check 鏄惁妫娴嬬┖ - * @param array 鏁扮粍 - * - * @return int - */ - public static int sum(boolean check, final int... array) { - if (array == null || array.length == 0) { - if (!check) return 0; - throw new NullPointerException("array is null or empty"); - } - int sum = 0; - for (int i : array) { - sum += i; - } - return sum; - } - - /** - * 鑾峰彇long鏁扮粍涔嬪拰, 绌烘暟缁勮繑鍥0 - * - * @param array 鏁扮粍 - * - * @return long - */ - public static long sum(final long... array) { - return sum(false, array); - } - - /** - * 鑾峰彇long鏁扮粍涔嬪拰 - * - * @param check 鏄惁妫娴嬬┖ - * @param array 鏁扮粍 - * - * @return long - */ - public static long sum(boolean check, final long... array) { - if (array == null || array.length == 0) { - if (!check) return 0; - throw new NullPointerException("array is null or empty"); - } - long sum = 0L; - for (long i : array) { - sum += i; - } - return sum; - } - - /** - * 鑾峰彇int鏁扮粍鏈澶у - * - * @param array 鏁扮粍 - * - * @return int - */ - public static int max(final int... array) { - if (array == null || array.length == 0) throw new NullPointerException("array is null or empty"); - int max = array[0]; - for (int i : array) { - if (i > max) i = max; - } - return max; - } - - /** - * 鑾峰彇long鏁扮粍鏈澶у - * - * @param array 鏁扮粍 - * - * @return long - */ - public static long max(final long... array) { - if (array == null || array.length == 0) throw new NullPointerException("array is null or empty"); - long max = array[0]; - for (long i : array) { - if (i > max) i = max; - } - return max; - } - - /** - * 鑾峰彇int鏁扮粍鏈灏忓 - * - * @param array 鏁扮粍 - * - * @return int - */ - public static long min(final int... array) { - if (array == null || array.length == 0) throw new NullPointerException("array is null or empty"); - int min = array[0]; - for (int i : array) { - if (i < min) i = min; - } - return min; - } - - /** - * 鑾峰彇long鏁扮粍鏈灏忓 - * - * @param array 鏁扮粍 - * - * @return long - */ - public static long min(final long... array) { - if (array == null || array.length == 0) throw new NullPointerException("array is null or empty"); - long min = array[0]; - for (long i : array) { - if (i < min) i = min; - } - return min; - } - - /** - * 灏哻har鏁扮粍鐢ㄥ垎闅旂鎷兼帴鎴愬瓧绗︿覆 - * - * @param array 鏁扮粍 - * @param delimiter 鍒嗛殧绗 - * - * @return String - */ - public static String joining(final char[] array, final String delimiter) { - if (array == null || array.length == 0) return ""; - StringBuilder sb = new StringBuilder(); - for (char i : array) { - if (sb.length() > 0) sb.append(delimiter); - sb.append(i); - } - return sb.toString(); - } - - /** - * 灏唅nt鏁扮粍鐢ㄥ垎闅旂鎷兼帴鎴愬瓧绗︿覆 - * - * @param array 鏁扮粍 - * @param delimiter 鍒嗛殧绗 - * - * @return String - */ - public static String joining(final int[] array, final String delimiter) { - if (array == null || array.length == 0) return ""; - StringBuilder sb = new StringBuilder(); - for (int i : array) { - if (sb.length() > 0) sb.append(delimiter); - sb.append(i); - } - return sb.toString(); - } - - /** - * 灏唋ong鏁扮粍鐢ㄥ垎闅旂鎷兼帴鎴愬瓧绗︿覆 - * - * @param array 鏁扮粍 - * @param delimiter 鍒嗛殧绗 - * - * @return String - */ - public static String joining(final long[] array, final String delimiter) { - if (array == null || array.length == 0) return ""; - StringBuilder sb = new StringBuilder(); - for (long i : array) { - if (sb.length() > 0) sb.append(delimiter); - sb.append(i); - } - return sb.toString(); - } - - /** - * 灏嗗璞℃暟缁勭敤鍒嗛殧绗︽嫾鎺ユ垚瀛楃涓 - * - * @param 娉涘瀷 - * @param array 鏁扮粍 - * @param delimiter 鍒嗛殧绗 - * - * @return String - */ - public static String joining(final T[] array, final String delimiter) { - if (array == null || array.length == 0) return ""; - StringBuilder sb = new StringBuilder(); - for (T i : array) { - if (sb.length() > 0) sb.append(delimiter); - sb.append(i); - } - return sb.toString(); - } - - /** - * 灏嗗璞℃暟缁勭敤鍒嗛殧绗︽嫾鎺ユ垚瀛楃涓 - * - * @param 娉涘瀷 - * @param array 鏁扮粍 - * @param delimiter 鍒嗛殧绗 - * - * @return String - */ - public static String joining(final String[] array, final char delimiter) { - if (array == null || array.length == 0) return ""; - StringBuilder sb = new StringBuilder(); - for (String i : array) { - if (sb.length() > 0) sb.append(delimiter); - sb.append(i); - } - return sb.toString(); - } - - /** - * 灏嗗璞℃暟缁勭敤鍒嗛殧绗︽嫾鎺ユ垚瀛楃涓 - * - * @param 娉涘瀷 - * @param array 鏁扮粍 - * @param delimiter 鍒嗛殧绗 - * - * @return String - */ - public static String joiningHex(final byte[] array, final char delimiter) { - if (array == null || array.length == 0) return ""; - StringBuilder sb = new StringBuilder(); - for (byte i : array) { - if (sb.length() > 0) sb.append(delimiter); - String s = Integer.toHexString(i & 0xff); - sb.append(s.length() > 1 ? "0x" : "0x0").append(s); - } - return sb.toString(); - } - - /** - * 灏嗗璞℃暟缁勭敤鍒嗛殧绗︽嫾鎺ユ垚瀛楃涓 - * - * @param 娉涘瀷 - * @param array 鏁扮粍 - * @param offset 鍋忕Щ閲 - * @param length 闀垮害 - * @param delimiter 鍒嗛殧绗 - * - * @return String - */ - public static String joiningHex(final byte[] array, int offset, int length, final char delimiter) { - if (array == null || array.length == 0) return ""; - StringBuilder sb = new StringBuilder(); - int len = offset + length; - for (int i = offset; i < len; i++) { - if (sb.length() > 0) sb.append(delimiter); - String s = Integer.toHexString(array[i] & 0xff); - sb.append(s.length() > 1 ? "0x" : "0x0").append(s); - } - return sb.toString(); - } - - /** - * 灏嗕竴涓垨澶氫釜byte鏂板厓绱犳坊鍔犲埌byte鏁扮粍缁撳熬 - * - * @param array 鍘熸暟缁 - * @param objs 寰呰拷鍔犳暟鎹 - * - * @return 鏂版暟缁 - */ - public static byte[] append(final byte[] array, final byte... objs) { - if (array == null || array.length == 0) return objs; - if (objs == null || objs.length == 0) return array; - final byte[] news = new byte[array.length + objs.length]; - System.arraycopy(array, 0, news, 0, array.length); - System.arraycopy(objs, 0, news, array.length, objs.length); - return news; - } - - /** - * 灏嗕竴涓垨澶氫釜byte鏂板厓绱犳坊鍔犲埌byte鏁扮粍缁撳熬 - * - * @param array 鍘熸暟缁 - * @param objs 寰呰拷鍔犳暟鎹 - * @param offset 寰呰拷鍔犳暟鎹亸绉婚噺 - * @param length 寰呰拷鍔犳暟鎹殑闀垮害 - * - * @return 鏂版暟缁 - */ - public static byte[] append(final byte[] array, final byte[] objs, int offset, int length) { - if (array == null || array.length == 0) { - if (objs != null && offset == 0 && objs.length == length) return objs; - final byte[] news = new byte[length]; - System.arraycopy(objs, 0, news, 0, length); - return news; - } - if (objs == null || length == 0) return array; - final byte[] news = new byte[array.length + length]; - System.arraycopy(array, 0, news, 0, array.length); - System.arraycopy(objs, offset, news, array.length, length); - return news; - } - - /** - * 灏嗕竴涓垨澶氫釜short鏂板厓绱犳坊鍔犲埌short鏁扮粍缁撳熬 - * - * @param array 鍘熸暟缁 - * @param objs 寰呰拷鍔犳暟鎹 - * - * @return 鏂版暟缁 - */ - public static short[] append(final short[] array, final short... objs) { - if (array == null || array.length == 0) return objs; - if (objs == null || objs.length == 0) return array; - final short[] news = new short[array.length + objs.length]; - System.arraycopy(array, 0, news, 0, array.length); - System.arraycopy(objs, 0, news, array.length, objs.length); - return news; - } - - /** - * 灏嗕竴涓垨澶氫釜char鏂板厓绱犳坊鍔犲埌char鏁扮粍缁撳熬 - * - * @param array 鍘熸暟缁 - * @param objs 寰呰拷鍔犳暟鎹 - * - * @return 鏂版暟缁 - */ - public static char[] append(final char[] array, final char... objs) { - if (array == null || array.length == 0) return objs; - if (objs == null || objs.length == 0) return array; - final char[] news = new char[array.length + objs.length]; - System.arraycopy(array, 0, news, 0, array.length); - System.arraycopy(objs, 0, news, array.length, objs.length); - return news; - } - - /** - * 灏嗕竴涓垨澶氫釜int鏂板厓绱犳坊鍔犲埌int鏁扮粍缁撳熬 - * - * @param array 鍘熸暟缁 - * @param objs 寰呰拷鍔犳暟鎹 - * - * @return 鏂版暟缁 - */ - public static int[] append(final int[] array, final int... objs) { - if (array == null || array.length == 0) return objs; - if (objs == null || objs.length == 0) return array; - final int[] news = new int[array.length + objs.length]; - System.arraycopy(array, 0, news, 0, array.length); - System.arraycopy(objs, 0, news, array.length, objs.length); - return news; - } - - /** - * 灏嗕竴涓垨澶氫釜long鏂板厓绱犳坊鍔犲埌long鏁扮粍缁撳熬 - * - * @param array 鍘熸暟缁 - * @param objs 寰呰拷鍔犳暟鎹 - * - * @return 鏂版暟缁 - */ - public static long[] append(final long[] array, final long... objs) { - if (array == null || array.length == 0) return objs; - if (objs == null || objs.length == 0) return array; - final long[] news = new long[array.length + objs.length]; - System.arraycopy(array, 0, news, 0, array.length); - System.arraycopy(objs, 0, news, array.length, objs.length); - return news; - } - - /** - * 灏嗕竴涓垨澶氫釜鏂板厓绱犳坊鍔犲埌鏁扮粍缁撳熬 - * - * @param 娉涘瀷 - * @param array 鍘熸暟缁 - * @param objs 寰呰拷鍔犳暟鎹 - * - * @return 鏂版暟缁 - */ - public static T[] append(final T[] array, final T... objs) { - if (array == null || array.length == 0) return objs; - if (objs == null || objs.length == 0) return array; - final T[] news = (T[]) Array.newInstance(array.getClass().getComponentType(), array.length + objs.length); - System.arraycopy(array, 0, news, 0, array.length); - System.arraycopy(objs, 0, news, array.length, objs.length); - return news; - } - - /** - * 灏嗕竴涓垨澶氫釜鏂板厓绱犳坊鍔犲埌鏁扮粍缁撳熬 - * - * @param 娉涘瀷 - * @param array 鍘熸暟缁 - * @param objs 寰呰拷鍔犳暟鎹 - * - * @return 鏂版暟缁 - */ - public static T[] append(final T[] array, final Collection objs) { - if (objs == null || objs.isEmpty()) return array; - if (array == null) { - T one = null; - for (T t : objs) { - if (t != null) one = t; - break; - } - if (one == null) return array; - T[] news = (T[]) Array.newInstance(one.getClass(), objs.size()); - return objs.toArray(news); - } - T[] news = (T[]) Array.newInstance(array.getClass().getComponentType(), array.length + objs.size()); - System.arraycopy(array, 0, news, 0, array.length); - int index = -1; - for (T t : objs) { - news[array.length + (++index)] = t; - } - return news; - } - - /** - * 灏唅nt鏁扮粍鍊掑簭 - * - * @param array 鍘熸暟缁 - * - * @return 鏂版暟缁 - */ - public static int[] reverseSort(final int[] array) { - if (array == null || array.length == 0) return array; - return Arrays.stream(array).boxed().sorted(Collections.reverseOrder()).mapToInt(x -> x).toArray(); - } - - /** - * 灏唋ong鏁扮粍鍊掑簭 - * - * @param array 鍘熸暟缁 - * - * @return 鏂版暟缁 - */ - public static long[] reverseSort(final long[] array) { - if (array == null || array.length == 0) return array; - return Arrays.stream(array).boxed().sorted(Collections.reverseOrder()).mapToLong(x -> x).toArray(); - } - - /** - * 灏嗗厓绱犱粠鏁扮粍涓垹闄 - * - * @param 娉涘瀷 - * @param array 鍘熸暟缁 - * @param item 鍏冪礌 - * - * @return 鏂版暟缁 - */ - public static T[] remove(final T[] array, final T item) { - return remove(array, (i) -> Objects.equals(i, item)); - } - - /** - * 灏嗙鍚堟潯浠剁殑鍏冪礌浠庢暟缁勪腑鍒犻櫎 - * - * @param 娉涘瀷 - * @param array 鍘熸暟缁 - * @param filter Predicate - * - * @return 鏂版暟缁 - */ - public static T[] remove(final T[] array, final Predicate filter) { - if (array == null || array.length == 0 || filter == null) return array; - final T[] news = (T[]) Array.newInstance(array.getClass().getComponentType(), array.length); - int index = 0; - for (int i = 0; i < news.length; i++) { - if (!filter.test(array[i])) { - news[index++] = array[i]; - } - } - if (index == array.length) return array; - final T[] rs = (T[]) Array.newInstance(array.getClass().getComponentType(), index); - System.arraycopy(news, 0, rs, 0, index); - return rs; - } - - /** - * 灏嗘寚瀹氱殑long鍏冪礌浠庢暟缁勪腑鍒犻櫎, 鐩稿悓鐨勫厓绱犱細鏍规嵁items閲岄噸澶嶆鏁版潵鎵ц鍒犻櫎
- * 渚嬪:
- * remove(new short[]{1, 1, 1, 2, 2, 3, 3, 3}, false, 1, 1, 2, 3, 3) = [1,2,3]
- * - * @param array 鍘熸暟缁 - * @param items short[] - * - * @return 鏂版暟缁 - */ - public static short[] removeMatch(final short[] array, final short... items) { - return remove(array, false, items); - } - - /** - * 灏嗘寚瀹氱殑int鍏冪礌浠庢暟缁勪腑鍒犻櫎, repeat=true鏃剁浉鍚岀殑鍏冪礌浼氭牴鎹甶tems閲岄噸澶嶆鏁版潵鎵ц鍒犻櫎
- * 渚嬪:
- * remove(new short[]{1, 1, 1, 2, 2, 3, 3, 3}, true, 1, 1, 2, 3, 3) = []
- * remove(new short[]{1, 1, 1, 2, 2, 3, 3, 3}, false, 1, 1, 2, 3, 3) = [1,2,3] - * - * @param array 鍘熸暟缁 - * @param repeat 鏄惁閲嶅鍒犻櫎鐩稿悓鐨勫厓绱 - * @param items short[] - * - * @return 鏂版暟缁 - */ - public static short[] remove(final short[] array, boolean repeat, final short... items) { - if (array == null || array.length == 0 || items == null || items.length == 0) return array; - final short[] news = new short[array.length]; - short[] subs = items; - int index = 0; - for (int i = 0; i < news.length; i++) { - if (subs.length > 0 && contains(subs, array[i])) { - if (!repeat) { - short[] newsubs = new short[subs.length - 1]; - int k = 0; - boolean done = false; - for (short v : subs) { - if (done) { - newsubs[k++] = v; - } else if (v == array[i]) { - done = true; - } else { - newsubs[k++] = v; - } - } - subs = newsubs; - } - } else { - news[index++] = array[i]; - } - } - if (index == array.length) return array; - final short[] rs = new short[index]; - System.arraycopy(news, 0, rs, 0, index); - return rs; - } - - /** - * 灏嗘寚瀹氱殑long鍏冪礌浠庢暟缁勪腑鍒犻櫎, 鐩稿悓鐨勫厓绱犱細鏍规嵁items閲岄噸澶嶆鏁版潵鎵ц鍒犻櫎
- * 渚嬪:
- * remove(new int[]{1, 1, 1, 2, 2, 3, 3, 3}, false, 1, 1, 2, 3, 3) = [1,2,3]
- * - * @param array 鍘熸暟缁 - * @param items int[] - * - * @return 鏂版暟缁 - */ - public static int[] removeMatch(final int[] array, final int... items) { - return remove(array, false, items); - } - - /** - * 灏嗘寚瀹氱殑int鍏冪礌浠庢暟缁勪腑鍒犻櫎, repeat=false鏃剁浉鍚岀殑鍏冪礌浼氭牴鎹甶tems閲岄噸澶嶆鏁版潵鎵ц鍒犻櫎
- * 渚嬪:
- * remove(new int[]{1, 1, 1, 2, 2, 3, 3, 3}, true, 1, 1, 2, 3, 3) = []
- * remove(new int[]{1, 1, 1, 2, 2, 3, 3, 3}, false, 1, 1, 2, 3, 3) = [1,2,3] - * - * @param array 鍘熸暟缁 - * @param repeat 鏄惁閲嶅鍒犻櫎鐩稿悓鐨勫厓绱 - * @param items int[] - * - * @return 鏂版暟缁 - */ - public static int[] remove(final int[] array, boolean repeat, final int... items) { - if (array == null || array.length == 0 || items == null || items.length == 0) return array; - final int[] news = new int[array.length]; - int[] subs = items; - int index = 0; - for (int i = 0; i < news.length; i++) { - if (subs.length > 0 && contains(subs, array[i])) { - if (!repeat) { - int[] newsubs = new int[subs.length - 1]; - int k = 0; - boolean done = false; - for (int v : subs) { - if (done) { - newsubs[k++] = v; - } else if (v == array[i]) { - done = true; - } else { - newsubs[k++] = v; - } - } - subs = newsubs; - } - } else { - news[index++] = array[i]; - } - } - if (index == array.length) return array; - final int[] rs = new int[index]; - System.arraycopy(news, 0, rs, 0, index); - return rs; - } - - /** - * 灏嗘寚瀹氱殑long鍏冪礌浠庢暟缁勪腑鍒犻櫎, 鐩稿悓鐨勫厓绱犱細鏍规嵁items閲岄噸澶嶆鏁版潵鎵ц鍒犻櫎
- * 渚嬪:
- * remove(new long[]{1, 1, 1, 2, 2, 3, 3, 3}, false, 1, 1, 2, 3, 3) = [1,2,3]
- * - * @param array 鍘熸暟缁 - * @param items long[] - * - * @return 鏂版暟缁 - */ - public static long[] removeMatch(final long[] array, final long... items) { - return remove(array, false, items); - } - - /** - * 灏嗘寚瀹氱殑long鍏冪礌浠庢暟缁勪腑鍒犻櫎, repeat=false鏃剁浉鍚岀殑鍏冪礌浼氭牴鎹甶tems閲岄噸澶嶆鏁版潵鎵ц鍒犻櫎
- * 渚嬪:
- * remove(new long[]{1, 1, 1, 2, 2, 3, 3, 3}, true, 1, 1, 2, 3, 3) = []
- * remove(new long[]{1, 1, 1, 2, 2, 3, 3, 3}, false, 1, 1, 2, 3, 3) = [1,2,3]
- * - * @param array 鍘熸暟缁 - * @param repeat 鏄惁閲嶅鍒犻櫎鐩稿悓鐨勫厓绱 - * @param items long[] - * - * @return 鏂版暟缁 - */ - public static long[] remove(final long[] array, boolean repeat, final long... items) { - if (array == null || array.length == 0 || items == null || items.length == 0) return array; - final long[] news = new long[array.length]; - long[] subs = items; - int index = 0; - for (int i = 0; i < news.length; i++) { - if (subs.length > 0 && contains(subs, array[i])) { - if (!repeat) { - long[] newsubs = new long[subs.length - 1]; - int k = 0; - boolean done = false; - for (long v : subs) { - if (done) { - newsubs[k++] = v; - } else if (v == array[i]) { - done = true; - } else { - newsubs[k++] = v; - } - } - subs = newsubs; - } - } else { - news[index++] = array[i]; - } - } - if (index == array.length) return array; - final long[] rs = new long[index]; - System.arraycopy(news, 0, rs, 0, index); - return rs; - } - - /** - * 鍒ゆ柇瀛楃涓叉槸鍚﹀寘鍚寚瀹氱殑瀛楃锛屽寘鍚繑鍥瀟rue - * - * @param string 瀛楃涓 - * @param values 瀛楃闆嗗悎 - * - * @return boolean - */ - public static boolean contains(String string, char... values) { - if (string == null) return false; - for (char ch : Utility.charArray(string)) { - for (char ch2 : values) { - if (ch == ch2) return true; - } - } - return false; - } - - /** - * 姣旇緝涓ら泦鍚堝厓绱犳槸鍚︿竴鏍凤紝 椤哄簭涓嶈姹備竴鏍 - * - * @param 娉涘瀷 - * @param array1 闆嗗悎 - * @param array2 闆嗗悎 - * - * @return 鍏冪礌鏄惁瀹屽叏鐩稿悓 - */ - public static boolean equalsElement(T[] array1, T[] array2) { - if (array1 == null && array2 == null) return true; - if (array1 == null && array2 != null) return false; - if (array1 != null && array2 == null) return false; - if (array1.length != array2.length) return false; - return equalsElement(ofList(array1), ofList(array2)); - } - - /** - * 姣旇緝涓ら泦鍚堝厓绱犳槸鍚︿竴鏍凤紝 椤哄簭涓嶈姹備竴鏍 - * - * @param 娉涘瀷 - * @param col1 闆嗗悎 - * @param col2 闆嗗悎 - * - * @return 鍏冪礌鏄惁瀹屽叏鐩稿悓 - */ - public static boolean equalsElement(Collection col1, Collection col2) { - if (col1 == null && col2 == null) return true; - if (col1 == null && col2 != null) return false; - if (col1 != null && col2 == null) return false; - if (col1.size() != col2.size()) return false; - //{1,2,2}, {1,1,2} - List list = new ArrayList<>(col2); - for (T item : col1) { - if (!list.remove(item)) return false; - } - return list.isEmpty(); - } - - /** - * 姣旇緝涓ら泦鍚堝厓绱犳槸鍚︿竴鏍凤紝 椤哄簭涓嶈姹備竴鏍 - * - * @param 娉涘瀷 - * @param 娉涘瀷 - * @param map1 闆嗗悎 - * @param map2 闆嗗悎 - * - * @return 鍏冪礌鏄惁瀹屽叏鐩稿悓 - */ - public static boolean equalsElement(Map map1, Map map2) { - if (map1 == null && map2 == null) return true; - if (map1 == null && map2 != null) return false; - if (map1 != null && map2 == null) return false; - if (map1.size() != map2.size()) return false; - for (Map.Entry en : map1.entrySet()) { - if (!Objects.equals(en.getValue(), map2.get(en.getKey()))) return false; - } - return true; - } - - /** - * 鍒ゆ柇鎸囧畾鍊兼槸鍚﹀寘鍚寚瀹氱殑鏁扮粍涓紝鍖呭惈杩斿洖true - * - * @param values 闆嗗悎 - * @param value 鍗曞 - * - * @return boolean - */ - public static boolean contains(char[] values, char value) { - if (values == null) return false; - for (char v : values) { - if (v == value) return true; - } - return false; - } - - /** - * 鍒ゆ柇鎸囧畾鍊兼槸鍚﹀寘鍚寚瀹氱殑鏁扮粍涓紝鍖呭惈杩斿洖true - * - * @param values 闆嗗悎 - * @param value 鍗曞 - * - * @return boolean - */ - public static boolean contains(short[] values, short value) { - if (values == null) return false; - for (short v : values) { - if (v == value) return true; - } - return false; - } - - /** - * 鍒ゆ柇鎸囧畾鍊(涓嶈鍖呭惈鐩稿悓鐨勫厓绱)鏄惁鍖呭惈鎸囧畾鐨勬暟缁勪腑锛屽寘鍚繑鍥瀟rue - * - * @param values 闆嗗悎 - * @param items 澶氬 - * - * @return boolean - */ - public static boolean contains(short[] values, short... items) { - if (values == null) return false; - for (short item : items) { - if (!contains(values, item)) return false; - } - return true; - } - - /** - * 鍒ゆ柇鎸囧畾鍊兼槸鍚﹀寘鍚寚瀹氱殑鏁扮粍涓紝鍖呭惈杩斿洖true - * - * @param values 闆嗗悎 - * @param value 鍗曞 - * - * @return boolean - */ - public static boolean contains(int[] values, int value) { - if (values == null) return false; - for (int v : values) { - if (v == value) return true; - } - return false; - } - - /** - * 鍒ゆ柇鎸囧畾鍊(涓嶈鍖呭惈鐩稿悓鐨勫厓绱)鏄惁鍖呭惈鎸囧畾鐨勬暟缁勪腑锛屽寘鍚繑鍥瀟rue - * - * @param values 闆嗗悎 - * @param items 澶氬 - * - * @return boolean - */ - public static boolean contains(int[] values, int... items) { - if (values == null) return false; - for (int item : items) { - if (!contains(values, item)) return false; - } - return true; - } - - /** - * 鍒ゆ柇鎸囧畾鍊兼槸鍚﹀寘鍚寚瀹氱殑鏁扮粍涓紝鍖呭惈杩斿洖true - * - * @param values 闆嗗悎 - * @param value 鍗曞 - * - * @return boolean - */ - public static boolean contains(long[] values, long value) { - if (values == null) return false; - for (long v : values) { - if (v == value) return true; - } - return false; - } - - /** - * 鍒ゆ柇鎸囧畾鍊(涓嶈鍖呭惈鐩稿悓鐨勫厓绱)鏄惁鍖呭惈鎸囧畾鐨勬暟缁勪腑锛屽寘鍚繑鍥瀟rue - * - * @param values 闆嗗悎 - * @param items 澶氬 - * - * @return boolean - */ - public static boolean contains(long[] values, long... items) { - if (values == null) return false; - for (long item : items) { - if (!contains(values, item)) return false; - } - return true; - } - - /** - * 鍒ゆ柇鎸囧畾鍊兼槸鍚﹀寘鍚寚瀹氱殑鏁扮粍涓紝鍖呭惈杩斿洖true - * - * @param 娉涘瀷 - * @param values 闆嗗悎 - * @param value 鍗曞 - * - * @return boolean - */ - public static boolean contains(T[] values, T value) { - if (values == null) return false; - for (T v : values) { - if (Objects.equals(v, value)) return true; - } - return false; - } - - /** - * 鍒ゆ柇鎸囧畾鍊兼槸鍚﹀寘鍚寚瀹氱殑鏁扮粍涓紝鍖呭惈杩斿洖true - * - * @param 娉涘瀷 - * @param values 闆嗗悎 - * @param predicate 杩囨护鏉′欢 - * - * @return boolean - */ - public static boolean contains(T[] values, Predicate predicate) { - if (values == null) return false; - for (T v : values) { - if (predicate.test(v)) return true; - } - return false; - } - - /** - * 灏嗘寚瀹氱殑short鍏冪礌鏄惁鏁扮粍涓畬鍏ㄥ寘鍚紝閲嶅鍏冪礌鐨勬鏁颁篃瑕佺浉鍚
- * 渚嬪:
- * containsMatch(new short[]{1, 2, 2, 3, 3, 3}, 1, 2, 3, 3) = true
- * containsMatch(new short[]{1, 2, 2, 3, 3, 3}, 1, 1, 2, 3, 3) = false
- * - * @param array 鍘熸暟缁 - * @param items short[] - * - * @return 鏄惁瀹屽叏鍖呭惈 - */ - public static boolean containsMatch(final short[] array, final short... items) { - if (array == null) return false; - if (items == null || items.length == 0) return true; - if (array.length == 0 && items.length == 0) return true; - if (array.length < items.length) return false; - - short[] subs = array; - for (short item : items) { - if (!contains(subs, item)) return false; - short[] newsubs = new short[subs.length - 1]; - int k = 0; - boolean done = false; - for (short v : subs) { - if (done) { - newsubs[k++] = v; - } else if (v == item) { - done = true; - } else { - newsubs[k++] = v; - } - } - subs = newsubs; - } - return true; - } - - /** - * 灏嗘寚瀹氱殑int鍏冪礌鏄惁鏁扮粍涓畬鍏ㄥ寘鍚紝閲嶅鍏冪礌鐨勬鏁颁篃瑕佺浉鍚
- * 渚嬪:
- * containsMatch(new int[]{1, 2, 2, 3, 3, 3}, 1, 2, 3, 3) = true
- * containsMatch(new int[]{1, 2, 2, 3, 3, 3}, 1, 1, 2, 3, 3) = false
- * - * @param array 鍘熸暟缁 - * @param items int[] - * - * @return 鏄惁瀹屽叏鍖呭惈 - */ - public static boolean containsMatch(final int[] array, final int... items) { - if (array == null) return false; - if (items == null || items.length == 0) return true; - if (array.length == 0 && items.length == 0) return true; - if (array.length < items.length) return false; - - int[] subs = array; - for (int item : items) { - if (!contains(subs, item)) return false; - int[] newsubs = new int[subs.length - 1]; - int k = 0; - boolean done = false; - for (int v : subs) { - if (done) { - newsubs[k++] = v; - } else if (v == item) { - done = true; - } else { - newsubs[k++] = v; - } - } - subs = newsubs; - } - return true; - } - - /** - * 灏嗘寚瀹氱殑long鍏冪礌鏄惁鏁扮粍涓畬鍏ㄥ寘鍚紝閲嶅鍏冪礌鐨勬鏁颁篃瑕佺浉鍚
- * 渚嬪:
- * containsMatch(new long[]{1, 2, 2, 3, 3, 3}, 1, 2, 3, 3) = true
- * containsMatch(new long[]{1, 2, 2, 3, 3, 3}, 1, 1, 2, 3, 3) = false
- * - * @param array 鍘熸暟缁 - * @param items long[] - * - * @return 鏄惁瀹屽叏鍖呭惈 - */ - public static boolean containsMatch(final long[] array, final long... items) { - if (array == null) return false; - if (items == null || items.length == 0) return true; - if (array.length == 0 && items.length == 0) return true; - if (array.length < items.length) return false; - - long[] subs = array; - for (long item : items) { - if (!contains(subs, item)) return false; - long[] newsubs = new long[subs.length - 1]; - int k = 0; - boolean done = false; - for (long v : subs) { - if (done) { - newsubs[k++] = v; - } else if (v == item) { - done = true; - } else { - newsubs[k++] = v; - } - } - subs = newsubs; - } - return true; - } - - /** - * 鍒犻櫎鎺夊瓧绗︿覆鏁扮粍涓寘鍚寚瀹氱殑瀛楃涓 - * - * @param columns 寰呭垹闄ゆ暟缁 - * @param cols 闇鎺掗櫎鐨勫瓧绗︿覆 - * - * @return 鏂板瓧绗︿覆鏁扮粍 - */ - public static String[] exclude(final String[] columns, final String... cols) { - if (columns == null || columns.length == 0 || cols == null || cols.length == 0) return columns; - int count = 0; - for (String column : columns) { - boolean flag = false; - for (String col : cols) { - if (column != null && column.equals(col)) { - flag = true; - break; - } - } - if (flag) count++; - } - if (count == 0) return columns; - if (count == columns.length) return new String[0]; - final String[] newcols = new String[columns.length - count]; - count = 0; - for (String column : columns) { - boolean flag = false; - for (String col : cols) { - if (column != null && column.equals(col)) { - flag = true; - break; - } - } - if (!flag) newcols[count++] = column; - } - return newcols; - } - - /** - * 灏哹uffer鐨勫唴瀹硅浆鎹㈡垚瀛楃涓, string鍙傛暟涓嶄负绌烘椂浼氳拷鍔犲湪buffer鍐呭瀛楃涓蹭箣鍓 - * - * @param string 瀛楃涓插墠缂 - * @param buffer ByteBuffer - * - * @return 瀛楃涓 - */ - public static String toString(String string, ByteBuffer buffer) { - if (buffer == null || !buffer.hasRemaining()) return string; - int pos = buffer.position(); - int limit = buffer.limit(); - byte[] bytes = new byte[buffer.remaining()]; - buffer.get(bytes); - buffer.position(pos); - buffer.limit(limit); - if (string == null) return new String(bytes, UTF_8); - return string + new String(bytes, UTF_8); - } - - /** - * 灏哹uffer鐨勫唴瀹硅浆鎹㈡垚瀛楃涓插苟鎵撳嵃鍒版帶鍒跺彴, string鍙傛暟涓嶄负绌烘椂浼氳拷鍔犲湪buffer鍐呭瀛楃涓蹭箣鍓 - * - * @param string 瀛楃涓插墠缂 - * @param buffer ByteBuffer - * - */ - public static void println(String string, ByteBuffer buffer) { - if (buffer == null || !buffer.hasRemaining()) return; - int pos = buffer.position(); - int limit = buffer.limit(); - byte[] bytes = new byte[buffer.remaining()]; - buffer.get(bytes); - buffer.position(pos); - buffer.limit(limit); - println(string, bytes); - } - - /** - * 灏嗗瓧鑺傛暟缁勭殑鍐呭杞崲鎴愬瓧绗︿覆骞舵墦鍗板埌鎺у埗鍙, string鍙傛暟涓嶄负绌烘椂浼氳拷鍔犲湪瀛楄妭鏁扮粍鍐呭瀛楃涓蹭箣鍓 - * - * @param string 瀛楃涓插墠缂 - * @param bytes 瀛楄妭鏁扮粍 - * - */ - public static void println(String string, byte... bytes) { - if (bytes == null) return; - StringBuilder sb = new StringBuilder(); - if (string != null) sb.append(string); - sb.append(bytes.length).append(".["); - boolean last = false; - for (byte b : bytes) { - if (last) sb.append(','); - int v = b & 0xff; - sb.append("0x"); - if (v < 16) sb.append('0'); - sb.append(Integer.toHexString(v)); - last = true; - } - sb.append(']'); - (System.out).println(sb); - } - - /** - * 杩斿洖鏈満鐨勭涓涓唴缃慖Pv4鍦板潃锛 娌℃湁鍒欒繑鍥瀗ull - * - * @return IPv4鍦板潃 - */ - public static InetAddress localInetAddress() { - InetAddress back = null; - try { - Enumeration nifs = NetworkInterface.getNetworkInterfaces(); - while (nifs.hasMoreElements()) { - NetworkInterface nif = nifs.nextElement(); - if (!nif.isUp()) continue; - Enumeration eis = nif.getInetAddresses(); - while (eis.hasMoreElements()) { - InetAddress ia = eis.nextElement(); - if (ia.isLoopbackAddress() && ia instanceof Inet4Address) back = ia; - if (ia.isSiteLocalAddress() && ia instanceof Inet4Address) return ia; - } - } - } catch (Exception e) { - e.printStackTrace(); - } - return back; - } - - /** - * 鍒涘缓 CompletionHandler 瀵硅薄 - * - * @param 缁撴灉瀵硅薄鐨勬硾鍨 - * @param 闄勪欢瀵硅薄鐨勬硾鍨 - * @param success 鎴愬姛鐨勫洖璋冨嚱鏁 - * @param fail 澶辫触鐨勫洖璋冨嚱鏁 - * - * @return CompletionHandler - */ - public static CompletionHandler createAsyncHandler(final BiConsumer success, final BiConsumer fail) { - return new CompletionHandler() { - @Override - public void completed(V result, A attachment) { - if (success != null) success.accept(result, attachment); - } - - @Override - public void failed(Throwable exc, A attachment) { - if (fail != null) fail.accept(exc, attachment); - } - }; - } - - /** - * 鍒涘缓娌℃湁杩斿洖缁撴灉鐨 CompletionHandler 瀵硅薄 - * - * @param 闄勪欢瀵硅薄鐨勬硾鍨 - * @param success 鎴愬姛鐨勫洖璋冨嚱鏁 - * @param fail 澶辫触鐨勫洖璋冨嚱鏁 - * - * @return CompletionHandler - */ - public static CompletionHandler createAsyncHandler(final Consumer success, final BiConsumer fail) { - return new CompletionHandler() { - @Override - public void completed(Void result, A attachment) { - if (success != null) success.accept(attachment); - } - - @Override - public void failed(Throwable exc, A attachment) { - if (fail != null) fail.accept(exc, attachment); - } - }; - } - - /** - * 鍒涘缓娌℃湁闄勪欢瀵硅薄鐨 CompletionHandler 瀵硅薄 - * - * @param 缁撴灉瀵硅薄鐨勬硾鍨 - * @param success 鎴愬姛鐨勫洖璋冨嚱鏁 - * @param fail 澶辫触鐨勫洖璋冨嚱鏁 - * - * @return CompletionHandler - */ - public static CompletionHandler createAsyncHandler(final Consumer success, final Consumer fail) { - return new CompletionHandler() { - @Override - public void completed(V result, Void attachment) { - if (success != null) success.accept(result); - } - - @Override - public void failed(Throwable exc, Void attachment) { - if (fail != null) fail.accept(exc); - } - }; - } - - /** - * 鑾峰彇鏍煎紡涓簓yyy-MM-dd HH:mm:ss鐨勫綋鍓嶆椂闂 - * - * @return 鏍煎紡涓簓yyy-MM-dd HH:mm:ss鐨勬椂闂村 - */ - public static String now() { - return String.format(format1, System.currentTimeMillis()); - } - - /** - * 鑾峰彇鏍煎紡涓簓yyy-MM-dd HH:mm:ss.fff鐨勫綋鍓嶆椂闂 - * - * @return 鏍煎紡涓簓yyy-MM-dd HH:mm:ss.fff鐨勬椂闂村 - */ - public static String nowMillis() { - return String.format(format2, System.currentTimeMillis()); - } - - /** - * 灏嗘寚瀹氭椂闂存牸寮忓寲涓 yyyy-MM-dd HH:mm:ss - * - * @param time 寰呮牸寮忓寲鐨勬椂闂 - * - * @return 鏍煎紡涓簓yyy-MM-dd HH:mm:ss鐨勬椂闂村 - */ - public static String formatTime(long time) { - return String.format(format1, time); - } - - /** - * 灏嗘椂闂村艰浆鎹负闀垮害涓9鐨36杩涘埗鍊 - * - * @param time 鏃堕棿鍊 - * - * @return 36杩涘埗鏃堕棿鍊 - */ - public static String format36time(long time) { - return Long.toString(time, 36); - } - - /** - * 鑾峰彇褰撳ぉ鍑屾櫒闆剁偣鐨勬牸鏋楁椂闂 - * - * @return 姣鏁 - */ - public static long midnight() { - return midnight(System.currentTimeMillis()); - } - - /** - * 鑾峰彇鎸囧畾鏃堕棿褰撳ぉ鍑屾櫒闆剁偣鐨勬牸鏋楁椂闂 - * - * @param time 鎸囧畾鏃堕棿 - * - * @return 姣鏁 - */ - public static long midnight(long time) { - return (time + zoneRawOffset) / 86400000 * 86400000 - zoneRawOffset; - } - - /** - * 鑾峰彇褰撳ぉ20151231鏍煎紡鐨刬nt鍊 - * - * @return 20151231鏍煎紡鐨刬nt鍊 - */ - public static int today() { - java.time.LocalDate today = java.time.LocalDate.now(); - return today.getYear() * 10000 + today.getMonthValue() * 100 + today.getDayOfMonth(); - } - - /** - * 鑾峰彇褰撳ぉ151231鏍煎紡鐨刬nt鍊 - * - * @return 151231鏍煎紡鐨刬nt鍊 - */ - public static int todayYYMMDD() { - java.time.LocalDate today = java.time.LocalDate.now(); - return today.getYear() % 100 * 10000 + today.getMonthValue() * 100 + today.getDayOfMonth(); - } - - /** - * 鑾峰彇褰撳ぉ1512312359鏍煎紡鐨刬nt鍊 - * - * @return 1512312359鏍煎紡鐨刬nt鍊 - */ - public static int todayYYMMDDHHmm() { - java.time.LocalDateTime today = java.time.LocalDateTime.now(); - return today.getYear() % 100 * 100_00_00_00 + today.getMonthValue() * 100_00_00 + today.getDayOfMonth() * 100_00 - + today.getHour() * 100 + today.getMinute(); - } - - /** - * 鑾峰彇褰撳ぉ20151231235959鏍煎紡鐨刬nt鍊 - * - * @return 20151231235959鏍煎紡鐨刬nt鍊 - */ - public static long todayYYYYMMDDHHmmss() { - java.time.LocalDateTime today = java.time.LocalDateTime.now(); - return today.getYear() * 100_00_00_00_00L + today.getMonthValue() * 100_00_00_00 + today.getDayOfMonth() * 100_00_00 - + today.getHour() * 100_00 + today.getMinute() * 100 + today.getSecond(); - } - - /** - * 鑾峰彇褰撳ぉ151231235959鏍煎紡鐨刬nt鍊 - * - * @return 151231235959鏍煎紡鐨刬nt鍊 - */ - public static long todayYYMMDDHHmmss() { - java.time.LocalDateTime today = java.time.LocalDateTime.now(); - return today.getYear() % 100 * 100_00_00_00_00L + today.getMonthValue() * 100_00_00_00 + today.getDayOfMonth() * 100_00_00 - + today.getHour() * 100_00 + today.getMinute() * 100 + today.getSecond(); - } - - /** - * 鑾峰彇鏄庡ぉ20151230鏍煎紡鐨刬nt鍊 - * - * @return 20151230鏍煎紡鐨刬nt鍊 - */ - public static int tomorrow() { - Calendar cal = Calendar.getInstance(); - cal.add(Calendar.DAY_OF_YEAR, 1); - return cal.get(Calendar.YEAR) * 10000 + (cal.get(Calendar.MONTH) + 1) * 100 + cal.get(Calendar.DAY_OF_MONTH); - } - - /** - * 鑾峰彇鏄庡ぉ151230鏍煎紡鐨刬nt鍊 - * - * @return 151230鏍煎紡鐨刬nt鍊 - */ - public static int tomorrowYYMMDD() { - Calendar cal = Calendar.getInstance(); - cal.add(Calendar.DAY_OF_YEAR, 1); - return cal.get(Calendar.YEAR) % 100 * 10000 + (cal.get(Calendar.MONTH) + 1) * 100 + cal.get(Calendar.DAY_OF_MONTH); - } - - /** - * 鑾峰彇鏄ㄥぉ20151230鏍煎紡鐨刬nt鍊 - * - * @return 20151230鏍煎紡鐨刬nt鍊 - */ - public static int yesterday() { - Calendar cal = Calendar.getInstance(); - cal.add(Calendar.DAY_OF_YEAR, -1); - return cal.get(Calendar.YEAR) * 10000 + (cal.get(Calendar.MONTH) + 1) * 100 + cal.get(Calendar.DAY_OF_MONTH); - } - - /** - * 鑾峰彇鏄ㄥぉ151230鏍煎紡鐨刬nt鍊 - * - * @return 151230鏍煎紡鐨刬nt鍊 - */ - public static int yesterdayYYMMDD() { - Calendar cal = Calendar.getInstance(); - cal.add(Calendar.DAY_OF_YEAR, -1); - return cal.get(Calendar.YEAR) % 100 * 10000 + (cal.get(Calendar.MONTH) + 1) * 100 + cal.get(Calendar.DAY_OF_MONTH); - } - - /** - * 鑾峰彇鎸囧畾鏃堕棿鐨20160202鏍煎紡鐨刬nt鍊 - * - * @param time 鎸囧畾鏃堕棿 - * - * @return 姣鏁 - */ - public static int yyyyMMdd(long time) { - Calendar cal = Calendar.getInstance(); - cal.setTimeInMillis(time); - return cal.get(Calendar.YEAR) * 10000 + (cal.get(Calendar.MONTH) + 1) * 100 + cal.get(Calendar.DAY_OF_MONTH); - } - - /** - * 鑾峰彇鎸囧畾鏃堕棿鐨160202鏍煎紡鐨刬nt鍊 - * - * @param time 鎸囧畾鏃堕棿 - * - * @return 姣鏁 - */ - public static int yyMMdd(long time) { - Calendar cal = Calendar.getInstance(); - cal.setTimeInMillis(time); - return cal.get(Calendar.YEAR) % 100 * 10000 + (cal.get(Calendar.MONTH) + 1) * 100 + cal.get(Calendar.DAY_OF_MONTH); - } - - /** - * 鑾峰彇褰撳ぉ16020223鏍煎紡鐨刬nt鍊 - * - * @param time 鎸囧畾鏃堕棿 - * - * @return 16020223鏍煎紡鐨刬nt鍊 - */ - public static int yyMMDDHHmm(long time) { - Calendar cal = Calendar.getInstance(); - cal.setTimeInMillis(time); - return cal.get(Calendar.YEAR) % 100 * 100_00_00 + (cal.get(Calendar.MONTH) + 1) * 100_00 + cal.get(Calendar.DAY_OF_MONTH) * 100 + cal.get(Calendar.HOUR_OF_DAY); - } - - /** - * 鑾峰彇鏃堕棿鐐规墍鍦ㄦ槦鏈熺殑鍛ㄤ竴 - * - * @param time 鎸囧畾鏃堕棿 - * - * @return 姣鏁 - */ - public static long monday(long time) { - ZoneId zid = ZoneId.systemDefault(); - Instant instant = Instant.ofEpochMilli(time); - LocalDate ld = instant.atZone(zid).toLocalDate(); - ld = ld.minusDays(ld.getDayOfWeek().getValue() - 1); - return ld.atStartOfDay(zid).toInstant().toEpochMilli(); - } - - /** - * 鑾峰彇鏃堕棿鐐规墍鍦ㄦ槦鏈熺殑鍛ㄦ棩 - * - * @param time 鎸囧畾鏃堕棿 - * - * @return 姣鏁 - */ - public static long sunday(long time) { - ZoneId zid = ZoneId.systemDefault(); - Instant instant = Instant.ofEpochMilli(time); - LocalDate ld = instant.atZone(zid).toLocalDate(); - ld = ld.plusDays(7 - ld.getDayOfWeek().getValue()); - return ld.atStartOfDay(zid).toInstant().toEpochMilli(); - } - - /** - * 鑾峰彇鏃堕棿鐐规墍鍦ㄦ湀浠界殑1鍙 - * - * @param time 鎸囧畾鏃堕棿 - * - * @return 姣鏁 - */ - public static long monthFirstDay(long time) { - ZoneId zid = ZoneId.systemDefault(); - Instant instant = Instant.ofEpochMilli(time); - LocalDate ld = instant.atZone(zid).toLocalDate().withDayOfMonth(1); - return ld.atStartOfDay(zid).toInstant().toEpochMilli(); - } - - /** - * 鑾峰彇鏃堕棿鐐规墍鍦ㄦ湀浠界殑鏈鍚庝竴澶 - * - * @param time 鎸囧畾鏃堕棿 - * - * @return 姣鏁 - */ - public static long monthLastDay(long time) { - ZoneId zid = ZoneId.systemDefault(); - Instant instant = Instant.ofEpochMilli(time); - LocalDate ld = instant.atZone(zid).toLocalDate(); - ld = ld.withDayOfMonth(ld.lengthOfMonth()); - return ld.atStartOfDay(zid).toInstant().toEpochMilli(); - } - - /** - * 灏唅nt[]寮哄埗杞崲鎴恇yte[] - * - * @param value int[] - * - * @return byte[] - */ - public static byte[] intsToBytes(int[] value) { - if (value == null) return null; - byte[] bs = new byte[value.length]; - for (int i = 0; i < bs.length; i++) { - bs[i] = (byte) value[i]; - } - return bs; - } - - /** - * MD5鍔犲瘑 - * - * @param bs 寰呭姞瀵嗘暟鎹 - * - * @return md5鍊 - */ - public static String md5Hex(byte[] bs) { - return binToHexString(md5Bytes(bs)); - } - - /** - * MD5鍔犲瘑 - * - * @param bs 寰呭姞瀵嗘暟鎹 - * - * @return md5鍊 - */ - public static byte[] md5Bytes(byte[] bs) { - if (bs == null) return null; - MessageDigest md5; - try { - md5 = MessageDigest.getInstance("MD5"); - } catch (NoSuchAlgorithmException ex) { - throw new RuntimeException(ex); - } - return md5.digest(bs); - } - - /** - * MD5鍔犲瘑 - * - * @param str 寰呭姞瀵嗘暟鎹 - * - * @return md5鍊 - */ - public static String md5Hex(String str) { - return binToHexString(md5Bytes(str)); - } - - /** - * MD5鍔犲瘑 - * - * @param str 寰呭姞瀵嗘暟鎹 - * - * @return md5鍊 - */ - public static byte[] md5Bytes(String str) { - if (str == null) return null; - MessageDigest md5; - try { - md5 = MessageDigest.getInstance("MD5"); - } catch (NoSuchAlgorithmException ex) { - throw new RuntimeException(ex); - } - return md5.digest(str.getBytes()); - } - - /** - * SHA-256 - * - * @param bs 寰卙ash鏁版嵁 - * - * @return hash鍊 - */ - public static String sha256Hex(byte[] bs) { - return binToHexString(sha256Bytes(bs)); - } - - /** - * SHA-256 - * - * @param bs 寰卙ash鏁版嵁 - * - * @return hash鍊 - */ - public static byte[] sha256Bytes(byte[] bs) { - if (bs == null) return null; - MessageDigest digester; - try { - digester = MessageDigest.getInstance("SHA-256"); - } catch (NoSuchAlgorithmException ex) { - throw new RuntimeException(ex); - } - return digester.digest(bs); - } - - /** - * SHA-256 - * - * @param str 寰卙ash鏁版嵁 - * - * @return hash鍊 - */ - public static String sha256Hex(String str) { - return binToHexString(sha256Bytes(str)); - } - - /** - * SHA-256 - * - * @param str 寰卙ash鏁版嵁 - * - * @return hash鍊 - */ - public static byte[] sha256Bytes(String str) { - if (str == null) return null; - MessageDigest digester; - try { - digester = MessageDigest.getInstance("SHA-256"); - } catch (NoSuchAlgorithmException ex) { - throw new RuntimeException(ex); - } - return digester.digest(str.getBytes()); - } - - /** - * 灏嗗瓧鑺傛暟缁勮浆鎹负16杩涘埗瀛楃涓 - * - * @param bytes 瀛楄妭鏁扮粍 - * - * @return 16杩涘埗瀛楃涓 - */ - public static String binToHexString(byte[] bytes) { - return new String(binToHex(bytes)); - } - - /** - * 灏嗗瓧鑺傛暟缁勮浆鎹负16杩涘埗瀛楃鏁扮粍 - * - * @param bytes 瀛楄妭鏁扮粍 - * - * @return 16杩涘埗瀛楃涓茬殑瀛楃鏁扮粍 - */ - public static char[] binToHex(byte[] bytes) { - return binToHex(bytes, 0, bytes.length); - } - - /** - * 灏嗗瓧鑺傛暟缁勮浆鎹负16杩涘埗瀛楃涓 - * - * @param bytes 瀛楄妭鏁扮粍 - * @param offset 鍋忕Щ閲 - * @param len 闀垮害 - * - * @return 16杩涘埗瀛楃涓 - */ - public static String binToHexString(byte[] bytes, int offset, int len) { - return new String(binToHex(bytes, offset, len)); - } - - /** - * 灏嗗瓧鑺傛暟缁勮浆鎹负16杩涘埗瀛楃鏁扮粍 - * - * @param bytes 瀛楄妭鏁扮粍 - * @param offset 鍋忕Щ閲 - * @param len 闀垮害 - * - * @return 16杩涘埗瀛楃涓茬殑瀛楃鏁扮粍 - */ - public static char[] binToHex(byte[] bytes, int offset, int len) { - final char[] sb = new char[len * 2]; - final int end = offset + len; - int index = 0; - final char[] hexs = hex; - for (int i = offset; i < end; i++) { - byte b = bytes[i]; - sb[index++] = (hexs[((b >> 4) & 0xF)]); - sb[index++] = hexs[((b) & 0xF)]; - } - return sb; - } - - /** - * 灏16杩涘埗瀛楃涓茶浆鎹㈡垚瀛楄妭鏁扮粍 - * - * @param src 16杩涘埗瀛楃涓 - * - * @return 瀛楄妭鏁扮粍 - */ - public static byte[] hexToBin(CharSequence src) { - return hexToBin(src, 0, src.length()); - } - - /** - * - * 灏16杩涘埗瀛楃涓茶浆鎹㈡垚瀛楄妭鏁扮粍 - * - * @param src 16杩涘埗瀛楃涓 - * @param offset 鍋忕Щ閲 - * @param len 闀垮害 - * - * @return 瀛楄妭鏁扮粍 - */ - public static byte[] hexToBin(CharSequence src, int offset, int len) { - final int size = (len + 1) / 2; - final byte[] bytes = new byte[size]; - String digits = "0123456789abcdef"; - for (int i = 0; i < size; i++) { - int ch1 = src.charAt(offset + i * 2); - if ('A' <= ch1 && 'F' >= ch1) ch1 = ch1 - 'A' + 'a'; - int ch2 = src.charAt(offset + i * 2 + 1); - if ('A' <= ch2 && 'F' >= ch2) ch2 = ch2 - 'A' + 'a'; - int pos1 = digits.indexOf(ch1); - if (pos1 < 0) throw new NumberFormatException(); - int pos2 = digits.indexOf(ch2); - if (pos2 < 0) throw new NumberFormatException(); - bytes[i] = (byte) (pos1 * 0x10 + pos2); - } - return bytes; - } - - /** - * - * 灏16杩涘埗瀛楃涓茶浆鎹㈡垚瀛楄妭鏁扮粍 - * - * @param str 16杩涘埗瀛楃涓 - * - * @return 瀛楄妭鏁扮粍 - */ - public static byte[] hexToBin(String str) { - return hexToBin(charArray(str)); - } - - /** - * - * 灏16杩涘埗瀛楃鏁扮粍杞崲鎴愬瓧鑺傛暟缁 - * - * @param src 16杩涘埗瀛楃鏁扮粍 - * - * @return 瀛楄妭鏁扮粍 - */ - public static byte[] hexToBin(char[] src) { - return hexToBin(src, 0, src.length); - } - - /** - * 灏16杩涘埗瀛楃鏁扮粍杞崲鎴愬瓧鑺傛暟缁 - * - * @param src 16杩涘埗瀛楃鏁扮粍 - * @param offset 鍋忕Щ閲 - * @param len 闀垮害 - * - * @return 瀛楄妭鏁扮粍 - */ - public static byte[] hexToBin(char[] src, int offset, int len) { - final int size = (len + 1) / 2; - final byte[] bytes = new byte[size]; - String digits = "0123456789abcdef"; - for (int i = 0; i < size; i++) { - int ch1 = src[offset + i * 2]; - if ('A' <= ch1 && 'F' >= ch1) ch1 = ch1 - 'A' + 'a'; - int ch2 = src[offset + i * 2 + 1]; - if ('A' <= ch2 && 'F' >= ch2) ch2 = ch2 - 'A' + 'a'; - int pos1 = digits.indexOf(ch1); - if (pos1 < 0) throw new NumberFormatException(); - int pos2 = digits.indexOf(ch2); - if (pos2 < 0) throw new NumberFormatException(); - bytes[i] = (byte) (pos1 * 0x10 + pos2); - } - return bytes; - } - - //----------------------------------------------------------------------------- - /** - * 浣跨敤UTF-8缂栫爜灏哹yte[]杞崲鎴恈har[] - * - * @param array byte[] - * - * @return char[] - */ - public static char[] decodeUTF8(final byte[] array) { - return decodeUTF8(array, 0, array.length); - } - - public static char[] decodeUTF8(final byte[] array, final int start, final int len) { - byte b; - int size = len; - final byte[] bytes = array; - final int limit = start + len; - for (int i = start; i < limit; i++) { - b = bytes[i]; - if ((b >> 5) == -2) {// 2 bytes, 11 bits: 110xxxxx 10xxxxxx - size--; - } else if ((b >> 4) == -2) {// 3 bytes, 16 bits: 1110xxxx 10xxxxxx 10xxxxxx - size -= 2; - } else if ((b >> 3) == -2) {// 4 bytes, 21 bits: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - size -= 2; - } - } - final char[] text = new char[size]; - size = 0; - for (int i = start; i < limit;) { - b = bytes[i++]; - if (b >= 0) {// 1 byte, 7 bits: 0xxxxxxx - text[size++] = (char) b; - } else if ((b >> 5) == -2) {// 2 bytes, 11 bits: 110xxxxx 10xxxxxx - text[size++] = (char) (((b << 6) ^ bytes[i++]) ^ (((byte) 0xC0 << 6) ^ ((byte) 0x80))); - } else if ((b >> 4) == -2) {// 3 bytes, 16 bits: 1110xxxx 10xxxxxx 10xxxxxx - text[size++] = (char) ((b << 12) ^ (bytes[i++] << 6) ^ (bytes[i++] ^ (((byte) 0xE0 << 12) ^ ((byte) 0x80 << 6) ^ ((byte) 0x80)))); - } else if ((b >> 3) == -2) {// 4 bytes, 21 bits: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - int uc = ((b << 18) ^ (bytes[i++] << 12) ^ (bytes[i++] << 6) ^ (bytes[i++] ^ (((byte) 0xF0 << 18) ^ ((byte) 0x80 << 12) ^ ((byte) 0x80 << 6) ^ ((byte) 0x80)))); - text[size++] = Character.highSurrogate(uc); - text[size++] = Character.lowSurrogate(uc); - //娴嬭瘯浠g爜 byte[] bs = {(byte)34, (byte)76, (byte)105, (byte)108, (byte)121, (byte)240, (byte)159, (byte)146, (byte)171, (byte)34}; - } - } - return text; - } - - public static byte[] encodeUTF8(final String value) { - if (value == null) return new byte[0]; - if (strCharFunction == null) return encodeUTF8(value.toCharArray()); - return encodeUTF8((char[]) strCharFunction.apply(value)); - } - - public static byte[] encodeUTF8(final char[] array) { - return encodeUTF8(array, 0, array.length); - } - - public static byte[] encodeUTF8(final char[] text, final int start, final int len) { - char c; - int size = 0; - final char[] chs = text; - final int limit = start + len; - for (int i = start; i < limit; i++) { - c = chs[i]; - if (c < 0x80) { - size++; - } else if (c < 0x800) { - size += 2; - } else if (Character.isSurrogate(c)) { - size += 2; - } else { - size += 3; - } - } - final byte[] bytes = new byte[size]; - size = 0; - for (int i = start; i < limit; i++) { - c = chs[i]; - if (c < 0x80) { - bytes[size++] = (byte) c; - } else if (c < 0x800) { - bytes[size++] = (byte) (0xc0 | (c >> 6)); - bytes[size++] = (byte) (0x80 | (c & 0x3f)); - } else if (Character.isSurrogate(c)) { //杩炲彇涓や釜 - int uc = Character.toCodePoint(c, chs[i + 1]); - bytes[size++] = (byte) (0xf0 | ((uc >> 18))); - bytes[size++] = (byte) (0x80 | ((uc >> 12) & 0x3f)); - bytes[size++] = (byte) (0x80 | ((uc >> 6) & 0x3f)); - bytes[size++] = (byte) (0x80 | (uc & 0x3f)); - i++; - } else { - bytes[size++] = (byte) (0xe0 | ((c >> 12))); - bytes[size++] = (byte) (0x80 | ((c >> 6) & 0x3f)); - bytes[size++] = (byte) (0x80 | (c & 0x3f)); - } - } - return bytes; - } - - public static long getAddress(ByteBuffer buffer) { - return bufferAddrFunction.applyAsLong(buffer); - } - - public static boolean isLatin1(String value) { - if (value == null) return true; - if (strLatin1Function != null) { - return strLatin1Function.test(value); //LATIN1:0 UTF16:1 - } - char[] chs = charArray(value); - for (char ch : chs) { - if (ch >= 0x80) return false; - } - return true; - } - - public static char[] charArray(String value) { - if (value == null) return null; - if (strCharFunction == null) return value.toCharArray(); - return (char[]) strCharFunction.apply(value); - } - - public static char[] charArray(StringBuilder value) { - if (value == null) return null; - if (sbCharFunction == null) return value.toString().toCharArray(); - return (char[]) sbCharFunction.apply(value); - } - - //鍙兘鏄崟瀛楄妭瀛楃涓 - public static byte[] latin1ByteArray(String latin1Value) { - if (latin1Value == null) return null; - if (strByteFunction == null) return latin1Value.getBytes(); - return (byte[]) strByteFunction.apply(latin1Value); - } - - //鍙兘鏄崟瀛楄妭瀛楃涓 - public static byte[] latin1ByteArray(StringBuilder latin1Value) { - if (latin1Value == null) return null; - if (sbByteFunction == null) return latin1Value.toString().getBytes(); - return (byte[]) sbByteFunction.apply(latin1Value); - } - - public static ByteBuffer encodeUTF8(final ByteBuffer buffer, final char[] array) { - return encodeUTF8(buffer, array, 0, array.length); - } - - public static ByteBuffer encodeUTF8(final ByteBuffer buffer, int bytesLength, final char[] array) { - return encodeUTF8(buffer, bytesLength, array, 0, array.length); - } - - public static int encodeUTF8Length(String value) { - if (value == null) return -1; - if (strCharFunction == null) return encodeUTF8Length(value.toCharArray()); - return encodeUTF8Length((char[]) strCharFunction.apply(value)); - } - - public static int encodeUTF8Length(final char[] text) { - return encodeUTF8Length(text, 0, text.length); - } - - public static int encodeUTF8Length(final char[] text, final int start, final int len) { - char c; - int size = 0; - final char[] chs = text; - final int limit = start + len; - for (int i = start; i < limit; i++) { - c = chs[i]; - if (c < 0x80) { - size++; - } else if (c < 0x800) { - size += 2; - } else if (Character.isSurrogate(c)) { - size += 2; - } else { - size += 3; - } - } - return size; - } - - /** - * 灏嗕袱涓暟瀛楃粍瑁呮垚涓涓猯ong - * - * @param high 楂樹綅鍊 - * @param low 浣庝綅鍊 - * - * @return long鍊 - */ - public static long merge(int high, int low) { - return (0L + high) << 32 | low; - } - - public static ByteBuffer encodeUTF8(final ByteBuffer buffer, final char[] text, final int start, final int len) { - return encodeUTF8(buffer, encodeUTF8Length(text, start, len), text, start, len); - } - - //杩斿洖鐨凚yteBuffer涓烘墿灞昩uffer锛屼负null琛ㄧず鍙傛暟涓殑buffer瓒冲瀛樺偍鏁版嵁 - public static ByteBuffer encodeUTF8(final ByteBuffer buffer, int bytesLength, final char[] text, final int start, final int len) { - char c; - char[] chs = text; - final int limit = start + len; - int remain = buffer.remaining(); - final ByteBuffer buffer2 = remain >= bytesLength ? null : ByteBuffer.allocate(bytesLength - remain + 4); //鏈宸儏鍐礲uffer鏈鍚庝袱byte娌℃湁濉厖 - ByteBuffer buf = buffer; - for (int i = start; i < limit; i++) { - c = chs[i]; - if (c < 0x80) { - if (buf.remaining() < 1) buf = buffer2; - buf.put((byte) c); - } else if (c < 0x800) { - if (buf.remaining() < 2) buf = buffer2; - buf.put((byte) (0xc0 | (c >> 6))); - buf.put((byte) (0x80 | (c & 0x3f))); - } else if (Character.isSurrogate(c)) { //杩炲彇涓や釜 - if (buf.remaining() < 4) buf = buffer2; - int uc = Character.toCodePoint(c, chs[i + 1]); - buf.put((byte) (0xf0 | ((uc >> 18)))); - buf.put((byte) (0x80 | ((uc >> 12) & 0x3f))); - buf.put((byte) (0x80 | ((uc >> 6) & 0x3f))); - buf.put((byte) (0x80 | (uc & 0x3f))); - i++; - } else { - if (buf.remaining() < 3) buf = buffer2; - buf.put((byte) (0xe0 | ((c >> 12)))); - buf.put((byte) (0x80 | ((c >> 6) & 0x3f))); - buf.put((byte) (0x80 | (c & 0x3f))); - } - } - if (buffer2 != null) buffer2.flip(); - return buffer2; //杩斿洖鎵╁睍buffer - } - - public static String getTypeDescriptor(java.lang.reflect.Type type) { - if (type == null) return null; - if (type instanceof Class) { - Class d = (Class) type; - final StringBuilder sb = new StringBuilder(); - while (true) { - if (d.isPrimitive()) { - char car; - if (d == Integer.TYPE) { - car = 'I'; - } else if (d == Void.TYPE) { - car = 'V'; - } else if (d == Boolean.TYPE) { - car = 'Z'; - } else if (d == Byte.TYPE) { - car = 'B'; - } else if (d == Character.TYPE) { - car = 'C'; - } else if (d == Short.TYPE) { - car = 'S'; - } else if (d == Double.TYPE) { - car = 'D'; - } else if (d == Float.TYPE) { - car = 'F'; - } else /* if (d == Long.TYPE) */ { - car = 'J'; - } - return sb.append(car).toString(); - } else if (d.isArray()) { - sb.append('['); - d = d.getComponentType(); - } else { - sb.append('L'); - String name = d.getName(); - int len = name.length(); - for (int i = 0; i < len; ++i) { - char car = name.charAt(i); - sb.append(car == '.' ? '/' : car); - } - return sb.append(';').toString(); - } - } - } - if (type instanceof ParameterizedType) {// 渚嬪: Map - ParameterizedType pt = (ParameterizedType) type; - final StringBuilder sb = new StringBuilder(); - String raw = getTypeDescriptor(pt.getRawType()); - sb.append(raw.substring(0, raw.length() - 1)).append('<'); - for (java.lang.reflect.Type item : pt.getActualTypeArguments()) { - sb.append(getTypeDescriptor(item)); - } - return sb.append(">;").toString(); - } - if (type instanceof WildcardType) { // 渚嬪: - final WildcardType wt = (WildcardType) type; - final StringBuilder sb = new StringBuilder(); - java.lang.reflect.Type[] us = wt.getUpperBounds(); - java.lang.reflect.Type[] ls = wt.getLowerBounds(); - if (ls.length < 1) { - if (us.length == 1 && us[0] == Object.class) { - sb.append('*'); - } else { - for (java.lang.reflect.Type f : us) { - sb.append('+'); - sb.append(getTypeDescriptor(f)); - } - } - } - for (java.lang.reflect.Type f : ls) { - sb.append('-'); - sb.append(getTypeDescriptor(f)); - } - return sb.toString(); - } - //TypeVariable 涓嶆敮鎸 - return null; - } - - //----------------------------------------------------------------------------- -// public static javax.net.ssl.SSLContext getDefaultSSLContext() { -// return DEFAULTSSL_CONTEXT; -// } -// -// public static javax.net.ssl.HostnameVerifier getDefaultHostnameVerifier() { -// return defaultVerifier; -// } -// -// public static Socket createDefaultSSLSocket(InetSocketAddress address) throws IOException { -// return createDefaultSSLSocket(address.getAddress(), address.getPort()); -// } -// -// public static Socket createDefaultSSLSocket(InetAddress host, int port) throws IOException { -// Socket socket = DEFAULTSSL_CONTEXT.getSocketFactory().createSocket(host, port); -// return socket; -// } - // - public static String postHttpContent(String url) throws IOException { - return remoteHttpContent("POST", url, 0, null, null).toString(StandardCharsets.UTF_8); - } - - public static String postHttpContent(String url, int timeout) throws IOException { - return remoteHttpContent("POST", url, timeout, null, null).toString(StandardCharsets.UTF_8); - } - - public static String postHttpContent(String url, String body) throws IOException { - return remoteHttpContent("POST", url, 0, null, body).toString(StandardCharsets.UTF_8); - } - - public static String postHttpContent(String url, int timeout, String body) throws IOException { - return remoteHttpContent("POST", url, timeout, null, body).toString(StandardCharsets.UTF_8); - } - - public static String postHttpContent(String url, Map headers, String body) throws IOException { - return remoteHttpContent("POST", url, 0, headers, body).toString(StandardCharsets.UTF_8); - } - - public static String postHttpContent(String url, int timeout, Map headers, String body) throws IOException { - return remoteHttpContent("POST", url, timeout, headers, body).toString(StandardCharsets.UTF_8); - } - - public static String postHttpContent(String url, Charset charset) throws IOException { - return remoteHttpContent("POST", url, 0, null, null).toString(charset.name()); - } - - public static String postHttpContent(String url, int timeout, Charset charset) throws IOException { - return remoteHttpContent("POST", url, timeout, null, null).toString(charset.name()); - } - - public static String postHttpContent(String url, Charset charset, String body) throws IOException { - return remoteHttpContent("POST", url, 0, null, body).toString(charset.name()); - } - - public static String postHttpContent(String url, int timeout, Charset charset, String body) throws IOException { - return remoteHttpContent("POST", url, timeout, null, body).toString(charset.name()); - } - - public static String postHttpContent(String url, Charset charset, Map headers, String body) throws IOException { - return remoteHttpContent("POST", url, 0, headers, body).toString(charset.name()); - } - - public static String postHttpContent(String url, int timeout, Charset charset, Map headers, String body) throws IOException { - return remoteHttpContent("POST", url, timeout, headers, body).toString(charset.name()); - } - - public static byte[] postHttpBytesContent(String url) throws IOException { - return remoteHttpContent("POST", url, 0, null, null).toByteArray(); - } - - public static byte[] postHttpBytesContent(String url, int timeout) throws IOException { - return remoteHttpContent("POST", url, timeout, null, null).toByteArray(); - } - - public static byte[] postHttpBytesContent(String url, Map headers, String body) throws IOException { - return remoteHttpContent("POST", url, 0, headers, body).toByteArray(); - } - - public static byte[] postHttpBytesContent(String url, int timeout, Map headers, String body) throws IOException { - return remoteHttpContent("POST", url, timeout, headers, body).toByteArray(); - } - - public static String getHttpContent(String url) throws IOException { - return remoteHttpContent("GET", url, 0, null, null).toString(StandardCharsets.UTF_8); - } - - public static String getHttpContent(String url, int timeout) throws IOException { - return remoteHttpContent("GET", url, timeout, null, null).toString(StandardCharsets.UTF_8); - } - - public static String getHttpContent(String url, Map headers, String body) throws IOException { - return remoteHttpContent("GET", url, 0, headers, body).toString(StandardCharsets.UTF_8); - } - - public static String getHttpContent(String url, int timeout, Map headers, String body) throws IOException { - return remoteHttpContent("GET", url, timeout, headers, body).toString(StandardCharsets.UTF_8); - } - - public static String getHttpContent(String url, Charset charset) throws IOException { - return remoteHttpContent("GET", url, 0, null, null).toString(charset.name()); - } - - public static String getHttpContent(String url, int timeout, Charset charset) throws IOException { - return remoteHttpContent("GET", url, timeout, null, null).toString(charset.name()); - } - - public static String getHttpContent(String url, Charset charset, Map headers, String body) throws IOException { - return remoteHttpContent("GET", url, 0, headers, body).toString(charset.name()); - } - - public static String getHttpContent(String url, int timeout, Charset charset, Map headers, String body) throws IOException { - return remoteHttpContent("GET", url, timeout, headers, body).toString(charset.name()); - } - - public static byte[] getHttpBytesContent(String url) throws IOException { - return remoteHttpContent("GET", url, 0, null, null).toByteArray(); - } - - public static byte[] getHttpBytesContent(String url, int timeout) throws IOException { - return remoteHttpContent("GET", url, timeout, null, null).toByteArray(); - } - - public static byte[] getHttpBytesContent(String url, Map headers, String body) throws IOException { - return remoteHttpContent("GET", url, 0, headers, body).toByteArray(); - } - - public static byte[] getHttpBytesContent(String url, int timeout, Map headers, String body) throws IOException { - return remoteHttpContent("GET", url, timeout, headers, body).toByteArray(); - } - - public static ByteArrayOutputStream remoteHttpContent(String method, String url, Map headers, String body) throws IOException { - return remoteHttpContent(method, url, 0, headers, body); - } - - public static ByteArrayOutputStream remoteHttpContent(String method, String url, int timeout, Map headers, String body) throws IOException { - return remoteHttpContentAsync(method, url, timeout, headers, body).join(); - } - - public static CompletableFuture postHttpContentAsync(String url) { - return remoteHttpContentAsync("POST", url, 0, null, null).thenApply(out -> out.toString(StandardCharsets.UTF_8)); - } - - public static CompletableFuture postHttpContentAsync(String url, int timeout) { - return remoteHttpContentAsync("POST", url, timeout, null, null).thenApply(out -> out.toString(StandardCharsets.UTF_8)); - } - - public static CompletableFuture postHttpContentAsync(String url, String body) { - return remoteHttpContentAsync("POST", url, 0, null, body).thenApply(out -> out.toString(StandardCharsets.UTF_8)); - } - - public static CompletableFuture postHttpContentAsync(String url, int timeout, String body) { - return remoteHttpContentAsync("POST", url, timeout, null, body).thenApply(out -> out.toString(StandardCharsets.UTF_8)); - } - - public static CompletableFuture postHttpContentAsync(String url, Map headers, String body) { - return remoteHttpContentAsync("POST", url, 0, headers, body).thenApply(out -> out.toString(StandardCharsets.UTF_8)); - } - - public static CompletableFuture postHttpContentAsync(String url, int timeout, Map headers, String body) { - return remoteHttpContentAsync("POST", url, timeout, headers, body).thenApply(out -> out.toString(StandardCharsets.UTF_8)); - } - - public static CompletableFuture postHttpContentAsync(String url, Charset charset) { - return remoteHttpContentAsync("POST", url, 0, null, null).thenApply(out -> out.toString(charset)); - } - - public static CompletableFuture postHttpContentAsync(String url, int timeout, Charset charset) { - return remoteHttpContentAsync("POST", url, timeout, null, null).thenApply(out -> out.toString(charset)); - } - - public static CompletableFuture postHttpContentAsync(String url, Charset charset, String body) { - return remoteHttpContentAsync("POST", url, 0, null, body).thenApply(out -> out.toString(charset)); - } - - public static CompletableFuture postHttpContentAsync(HttpClient client, String url, Charset charset, String body) { - return remoteHttpContentAsync(client, "POST", url, 0, null, body).thenApply(out -> out.toString(charset)); - } - - public static CompletableFuture postHttpContentAsync(String url, int timeout, Charset charset, String body) { - return remoteHttpContentAsync("POST", url, timeout, null, body).thenApply(out -> out.toString(charset)); - } - - public static CompletableFuture postHttpContentAsync(String url, Charset charset, Map headers, String body) { - return remoteHttpContentAsync("POST", url, 0, headers, body).thenApply(out -> out.toString(charset)); - } - - public static CompletableFuture postHttpContentAsync(String url, int timeout, Charset charset, Map headers, String body) { - return remoteHttpContentAsync("POST", url, timeout, headers, body).thenApply(out -> out.toString(charset)); - } - - public static CompletableFuture postHttpBytesContentAsync(String url) { - return remoteHttpContentAsync("POST", url, 0, null, null).thenApply(out -> out.toByteArray()); - } - - public static CompletableFuture postHttpBytesContentAsync(String url, int timeout) { - return remoteHttpContentAsync("POST", url, timeout, null, null).thenApply(out -> out.toByteArray()); - } - - public static CompletableFuture postHttpBytesContentAsync(String url, Map headers, String body) { - return remoteHttpContentAsync("POST", url, 0, headers, body).thenApply(out -> out.toByteArray()); - } - - public static CompletableFuture postHttpBytesContentAsync(String url, int timeout, Map headers, String body) { - return remoteHttpContentAsync("POST", url, timeout, headers, body).thenApply(out -> out.toByteArray()); - } - - public static CompletableFuture getHttpContentAsync(String url) { - return remoteHttpContentAsync("GET", url, 0, null, null).thenApply(out -> out.toString(StandardCharsets.UTF_8)); - } - - public static CompletableFuture getHttpContentAsync(String url, int timeout) { - return remoteHttpContentAsync("GET", url, timeout, null, null).thenApply(out -> out.toString(StandardCharsets.UTF_8)); - } - - public static CompletableFuture getHttpContentAsync(String url, Map headers, String body) { - return remoteHttpContentAsync("GET", url, 0, headers, body).thenApply(out -> out.toString(StandardCharsets.UTF_8)); - } - - public static CompletableFuture getHttpContentAsync(String url, int timeout, Map headers, String body) { - return remoteHttpContentAsync("GET", url, timeout, headers, body).thenApply(out -> out.toString(StandardCharsets.UTF_8)); - } - - public static CompletableFuture getHttpContentAsync(String url, Charset charset) { - return remoteHttpContentAsync("GET", url, 0, null, null).thenApply(out -> out.toString(charset)); - } - - public static CompletableFuture getHttpContentAsync(String url, int timeout, Charset charset) { - return remoteHttpContentAsync("GET", url, timeout, null, null).thenApply(out -> out.toString(charset)); - } - - public static CompletableFuture getHttpContentAsync(String url, Charset charset, Map headers, String body) { - return remoteHttpContentAsync("GET", url, 0, headers, body).thenApply(out -> out.toString(charset)); - } - - public static CompletableFuture getHttpContentAsync(String url, int timeout, Charset charset, Map headers, String body) { - return remoteHttpContentAsync("GET", url, timeout, headers, body).thenApply(out -> out.toString(charset)); - } - - public static CompletableFuture getHttpBytesContentAsync(String url) { - return remoteHttpContentAsync("GET", url, 0, null, null).thenApply(out -> out.toByteArray()); - } - - public static CompletableFuture getHttpBytesContentAsync(String url, int timeout) { - return remoteHttpContentAsync("GET", url, timeout, null, null).thenApply(out -> out.toByteArray()); - } - - public static CompletableFuture getHttpBytesContentAsync(String url, Map headers, String body) { - return remoteHttpContentAsync("GET", url, 0, headers, body).thenApply(out -> out.toByteArray()); - } - - public static CompletableFuture getHttpBytesContentAsync(String url, int timeout, Map headers, String body) { - return remoteHttpContentAsync("GET", url, timeout, headers, body).thenApply(out -> out.toByteArray()); - } - - public static CompletableFuture remoteHttpContentAsync(String method, String url, Map headers, String body) { - return remoteHttpContentAsync(method, url, 0, headers, body); - } - - public static CompletableFuture remoteHttpContentAsync(String method, String url, int timeout, Map headers, String body) { - return remoteHttpContentAsync(httpClient, method, url, timeout, headers, body); - } - - public static CompletableFuture remoteHttpContentAsync(java.net.http.HttpClient client, String method, String url, int timeout, Map headers, String body) { - java.net.http.HttpRequest.Builder builder = java.net.http.HttpRequest.newBuilder().uri(URI.create(url)) - .timeout(Duration.ofMillis(timeout > 0 ? timeout : 6000)) - .method(method, body == null ? java.net.http.HttpRequest.BodyPublishers.noBody() : java.net.http.HttpRequest.BodyPublishers.ofString(body)); - if (headers != null) headers.forEach((n, v) -> builder.header(n, v)); - java.net.http.HttpClient c = client == null ? httpClient : client; - if (c == null) { - synchronized (clientLock) { - if (httpClient == null) { - httpClient = java.net.http.HttpClient.newHttpClient(); - } - } - c = httpClient; - } - return c.sendAsync(builder.build(), java.net.http.HttpResponse.BodyHandlers.ofByteArray()) - .thenCompose((java.net.http.HttpResponse resp) -> { - final int rs = resp.statusCode(); - if (rs == 301 || rs == 302) { - Optional opt = resp.headers().firstValue("Location"); - if (opt.isPresent()) { - return remoteHttpContentAsync(client, method, opt.get(), timeout, headers, body); - } else { - return CompletableFuture.failedFuture(new IOException(url + " httpcode = " + rs + ", but not found Localtion")); - } - } - byte[] result = resp.body(); - if (rs == 200 || result != null) { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - if (result != null) { - if ("gzip".equalsIgnoreCase(resp.headers().firstValue("content-encoding").orElse(null))) { - try { - GZIPInputStream in = new GZIPInputStream(new ByteArrayInputStream(result)); - in.transferTo(out); - } catch (IOException e) { - return CompletableFuture.failedFuture(e); - } - } else { - out.writeBytes(result); - } - } - return CompletableFuture.completedFuture(out); - } - return CompletableFuture.failedFuture(new IOException(url + " httpcode = " + rs)); - }); - } -// -// public static ByteArrayOutputStream remoteHttpContent(SSLContext ctx, String method, String url, int timeout, Map headers, String body) throws IOException { -// HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection(); -// boolean opening = true; -// try { -// conn.setConnectTimeout(timeout > 0 ? timeout : 3000); -// conn.setReadTimeout(timeout > 0 ? timeout : 3000); -// if (conn instanceof HttpsURLConnection) { -// HttpsURLConnection httpsconn = ((HttpsURLConnection) conn); -// httpsconn.setSSLSocketFactory((ctx == null ? DEFAULTSSL_CONTEXT : ctx).getSocketFactory()); -// httpsconn.setHostnameVerifier(defaultVerifier); -// } -// conn.setRequestMethod(method); -// if (headers != null) { -// for (Map.Entry en : headers.entrySet()) { -// conn.setRequestProperty(en.getKey(), en.getValue()); -// } -// } -// if (body != null && !body.isEmpty()) { //conn.getOutputStream()浼氬皢GET寮哄埗鍙樻垚POST -// conn.setDoInput(true); -// conn.setDoOutput(true); -// conn.getOutputStream().write(body.getBytes(UTF_8)); -// } -// conn.connect(); -// int rs = conn.getResponseCode(); -// if (rs == 301 || rs == 302) { -// String newurl = conn.getHeaderField("Location"); -// conn.disconnect(); -// opening = false; -// return remoteHttpContent(ctx, method, newurl, timeout, headers, body); -// } -// InputStream in = (rs < 400 || rs == 404) && rs != 405 ? conn.getInputStream() : conn.getErrorStream(); -// if ("gzip".equalsIgnoreCase(conn.getContentEncoding())) in = new GZIPInputStream(in); -// ByteArrayOutputStream out = new ByteArrayOutputStream(1024); -// byte[] bytes = new byte[1024]; -// int pos; -// while ((pos = in.read(bytes)) != -1) { -// out.write(bytes, 0, pos); -// } -// in.close(); -// return out; -// } finally { -// if (opening) conn.disconnect(); -// } -// } - - public static String read(InputStream in) throws IOException { - return read(in, StandardCharsets.UTF_8, false); - } - - public static String readThenClose(InputStream in) throws IOException { - return read(in, StandardCharsets.UTF_8, true); - } - - public static String read(InputStream in, String charsetName) throws IOException { - return read(in, Charset.forName(charsetName), false); - } - - public static String read(InputStream in, Charset charset) throws IOException { - return read(in, charset, false); - } - - private static String read(InputStream in, Charset charset, boolean close) throws IOException { - ByteArrayOutputStream out = new ByteArrayOutputStream(1024); - byte[] bytes = new byte[1024]; - int pos; - while ((pos = in.read(bytes)) != -1) { - out.write(bytes, 0, pos); - } - if (close) in.close(); - return charset == null ? out.toString() : out.toString(charset); - } - - public static ByteArrayOutputStream readStream(InputStream in) throws IOException { - return readStream(in, false); - } - - public static ByteArrayOutputStream readStreamThenClose(InputStream in) throws IOException { - return readStream(in, true); - } - - private static ByteArrayOutputStream readStream(InputStream in, boolean close) throws IOException { - ByteArrayOutputStream out = new ByteArrayOutputStream(1024); - byte[] bytes = new byte[1024]; - int pos; - while ((pos = in.read(bytes)) != -1) { - out.write(bytes, 0, pos); - } - if (close) in.close(); - return out; - } - - public static byte[] readBytes(File file) throws IOException { - return readBytesThenClose(new FileInputStream(file)); - } - - public static byte[] readBytes(InputStream in) throws IOException { - return readStream(in).toByteArray(); - } - - public static byte[] readBytesThenClose(InputStream in) throws IOException { - return readStreamThenClose(in).toByteArray(); - } -} +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkale.util; + +import java.io.*; +import java.lang.reflect.*; +import java.net.*; +import java.net.http.HttpClient; +import java.nio.*; +import java.nio.channels.CompletionHandler; +import java.nio.charset.*; +import static java.nio.charset.StandardCharsets.UTF_8; +import java.security.*; +import java.time.*; +import java.util.*; +import java.util.concurrent.*; +import java.util.function.*; +import java.util.stream.Stream; +import java.util.zip.GZIPInputStream; + +/** + * + * 甯歌鎿嶄綔鐨勫伐鍏风被 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public final class Utility { + + private static final int zoneRawOffset = TimeZone.getDefault().getRawOffset(); + + static final String format1 = "%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS"; //yyyy-MM-dd HH:mm:ss + + static final String format2 = "%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%1$tL"; //yyyy-MM-dd HH:mm:ss.fff + + private static final char hex[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + + private static final int MAX_POW2 = 1 << 30; + + private static final Class JAVA_RECORD_CLASS; + + private static final IntFunction futureArrayFunc = c -> new CompletableFuture[c]; + + static { + Class clz = null; + try { + clz = Thread.currentThread().getContextClassLoader().loadClass("java.lang.Record"); + } catch (Throwable t) { //JDK14浠ヤ笅鐗堟湰浼氬紓甯 + } + JAVA_RECORD_CLASS = clz; + } + + private static final String funcAnonymousUnsafeBinary = "cafebabe0000003701710a000200030700040c000500060100106a6176612f6c616e672f4f626a6563740100063c696e69743e01000328295607000801000f73756e2f6d6973632f556e7361666509000a000b07000c0c000d000e0100206f72672f7265646b616c652f7574696c2f416e6f6e796d6f7573556e73616665010006756e736166650100114c73756e2f6d6973632f556e736166653b0a000700100c00110012010006676574496e74010016284c6a6176612f6c616e672f4f626a6563743b4a29490a000700140c00150016010006707574496e74010017284c6a6176612f6c616e672f4f626a6563743b4a4929560a000700180c0019001a0100096765744f626a656374010027284c6a6176612f6c616e672f4f626a6563743b4a294c6a6176612f6c616e672f4f626a6563743b0a0007001c0c001d001e0100097075744f626a656374010028284c6a6176612f6c616e672f4f626a6563743b4a4c6a6176612f6c616e672f4f626a6563743b29560a000700200c0021002201000a676574426f6f6c65616e010016284c6a6176612f6c616e672f4f626a6563743b4a295a0a000700240c0025002601000a707574426f6f6c65616e010017284c6a6176612f6c616e672f4f626a6563743b4a5a29560a000700280c0029002a01000767657442797465010016284c6a6176612f6c616e672f4f626a6563743b4a29420a0007002c0c002d002e01000770757442797465010017284c6a6176612f6c616e672f4f626a6563743b4a4229560a000700300c0031003201000867657453686f7274010016284c6a6176612f6c616e672f4f626a6563743b4a29530a000700340c0035003601000870757453686f7274010017284c6a6176612f6c616e672f4f626a6563743b4a5329560a000700380c0039003a01000767657443686172010016284c6a6176612f6c616e672f4f626a6563743b4a29430a0007003c0c003d003e01000770757443686172010017284c6a6176612f6c616e672f4f626a6563743b4a4329560a000700400c004100420100076765744c6f6e67010016284c6a6176612f6c616e672f4f626a6563743b4a294a0a000700440c004500460100077075744c6f6e67010017284c6a6176612f6c616e672f4f626a6563743b4a4a29560a000700480c0049004a010008676574466c6f6174010016284c6a6176612f6c616e672f4f626a6563743b4a29460a0007004c0c004d004e010008707574466c6f6174010017284c6a6176612f6c616e672f4f626a6563743b4a4629560a000700500c00510052010009676574446f75626c65010016284c6a6176612f6c616e672f4f626a6563743b4a29440a000700540c00550056010009707574446f75626c65010017284c6a6176612f6c616e672f4f626a6563743b4a4429560a000700580c00290059010004284a29420a0007005b0c002d005c010005284a4229560a0007005e0c0031005f010004284a29530a000700610c00350062010005284a5329560a000700640c00390065010004284a29430a000700670c003d0068010005284a4329560a0007006a0c0011006b010004284a29490a0007006d0c0015006e010005284a4929560a000700700c00410071010004284a294a0a000700730c00450074010005284a4a29560a000700760c00490077010004284a29460a000700790c004d007a010005284a4629560a0007007c0c0051007d010004284a29440a0007007f0c00550080010005284a4429560a000700820c0083007101000a676574416464726573730a000700850c0086007401000a707574416464726573730a000700880c0089007101000e616c6c6f636174654d656d6f72790a0007008b0c008c008d0100107265616c6c6f636174654d656d6f7279010005284a4a294a0a0007008f0c009000910100097365744d656d6f7279010018284c6a6176612f6c616e672f4f626a6563743b4a4a4229560a000700930c00900094010006284a4a4229560a000700960c0097009801000a636f70794d656d6f727901002a284c6a6176612f6c616e672f4f626a6563743b4a4c6a6176612f6c616e672f4f626a6563743b4a4a29560a0007009a0c0097009b010006284a4a4a29560a0007009d0c009e009f01000a667265654d656d6f7279010004284a29560a000700a10c00a200a30100116f626a6563744669656c644f666673657401001c284c6a6176612f6c616e672f7265666c6563742f4669656c643b294a0a000700a50c00a600a30100117374617469634669656c644f66667365740a000700a80c00a900aa01000f7374617469634669656c644261736501002d284c6a6176612f6c616e672f7265666c6563742f4669656c643b294c6a6176612f6c616e672f4f626a6563743b0a000700ac0c00ad00ae01000f6172726179426173654f6666736574010014284c6a6176612f6c616e672f436c6173733b29490a000700b00c00b100ae01000f6172726179496e6465785363616c650a000700b30c00b400b501000b6164647265737353697a650100032829490a000700b70c00b800b50100087061676553697a650a000700ba0c00bb00bc010010616c6c6f63617465496e7374616e6365010025284c6a6176612f6c616e672f436c6173733b294c6a6176612f6c616e672f4f626a6563743b0a000700be0c00bf00c001000e7468726f77457863657074696f6e010018284c6a6176612f6c616e672f5468726f7761626c653b29560a000700c20c00c300c4010014636f6d70617265416e64537761704f626a65637401003a284c6a6176612f6c616e672f4f626a6563743b4a4c6a6176612f6c616e672f4f626a6563743b4c6a6176612f6c616e672f4f626a6563743b295a0a000700c60c00c700c8010011636f6d70617265416e6453776170496e74010018284c6a6176612f6c616e672f4f626a6563743b4a4949295a0a000700ca0c00cb00cc010012636f6d70617265416e64537761704c6f6e67010018284c6a6176612f6c616e672f4f626a6563743b4a4a4a295a0a000700ce0c00cf001a0100116765744f626a656374566f6c6174696c650a000700d10c00d2001e0100117075744f626a656374566f6c6174696c650a000700d40c00d5001201000e676574496e74566f6c6174696c650a000700d70c00d8001601000e707574496e74566f6c6174696c650a000700da0c00db0022010012676574426f6f6c65616e566f6c6174696c650a000700dd0c00de0026010012707574426f6f6c65616e566f6c6174696c650a000700e00c00e1002a01000f67657442797465566f6c6174696c650a000700e30c00e4002e01000f70757442797465566f6c6174696c650a000700e60c00e7003201001067657453686f7274566f6c6174696c650a000700e90c00ea003601001070757453686f7274566f6c6174696c650a000700ec0c00ed003a01000f67657443686172566f6c6174696c650a000700ef0c00f0003e01000f70757443686172566f6c6174696c650a000700f20c00f3004201000f6765744c6f6e67566f6c6174696c650a000700f50c00f6004601000f7075744c6f6e67566f6c6174696c650a000700f80c00f9004a010010676574466c6f6174566f6c6174696c650a000700fb0c00fc004e010010707574466c6f6174566f6c6174696c650a000700fe0c00ff0052010011676574446f75626c65566f6c6174696c650a000701010c01020056010011707574446f75626c65566f6c6174696c650a000701040c0105001e0100107075744f7264657265644f626a6563740a000701070c0108001601000d7075744f726465726564496e740a0007010a0c010b004601000e7075744f7264657265644c6f6e670a0007010d0c010e010f010006756e7061726b010015284c6a6176612f6c616e672f4f626a6563743b29560a000701110c011201130100047061726b010005285a4a29560a000701150c0116011701000e6765744c6f616441766572616765010006285b444929490a000701190c011a011b01000c676574416e64416464496e74010017284c6a6176612f6c616e672f4f626a6563743b4a4929490a0007011d0c011e011f01000d676574416e644164644c6f6e67010017284c6a6176612f6c616e672f4f626a6563743b4a4a294a0a000701210c0122011b01000c676574416e64536574496e740a000701240c0125011f01000d676574416e645365744c6f6e670a000701270c0128012901000f676574416e645365744f626a656374010039284c6a6176612f6c616e672f4f626a6563743b4a4c6a6176612f6c616e672f4f626a6563743b294c6a6176612f6c616e672f4f626a6563743b0a0007012b0c012c00060100096c6f616446656e63650a0007012e0c012f000601000a73746f726546656e63650a000701310c0132000601000966756c6c46656e63650a000701340c0135013601000d696e766f6b65436c65616e6572010018284c6a6176612f6e696f2f427974654275666665723b29560701380100176f72672f7265646b616c652f7574696c2f556e73616665010004436f646501000f4c696e654e756d6265725461626c650100124c6f63616c5661726961626c655461626c65010004746869730100224c6f72672f7265646b616c652f7574696c2f416e6f6e796d6f7573556e736166653b0100036f626a0100124c6a6176612f6c616e672f4f626a6563743b0100104d6574686f64506172616d65746572730100016f0100066f66667365740100014a01000178010001490100015a010001420100015301000143010001460100014401000761646472657373010005627974657301000576616c7565010007737263426173650100097372634f6666736574010008646573744261736501000a646573744f666673657401000a7372634164647265737301000b6465737441646472657373010001660100194c6a6176612f6c616e672f7265666c6563742f4669656c643b01000a6172726179436c6173730100114c6a6176612f6c616e672f436c6173733b0100164c6f63616c5661726961626c65547970655461626c650100144c6a6176612f6c616e672f436c6173733c2a3e3b0100095369676e6174757265010017284c6a6176612f6c616e672f436c6173733c2a3e3b2949010003636c7301000a457863657074696f6e730701600100206a6176612f6c616e672f496e7374616e74696174696f6e457863657074696f6e010028284c6a6176612f6c616e672f436c6173733c2a3e3b294c6a6176612f6c616e672f4f626a6563743b01000265650100154c6a6176612f6c616e672f5468726f7761626c653b010008657870656374656401000674687265616401000a69734162736f6c75746501000474696d650100076c6f61646176670100025b440100066e656c656d7301000564656c74610100086e657756616c756501000c6469726563744275666665720100154c6a6176612f6e696f2f427974654275666665723b01000a536f7572636546696c65010014416e6f6e796d6f7573556e736166652e6a6176610021000a00020001013700010012000d000e0000005700010005010f0002013900000049000200020000000d2ab700012a2bc00007b50009b100000002013a0000000e00030000000a0004000b000c000c013b0000001600020000000d013c013d00000000000d013e013f000101400000000501013e00000001001100120002013900000048000400040000000a2ab400092b20b6000fac00000002013a00000006000100000010013b0000002000030000000a013c013d00000000000a0141013f00010000000a0142014300020140000000090201410000014200000001001500160002013900000058000500050000000c2ab400092b201504b60013b100000002013a0000000a000200000015000b0016013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c01440145000401400000000d0301410000014200000144000000010019001a0002013900000048000400040000000a2ab400092b20b60017b000000002013a0000000600010000001a013b0000002000030000000a013c013d00000000000a0141013f00010000000a0142014300020140000000090201410000014200000001001d001e0002013900000058000500050000000c2ab400092b201904b6001bb100000002013a0000000a00020000001f000b0020013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c0144013f000401400000000d030141000001420000014400000001002100220002013900000048000400040000000a2ab400092b20b6001fac00000002013a00000006000100000024013b0000002000030000000a013c013d00000000000a0141013f00010000000a0142014300020140000000090201410000014200000001002500260002013900000058000500050000000c2ab400092b201504b60023b100000002013a0000000a000200000029000b002a013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c01440146000401400000000d0301410000014200000144000000010029002a0002013900000048000400040000000a2ab400092b20b60027ac00000002013a0000000600010000002e013b0000002000030000000a013c013d00000000000a0141013f00010000000a0142014300020140000000090201410000014200000001002d002e0002013900000058000500050000000c2ab400092b201504b6002bb100000002013a0000000a000200000033000b0034013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c01440147000401400000000d030141000001420000014400000001003100320002013900000048000400040000000a2ab400092b20b6002fac00000002013a00000006000100000038013b0000002000030000000a013c013d00000000000a0141013f00010000000a0142014300020140000000090201410000014200000001003500360002013900000058000500050000000c2ab400092b201504b60033b100000002013a0000000a00020000003d000b003e013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c01440148000401400000000d0301410000014200000144000000010039003a0002013900000048000400040000000a2ab400092b20b60037ac00000002013a00000006000100000042013b0000002000030000000a013c013d00000000000a0141013f00010000000a0142014300020140000000090201410000014200000001003d003e0002013900000058000500050000000c2ab400092b201504b6003bb100000002013a0000000a000200000047000b0048013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c01440149000401400000000d030141000001420000014400000001004100420002013900000048000400040000000a2ab400092b20b6003fad00000002013a0000000600010000004c013b0000002000030000000a013c013d00000000000a0141013f00010000000a0142014300020140000000090201410000014200000001004500460002013900000058000600060000000c2ab400092b201604b60043b100000002013a0000000a000200000051000b0052013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c01440143000401400000000d0301410000014200000144000000010049004a0002013900000048000400040000000a2ab400092b20b60047ae00000002013a00000006000100000056013b0000002000030000000a013c013d00000000000a0141013f00010000000a0142014300020140000000090201410000014200000001004d004e0002013900000058000500050000000c2ab400092b201704b6004bb100000002013a0000000a00020000005b000b005c013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c0144014a000401400000000d030141000001420000014400000001005100520002013900000048000400040000000a2ab400092b20b6004faf00000002013a00000006000100000060013b0000002000030000000a013c013d00000000000a0141013f00010000000a0142014300020140000000090201410000014200000001005500560002013900000058000600060000000c2ab400092b201804b60053b100000002013a0000000a000200000065000b0066013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c0144014b000401400000000d03014100000142000001440000000100290059000201390000003d00030003000000092ab400091fb60057ac00000002013a0000000600010000006a013b00000016000200000009013c013d000000000009014c0143000101400000000501014c00000001002d005c000201390000004c000400040000000a2ab400091f1db6005ab100000002013a0000000a00020000006f00090070013b0000002000030000000a013c013d00000000000a014c014300010000000a01440147000301400000000902014c00000144000000010031005f000201390000003d00030003000000092ab400091fb6005dac00000002013a00000006000100000074013b00000016000200000009013c013d000000000009014c0143000101400000000501014c0000000100350062000201390000004c000400040000000a2ab400091f1db60060b100000002013a0000000a0002000000790009007a013b0000002000030000000a013c013d00000000000a014c014300010000000a01440148000301400000000902014c000001440000000100390065000201390000003d00030003000000092ab400091fb60063ac00000002013a0000000600010000007e013b00000016000200000009013c013d000000000009014c0143000101400000000501014c00000001003d0068000201390000004c000400040000000a2ab400091f1db60066b100000002013a0000000a00020000008300090084013b0000002000030000000a013c013d00000000000a014c014300010000000a01440149000301400000000902014c00000144000000010011006b000201390000003d00030003000000092ab400091fb60069ac00000002013a00000006000100000088013b00000016000200000009013c013d000000000009014c0143000101400000000501014c000000010015006e000201390000004c000400040000000a2ab400091f1db6006cb100000002013a0000000a00020000008d0009008e013b0000002000030000000a013c013d00000000000a014c014300010000000a01440145000301400000000902014c000001440000000100410071000201390000003d00030003000000092ab400091fb6006fad00000002013a00000006000100000092013b00000016000200000009013c013d000000000009014c0143000101400000000501014c0000000100450074000201390000004c000500050000000a2ab400091f21b60072b100000002013a0000000a00020000009700090098013b0000002000030000000a013c013d00000000000a014c014300010000000a01440143000301400000000902014c000001440000000100490077000201390000003d00030003000000092ab400091fb60075ae00000002013a0000000600010000009c013b00000016000200000009013c013d000000000009014c0143000101400000000501014c00000001004d007a000201390000004c000400040000000a2ab400091f25b60078b100000002013a0000000a0002000000a1000900a2013b0000002000030000000a013c013d00000000000a014c014300010000000a0144014a000301400000000902014c00000144000000010051007d000201390000003d00030003000000092ab400091fb6007baf00000002013a000000060001000000a6013b00000016000200000009013c013d000000000009014c0143000101400000000501014c0000000100550080000201390000004c000500050000000a2ab400091f29b6007eb100000002013a0000000a0002000000ab000900ac013b0000002000030000000a013c013d00000000000a014c014300010000000a0144014b000301400000000902014c000001440000000100830071000201390000003d00030003000000092ab400091fb60081ad00000002013a000000060001000000b0013b00000016000200000009013c013d000000000009014c0143000101400000000501014c0000000100860074000201390000004c000500050000000a2ab400091f21b60084b100000002013a0000000a0002000000b5000900b6013b0000002000030000000a013c013d00000000000a014c014300010000000a01440143000301400000000902014c000001440000000100890071000201390000003d00030003000000092ab400091fb60087ad00000002013a000000060001000000ba013b00000016000200000009013c013d000000000009014d0143000101400000000501014d00000001008c008d0002013900000048000500050000000a2ab400091f21b6008aad00000002013a000000060001000000bf013b0000002000030000000a013c013d00000000000a014c014300010000000a014d0143000301400000000902014c0000014d00000001009000910002013900000064000700070000000e2ab400092b2016041506b6008eb100000002013a0000000a0002000000c4000d00c5013b0000003400050000000e013c013d00000000000e0141013f00010000000e0142014300020000000e014d014300040000000e014e01470006014000000011040141000001420000014d0000014e00000001009000940002013900000058000600060000000c2ab400091f211505b60092b100000002013a0000000a0002000000c9000b00ca013b0000002a00040000000c013c013d00000000000c014c014300010000000c014d014300030000000c014e0147000501400000000d03014c0000014d0000014e0000000100970098000201390000007000090009000000102ab400092b20190416051607b60095b100000002013a0000000a0002000000ce000f00cf013b0000003e000600000010013c013d000000000010014f013f000100000010015001430002000000100151013f00040000001001520143000500000010014d0143000701400000001505014f0000015000000151000001520000014d000000010097009b0002013900000058000700070000000c2ab400091f211605b60099b100000002013a0000000a0002000000d3000b00d4013b0000002a00040000000c013c013d00000000000c0153014300010000000c0154014300030000000c014d0143000501400000000d030153000001540000014d00000001009e009f000201390000004100030003000000092ab400091fb6009cb100000002013a0000000a0002000000d8000800d9013b00000016000200000009013c013d000000000009014c0143000101400000000501014c0000000100a200a3000201390000003d00020002000000092ab400092bb600a0ad00000002013a000000060001000000dd013b00000016000200000009013c013d0000000000090155015600010140000000050101550000000100a600a3000201390000003d00020002000000092ab400092bb600a4ad00000002013a000000060001000000e2013b00000016000200000009013c013d0000000000090155015600010140000000050101550000000100a900aa000201390000003d00020002000000092ab400092bb600a7b000000002013a000000060001000000e7013b00000016000200000009013c013d0000000000090155015600010140000000050101550000000100ad00ae000301390000004f00020002000000092ab400092bb600abac00000003013a000000060001000000ec013b00000016000200000009013c013d00000000000901570158000101590000000c0001000000090157015a00010140000000050101570000015b00000002015c000100b100ae000301390000004f00020002000000092ab400092bb600afac00000003013a000000060001000000f1013b00000016000200000009013c013d00000000000901570158000101590000000c0001000000090157015a00010140000000050101570000015b00000002015c000100b400b5000101390000003200010001000000082ab40009b600b2ac00000002013a000000060001000000f6013b0000000c000100000008013c013d0000000100b800b5000101390000003200010001000000082ab40009b600b6ac00000002013a000000060001000000fb013b0000000c000100000008013c013d0000000100bb00bc000401390000004f00020002000000092ab400092bb600b9b000000003013a00000006000100000100013b00000016000200000009013c013d000000000009015d0158000101590000000c000100000009015d015a0001015e000000040001015f01400000000501015d0000015b000000020161000100bf00c0000201390000004100020002000000092ab400092bb600bdb100000002013a0000000a00020000010500080106013b00000016000200000009013c013d0000000000090162016300010140000000050101620000000100c300c40002013900000060000600060000000e2ab400092b2019041905b600c1ac00000002013a0000000600010000010a013b0000003400050000000e013c013d00000000000e0141013f00010000000e0142014300020000000e0164013f00040000000e0144013f00050140000000110401410000014200000164000001440000000100c700c80002013900000060000600060000000e2ab400092b2015041505b600c5ac00000002013a0000000600010000010f013b0000003400050000000e013c013d00000000000e0141013f00010000000e0142014300020000000e0164014500040000000e0144014500050140000000110401410000014200000164000001440000000100cb00cc0002013900000060000800080000000e2ab400092b2016041606b600c9ac00000002013a00000006000100000114013b0000003400050000000e013c013d00000000000e0141013f00010000000e0142014300020000000e0164014300040000000e0144014300060140000000110401410000014200000164000001440000000100cf001a0002013900000048000400040000000a2ab400092b20b600cdb000000002013a00000006000100000119013b0000002000030000000a013c013d00000000000a0141013f00010000000a014201430002014000000009020141000001420000000100d2001e0002013900000058000500050000000c2ab400092b201904b600d0b100000002013a0000000a00020000011e000b011f013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c0144013f000401400000000d03014100000142000001440000000100d500120002013900000048000400040000000a2ab400092b20b600d3ac00000002013a00000006000100000123013b0000002000030000000a013c013d00000000000a0141013f00010000000a014201430002014000000009020141000001420000000100d800160002013900000058000500050000000c2ab400092b201504b600d6b100000002013a0000000a000200000128000b0129013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c01440145000401400000000d03014100000142000001440000000100db00220002013900000048000400040000000a2ab400092b20b600d9ac00000002013a0000000600010000012d013b0000002000030000000a013c013d00000000000a0141013f00010000000a014201430002014000000009020141000001420000000100de00260002013900000058000500050000000c2ab400092b201504b600dcb100000002013a0000000a000200000132000b0133013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c01440146000401400000000d03014100000142000001440000000100e1002a0002013900000048000400040000000a2ab400092b20b600dfac00000002013a00000006000100000137013b0000002000030000000a013c013d00000000000a0141013f00010000000a014201430002014000000009020141000001420000000100e4002e0002013900000058000500050000000c2ab400092b201504b600e2b100000002013a0000000a00020000013c000b013d013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c01440147000401400000000d03014100000142000001440000000100e700320002013900000048000400040000000a2ab400092b20b600e5ac00000002013a00000006000100000141013b0000002000030000000a013c013d00000000000a0141013f00010000000a014201430002014000000009020141000001420000000100ea00360002013900000058000500050000000c2ab400092b201504b600e8b100000002013a0000000a000200000146000b0147013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c01440148000401400000000d03014100000142000001440000000100ed003a0002013900000048000400040000000a2ab400092b20b600ebac00000002013a0000000600010000014b013b0000002000030000000a013c013d00000000000a0141013f00010000000a014201430002014000000009020141000001420000000100f0003e0002013900000058000500050000000c2ab400092b201504b600eeb100000002013a0000000a000200000150000b0151013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c01440149000401400000000d03014100000142000001440000000100f300420002013900000048000400040000000a2ab400092b20b600f1ad00000002013a00000006000100000155013b0000002000030000000a013c013d00000000000a0141013f00010000000a014201430002014000000009020141000001420000000100f600460002013900000058000600060000000c2ab400092b201604b600f4b100000002013a0000000a00020000015a000b015b013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c01440143000401400000000d03014100000142000001440000000100f9004a0002013900000048000400040000000a2ab400092b20b600f7ae00000002013a0000000600010000015f013b0000002000030000000a013c013d00000000000a0141013f00010000000a014201430002014000000009020141000001420000000100fc004e0002013900000058000500050000000c2ab400092b201704b600fab100000002013a0000000a000200000164000b0165013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c0144014a000401400000000d03014100000142000001440000000100ff00520002013900000048000400040000000a2ab400092b20b600fdaf00000002013a00000006000100000169013b0000002000030000000a013c013d00000000000a0141013f00010000000a0142014300020140000000090201410000014200000001010200560002013900000058000600060000000c2ab400092b201804b60100b100000002013a0000000a00020000016e000b016f013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c0144014b000401400000000d0301410000014200000144000000010105001e0002013900000058000500050000000c2ab400092b201904b60103b100000002013a0000000a000200000173000b0174013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c0144013f000401400000000d030141000001420000014400000001010800160002013900000058000500050000000c2ab400092b201504b60106b100000002013a0000000a000200000178000b0179013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c01440145000401400000000d030141000001420000014400000001010b00460002013900000058000600060000000c2ab400092b201604b60109b100000002013a0000000a00020000017d000b017e013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c01440143000401400000000d030141000001420000014400000001010e010f000201390000004100020002000000092ab400092bb6010cb100000002013a0000000a00020000018200080183013b00000016000200000009013c013d0000000000090165013f00010140000000050101650000000101120113000201390000004c000400040000000a2ab400091b20b60110b100000002013a0000000a00020000018700090188013b0000002000030000000a013c013d00000000000a0166014600010000000a0167014300020140000000090201660000016700000001011601170002013900000048000300030000000a2ab400092b1cb60114ac00000002013a0000000600010000018c013b0000002000030000000a013c013d00000000000a0168016900010000000a016a014500020140000000090201680000016a00000001011a011b0002013900000054000500050000000c2ab400092b201504b60118ac00000002013a00000006000100000191013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c016b0145000401400000000d030141000001420000016b00000001011e011f0002013900000054000600060000000c2ab400092b201604b6011cad00000002013a00000006000100000196013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c016b0143000401400000000d030141000001420000016b000000010122011b0002013900000054000500050000000c2ab400092b201504b60120ac00000002013a0000000600010000019b013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c016c0145000401400000000d030141000001420000016c000000010125011f0002013900000054000600060000000c2ab400092b201604b60123ad00000002013a000000060001000001a0013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c016c0143000401400000000d030141000001420000016c00000001012801290002013900000054000500050000000c2ab400092b201904b60126b000000002013a000000060001000001a5013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c016c013f000401400000000d030141000001420000016c00000001012c0006000101390000003600010001000000082ab40009b6012ab100000002013a0000000a0002000001aa000701ab013b0000000c000100000008013c013d00000001012f0006000101390000003600010001000000082ab40009b6012db100000002013a0000000a0002000001af000701b0013b0000000c000100000008013c013d0000000101320006000101390000003600010001000000082ab40009b60130b100000002013a0000000a0002000001b4000701b5013b0000000c000100000008013c013d0000000101350136000201390000004100020002000000092ab400092bb60133b100000002013a0000000a0002000001b9000801ba013b00000016000200000009013c013d000000000009016d016e000101400000000501016d00000001016f000000020170"; + + private static final Unsafe unsafeInstance; + + //------------------------------------------------------------------------------- + private static final Function strByteFunction; + + private static final Function sbByteFunction; + + private static final Function strCharFunction; + + private static final Function sbCharFunction; + + private static final Predicate strLatin1Function; + + private static final ToLongFunction bufferAddrFunction; + + private static final Object clientLock = new Object(); + + private static HttpClient httpClient; + + //private static final javax.net.ssl.SSLContext DEFAULTSSL_CONTEXT; + //private static final javax.net.ssl.HostnameVerifier defaultVerifier = (s, ss) -> true; + static { + Unsafe unsafe0 = null; + Function strCharFunction0 = null; + Function sbCharFunction0 = null; + Function strByteFunction0 = null; + Function sbByteFunction0 = null; + Predicate strLatin1Function0 = null; + ToLongFunction bufferAddrFunction0 = null; + + if (!"executable".equals(System.getProperty("org.graalvm.nativeimage.kind"))) { //not native-image + try { + Field f = String.class.getDeclaredField("value"); + final ClassLoader loader = Thread.currentThread().getContextClassLoader(); + final Class unsafeClass = loader.loadClass("sun.misc.Unsafe"); + final Field safeField = unsafeClass.getDeclaredField("theUnsafe"); + RedkaleClassLoader.putReflectionField("sun.misc.Unsafe", safeField); + safeField.setAccessible(true); + final Object usafe = safeField.get(null); + + Class unsafeClazz1 = null; + try { + unsafeClazz1 = (Class) loader.loadClass("org.re" + "dkale.util.AnonymousUnsafe"); + } catch (Throwable t) { + } + if (unsafeClazz1 == null) { + byte[] classBytes = hexToBin(funcAnonymousUnsafeBinary); + unsafeClazz1 = (Class) new ClassLoader(loader) { + public final Class loadClass(String name, byte[] b) { + return defineClass(name, b, 0, b.length); + } + }.loadClass("org.re" + "dkale.util.AnonymousUnsafe", classBytes); + RedkaleClassLoader.putDynClass(unsafeClazz1.getName(), classBytes, unsafeClazz1); + } + RedkaleClassLoader.putReflectionDeclaredConstructors(unsafeClazz1, unsafeClazz1.getName(), Object.class); + unsafe0 = unsafeClazz1.getConstructor(Object.class).newInstance(usafe); + + final Unsafe unsafe = unsafe0; + final long fd1 = unsafe0.objectFieldOffset(f); + final long fd2 = unsafe0.objectFieldOffset(StringBuilder.class.getSuperclass().getDeclaredField("value")); + final long fd3 = unsafe0.objectFieldOffset(String.class.getDeclaredField("coder")); + final long fd4 = unsafe0.objectFieldOffset(Buffer.class.getDeclaredField("address")); + + strByteFunction0 = new Function() { + public Object apply(Object t) { + return unsafe.getObject(t, fd1); + } + }; + sbByteFunction0 = new Function() { + public Object apply(Object t) { + return unsafe.getObject(t, fd2); + } + }; + strLatin1Function0 = new Predicate() { + public boolean test(Object t) { + return unsafe.getByte(t, fd3) == 0; //LATIN1:0 UTF16:1 + } + }; + bufferAddrFunction0 = new ToLongFunction() { + public long applyAsLong(Object t) { + return unsafe.getLong(t, fd4); + } + }; + } catch (Throwable e) { //涓嶄細鍙戠敓 + e.printStackTrace(); + } + + } + unsafeInstance = unsafe0; + strCharFunction = strCharFunction0; + sbCharFunction = sbCharFunction0; + strByteFunction = strByteFunction0; + sbByteFunction = sbByteFunction0; + strLatin1Function = strLatin1Function0; + bufferAddrFunction = bufferAddrFunction0; + +// try { +// DEFAULTSSL_CONTEXT = javax.net.ssl.SSLContext.getInstance("SSL"); +// DEFAULTSSL_CONTEXT.init(null, new javax.net.ssl.TrustManager[]{new javax.net.ssl.X509TrustManager() { +// @Override +// public java.security.cert.X509Certificate[] getAcceptedIssuers() { +// return null; +// } +// +// @Override +// public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) throws java.security.cert.CertificateException { +// } +// +// @Override +// public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) throws java.security.cert.CertificateException { +// } +// }}, null); +// } catch (Exception e) { +// throw new RuntimeException(e); //涓嶄細鍙戠敓 +// } + } + + private Utility() { + } + + public static Unsafe unsafe() { + return unsafeInstance; + } + + public static int cpus() { + return Runtime.getRuntime().availableProcessors(); + } + + /** + * @param value from which next positive power of two will be found. + * + * @return the next positive power of 2, this value if it is a power of 2. Negative values are mapped to 1. + * @throws IllegalArgumentException is value is more than MAX_POW2 or less than 0 + */ + public static int roundToPowerOfTwo(final int value) { + if (value > MAX_POW2) throw new IllegalArgumentException("There is no larger power of 2 int for value:" + value + " since it exceeds 2^31."); + if (value < 0) throw new IllegalArgumentException("Given value:" + value + ". Expecting value >= 0."); + return 1 << (32 - Integer.numberOfLeadingZeros(value - 1)); + } + + public static boolean isRecordGetter(Method method) { + return isRecordGetter(method.getDeclaringClass(), method); + } + + public static boolean isRecordGetter(Class clazz, Method method) { + if (JAVA_RECORD_CLASS == null) return false; + if (method.getReturnType() == void.class) return false; + if (method.getParameterCount() != 0) return false; + if (method.getName().equals("getClass")) return false; + Class clz = (clazz == null ? method.getDeclaringClass() : clazz); + if (!JAVA_RECORD_CLASS.isAssignableFrom(clz)) return false; + try { + return clz.getDeclaredField(method.getName()).getType() == method.getReturnType(); + } catch (Throwable t) { + return false; + } + } + + public static CompletableFuture orTimeout(CompletableFuture future, long timeout, TimeUnit unit) { + return future.orTimeout(timeout, unit); + } + + public static CompletableFuture completeOnTimeout(CompletableFuture future, T value, long timeout, TimeUnit unit) { + return future.completeOnTimeout(value, timeout, unit); + } + + public static CompletableFuture allOfFutures(Stream> stream, IntFunction func) { + CompletableFuture[] futures = stream.toArray(futureArrayFunc); + return CompletableFuture.allOf(futures).thenApply(v -> { + int size = futures.length; + T[] array = func.apply(size); + for (int i = 0; i < size; i++) { + array[i] = futures[i].join(); + } + return array; + }); + } + + public static CompletableFuture allOfFutures(CompletableFuture[] futures, IntFunction func) { + return CompletableFuture.allOf(futures).thenApply(v -> { + int size = futures.length; + T[] array = func.apply(size); + for (int i = 0; i < size; i++) { + array[i] = futures[i].join(); + } + return array; + }); + } + + public static CompletableFuture allOfFutures(Stream> stream, IntFunction func, BiConsumer consumer) { + CompletableFuture[] futures = stream.toArray(futureArrayFunc); + return CompletableFuture.allOf(futures).thenApply(v -> { + int size = futures.length; + T[] array = func.apply(size); + for (int i = 0; i < size; i++) { + T val = futures[i].join(); + consumer.accept(i, val); + array[i] = val; + } + return array; + }); + } + + public static CompletableFuture allOfFutures(CompletableFuture[] futures, IntFunction func, BiConsumer consumer) { + return CompletableFuture.allOf(futures).thenApply(v -> { + int size = futures.length; + T[] array = func.apply(size); + for (int i = 0; i < size; i++) { + T val = futures[i].join(); + consumer.accept(i, val); + array[i] = val; + } + return array; + }); + } + + /** + * 灏嗗涓猭ey:value鐨勫瓧绗︿覆閿煎缁勫悎鎴愪竴涓狹ap锛宨tems闀垮害蹇呴』鏄伓鏁, 鍙傛暟涓暟鑻ユ槸濂囨暟鐨勮瘽锛屾渶鍚庝竴涓細琚拷鐣 + * 绫讳技 JDK9涓殑 Map.of 鏂规硶 + * + * @param items 閿煎 + * + * @return Map + */ + public static HashMap ofMap(String... items) { + HashMap map = new LinkedHashMap<>(Math.max(1, items.length / 2)); + int len = items.length / 2; + for (int i = 0; i < len; i++) { + map.put(items[i * 2], items[i * 2 + 1]); + } + return map; + } + + /** + * 灏嗗涓猭ey:value瀵瑰簲鍊肩粍鍚堟垚涓涓狹ap锛宨tems闀垮害蹇呴』鏄伓鏁, 鍙傛暟涓暟鑻ユ槸濂囨暟鐨勮瘽锛屾渶鍚庝竴涓細琚拷鐣 + * 绫讳技 JDK9涓殑 Map.of 鏂规硶 + * + * @param 娉涘瀷 + * @param 娉涘瀷 + * @param items 閿煎 + * + * @return Map + */ + public static HashMap ofMap(Object... items) { + HashMap map = new LinkedHashMap<>(Math.max(1, items.length / 2)); + int len = items.length / 2; + for (int i = 0; i < len; i++) { + map.put((K) items[i * 2], (V) items[i * 2 + 1]); + } + return map; + } + + /** + * 灏嗗涓狹ap鍚堝苟鍒扮涓涓狹ap涓 + * + * @param 娉涘瀷 + * @param 娉涘瀷 + * @param maps Map + * + * @return Map + */ + public static Map merge(Map... maps) { + Map map = null; + for (Map m : maps) { + if (map == null) { + map = m; + } else if (m != null) { + map.putAll(m); + } + } + return map; + } + + /** + * 灏嗗涓厓绱犵粍鍚堟垚涓涓猄et + * + * @param 娉涘瀷 + * @param items 鍏冪礌 + * + * @return Set + */ + public static Set ofSet(T... items) { + Set set = new LinkedHashSet<>(items.length); + for (T item : items) set.add(item); + return set; + } + + /** + * 灏嗗涓厓绱犵粍鍚堟垚涓涓狶ist
+ * 绫讳技 JDK9涓殑 List.of 鏂规硶 + * + * @param 娉涘瀷 + * @param items 鍏冪礌 + * + * @return List + */ + public static List ofList(T... items) { + List list = new ArrayList<>(items.length); + for (T item : items) list.add(item); + return list; + } + + /** + * 灏嗗涓厓绱犵粍鍚堟垚涓涓狝rray + * + * @param 娉涘瀷 + * @param items 鍏冪礌 + * + * @return Array + */ + public static T[] ofArray(T... items) { + return items; + } + + /** + * 瑁佸壀List锛屼娇鍏秙ize涓嶈秴杩噇imit澶у皬
+ * + * @param 娉涘瀷 + * @param list 闆嗗悎 + * @param limit 澶у皬 + * + * @return List + */ + public static List limit(List list, int limit) { + if (list == null || list.isEmpty() || list.size() <= limit) return list; + return list.subList(0, limit); + } + + /** + * 鑾峰彇涓嶅甫"-"鐨刄UID鍊 + * + * @return 涓嶅甫"-"UUID鍊 + */ + public static String uuid() { + return UUID.randomUUID().toString().replace("-", ""); + } + + /** + * 灏嗕竴涓垨澶氫釜鏂板厓绱犳坊鍔犲埌鏁扮粍寮濮嬶紝鏁扮粍涓殑鍏冪礌鑷姩鍚庣Щ + * + * @param 娉涘瀷 + * @param array 鍘熸暟缁 + * @param objs 寰呰拷鍔犳暟鎹 + * + * @return 鏂版暟缁 + */ + public static T[] unshift(final T[] array, final T... objs) { + if (array == null || array.length == 0) return objs; + final T[] news = (T[]) Array.newInstance(array.getClass().getComponentType(), array.length + objs.length); + System.arraycopy(objs, 0, news, 0, objs.length); + System.arraycopy(array, 0, news, objs.length, array.length); + return news; + } + + /** + * 灏嗕竴涓垨澶氫釜鏂板厓绱犳坊鍔犲埌鏁扮粍寮濮嬶紝鏁扮粍涓殑鍏冪礌鑷姩鍚庣Щ + * + * @param 娉涘瀷 + * @param array 鍘熸暟缁 + * @param objs 寰呰拷鍔犳暟鎹 + * + * @return 鏂版暟缁 + */ + public static T[] unshift(final T[] array, final Collection objs) { + if (objs == null || objs.isEmpty()) return array; + if (array == null) { + T one = null; + for (T t : objs) { + if (t != null) one = t; + break; + } + if (one == null) return array; + T[] news = (T[]) Array.newInstance(one.getClass(), objs.size()); + return objs.toArray(news); + } + T[] news = (T[]) Array.newInstance(array.getClass().getComponentType(), array.length + objs.size()); + int index = -1; + for (T t : objs) { + news[(++index)] = t; + } + System.arraycopy(array, 0, news, objs.size(), array.length); + return news; + } + + /** + * 鑾峰彇int鏁扮粍涔嬪拰, 绌烘暟缁勮繑鍥0 + * + * @param array 鏁扮粍 + * + * @return int + */ + public static int sum(final int... array) { + return sum(false, array); + } + + /** + * 鑾峰彇int鏁扮粍涔嬪拰 + * + * @param check 鏄惁妫娴嬬┖ + * @param array 鏁扮粍 + * + * @return int + */ + public static int sum(boolean check, final int... array) { + if (array == null || array.length == 0) { + if (!check) return 0; + throw new NullPointerException("array is null or empty"); + } + int sum = 0; + for (int i : array) { + sum += i; + } + return sum; + } + + /** + * 鑾峰彇long鏁扮粍涔嬪拰, 绌烘暟缁勮繑鍥0 + * + * @param array 鏁扮粍 + * + * @return long + */ + public static long sum(final long... array) { + return sum(false, array); + } + + /** + * 鑾峰彇long鏁扮粍涔嬪拰 + * + * @param check 鏄惁妫娴嬬┖ + * @param array 鏁扮粍 + * + * @return long + */ + public static long sum(boolean check, final long... array) { + if (array == null || array.length == 0) { + if (!check) return 0; + throw new NullPointerException("array is null or empty"); + } + long sum = 0L; + for (long i : array) { + sum += i; + } + return sum; + } + + /** + * 鑾峰彇int鏁扮粍鏈澶у + * + * @param array 鏁扮粍 + * + * @return int + */ + public static int max(final int... array) { + if (array == null || array.length == 0) throw new NullPointerException("array is null or empty"); + int max = array[0]; + for (int i : array) { + if (i > max) i = max; + } + return max; + } + + /** + * 鑾峰彇long鏁扮粍鏈澶у + * + * @param array 鏁扮粍 + * + * @return long + */ + public static long max(final long... array) { + if (array == null || array.length == 0) throw new NullPointerException("array is null or empty"); + long max = array[0]; + for (long i : array) { + if (i > max) i = max; + } + return max; + } + + /** + * 鑾峰彇int鏁扮粍鏈灏忓 + * + * @param array 鏁扮粍 + * + * @return int + */ + public static long min(final int... array) { + if (array == null || array.length == 0) throw new NullPointerException("array is null or empty"); + int min = array[0]; + for (int i : array) { + if (i < min) i = min; + } + return min; + } + + /** + * 鑾峰彇long鏁扮粍鏈灏忓 + * + * @param array 鏁扮粍 + * + * @return long + */ + public static long min(final long... array) { + if (array == null || array.length == 0) throw new NullPointerException("array is null or empty"); + long min = array[0]; + for (long i : array) { + if (i < min) i = min; + } + return min; + } + + /** + * 灏哻har鏁扮粍鐢ㄥ垎闅旂鎷兼帴鎴愬瓧绗︿覆 + * + * @param array 鏁扮粍 + * @param delimiter 鍒嗛殧绗 + * + * @return String + */ + public static String joining(final char[] array, final String delimiter) { + if (array == null || array.length == 0) return ""; + StringBuilder sb = new StringBuilder(); + for (char i : array) { + if (sb.length() > 0) sb.append(delimiter); + sb.append(i); + } + return sb.toString(); + } + + /** + * 灏唅nt鏁扮粍鐢ㄥ垎闅旂鎷兼帴鎴愬瓧绗︿覆 + * + * @param array 鏁扮粍 + * @param delimiter 鍒嗛殧绗 + * + * @return String + */ + public static String joining(final int[] array, final String delimiter) { + if (array == null || array.length == 0) return ""; + StringBuilder sb = new StringBuilder(); + for (int i : array) { + if (sb.length() > 0) sb.append(delimiter); + sb.append(i); + } + return sb.toString(); + } + + /** + * 灏唋ong鏁扮粍鐢ㄥ垎闅旂鎷兼帴鎴愬瓧绗︿覆 + * + * @param array 鏁扮粍 + * @param delimiter 鍒嗛殧绗 + * + * @return String + */ + public static String joining(final long[] array, final String delimiter) { + if (array == null || array.length == 0) return ""; + StringBuilder sb = new StringBuilder(); + for (long i : array) { + if (sb.length() > 0) sb.append(delimiter); + sb.append(i); + } + return sb.toString(); + } + + /** + * 灏嗗璞℃暟缁勭敤鍒嗛殧绗︽嫾鎺ユ垚瀛楃涓 + * + * @param 娉涘瀷 + * @param array 鏁扮粍 + * @param delimiter 鍒嗛殧绗 + * + * @return String + */ + public static String joining(final T[] array, final String delimiter) { + if (array == null || array.length == 0) return ""; + StringBuilder sb = new StringBuilder(); + for (T i : array) { + if (sb.length() > 0) sb.append(delimiter); + sb.append(i); + } + return sb.toString(); + } + + /** + * 灏嗗璞℃暟缁勭敤鍒嗛殧绗︽嫾鎺ユ垚瀛楃涓 + * + * @param 娉涘瀷 + * @param array 鏁扮粍 + * @param delimiter 鍒嗛殧绗 + * + * @return String + */ + public static String joining(final String[] array, final char delimiter) { + if (array == null || array.length == 0) return ""; + StringBuilder sb = new StringBuilder(); + for (String i : array) { + if (sb.length() > 0) sb.append(delimiter); + sb.append(i); + } + return sb.toString(); + } + + /** + * 灏嗗璞℃暟缁勭敤鍒嗛殧绗︽嫾鎺ユ垚瀛楃涓 + * + * @param 娉涘瀷 + * @param array 鏁扮粍 + * @param delimiter 鍒嗛殧绗 + * + * @return String + */ + public static String joiningHex(final byte[] array, final char delimiter) { + if (array == null || array.length == 0) return ""; + StringBuilder sb = new StringBuilder(); + for (byte i : array) { + if (sb.length() > 0) sb.append(delimiter); + String s = Integer.toHexString(i & 0xff); + sb.append(s.length() > 1 ? "0x" : "0x0").append(s); + } + return sb.toString(); + } + + /** + * 灏嗗璞℃暟缁勭敤鍒嗛殧绗︽嫾鎺ユ垚瀛楃涓 + * + * @param 娉涘瀷 + * @param array 鏁扮粍 + * @param offset 鍋忕Щ閲 + * @param length 闀垮害 + * @param delimiter 鍒嗛殧绗 + * + * @return String + */ + public static String joiningHex(final byte[] array, int offset, int length, final char delimiter) { + if (array == null || array.length == 0) return ""; + StringBuilder sb = new StringBuilder(); + int len = offset + length; + for (int i = offset; i < len; i++) { + if (sb.length() > 0) sb.append(delimiter); + String s = Integer.toHexString(array[i] & 0xff); + sb.append(s.length() > 1 ? "0x" : "0x0").append(s); + } + return sb.toString(); + } + + /** + * 灏嗕竴涓垨澶氫釜byte鏂板厓绱犳坊鍔犲埌byte鏁扮粍缁撳熬 + * + * @param array 鍘熸暟缁 + * @param objs 寰呰拷鍔犳暟鎹 + * + * @return 鏂版暟缁 + */ + public static byte[] append(final byte[] array, final byte... objs) { + if (array == null || array.length == 0) return objs; + if (objs == null || objs.length == 0) return array; + final byte[] news = new byte[array.length + objs.length]; + System.arraycopy(array, 0, news, 0, array.length); + System.arraycopy(objs, 0, news, array.length, objs.length); + return news; + } + + /** + * 灏嗕竴涓垨澶氫釜byte鏂板厓绱犳坊鍔犲埌byte鏁扮粍缁撳熬 + * + * @param array 鍘熸暟缁 + * @param objs 寰呰拷鍔犳暟鎹 + * @param offset 寰呰拷鍔犳暟鎹亸绉婚噺 + * @param length 寰呰拷鍔犳暟鎹殑闀垮害 + * + * @return 鏂版暟缁 + */ + public static byte[] append(final byte[] array, final byte[] objs, int offset, int length) { + if (array == null || array.length == 0) { + if (objs != null && offset == 0 && objs.length == length) return objs; + final byte[] news = new byte[length]; + System.arraycopy(objs, 0, news, 0, length); + return news; + } + if (objs == null || length == 0) return array; + final byte[] news = new byte[array.length + length]; + System.arraycopy(array, 0, news, 0, array.length); + System.arraycopy(objs, offset, news, array.length, length); + return news; + } + + /** + * 灏嗕竴涓垨澶氫釜short鏂板厓绱犳坊鍔犲埌short鏁扮粍缁撳熬 + * + * @param array 鍘熸暟缁 + * @param objs 寰呰拷鍔犳暟鎹 + * + * @return 鏂版暟缁 + */ + public static short[] append(final short[] array, final short... objs) { + if (array == null || array.length == 0) return objs; + if (objs == null || objs.length == 0) return array; + final short[] news = new short[array.length + objs.length]; + System.arraycopy(array, 0, news, 0, array.length); + System.arraycopy(objs, 0, news, array.length, objs.length); + return news; + } + + /** + * 灏嗕竴涓垨澶氫釜char鏂板厓绱犳坊鍔犲埌char鏁扮粍缁撳熬 + * + * @param array 鍘熸暟缁 + * @param objs 寰呰拷鍔犳暟鎹 + * + * @return 鏂版暟缁 + */ + public static char[] append(final char[] array, final char... objs) { + if (array == null || array.length == 0) return objs; + if (objs == null || objs.length == 0) return array; + final char[] news = new char[array.length + objs.length]; + System.arraycopy(array, 0, news, 0, array.length); + System.arraycopy(objs, 0, news, array.length, objs.length); + return news; + } + + /** + * 灏嗕竴涓垨澶氫釜int鏂板厓绱犳坊鍔犲埌int鏁扮粍缁撳熬 + * + * @param array 鍘熸暟缁 + * @param objs 寰呰拷鍔犳暟鎹 + * + * @return 鏂版暟缁 + */ + public static int[] append(final int[] array, final int... objs) { + if (array == null || array.length == 0) return objs; + if (objs == null || objs.length == 0) return array; + final int[] news = new int[array.length + objs.length]; + System.arraycopy(array, 0, news, 0, array.length); + System.arraycopy(objs, 0, news, array.length, objs.length); + return news; + } + + /** + * 灏嗕竴涓垨澶氫釜long鏂板厓绱犳坊鍔犲埌long鏁扮粍缁撳熬 + * + * @param array 鍘熸暟缁 + * @param objs 寰呰拷鍔犳暟鎹 + * + * @return 鏂版暟缁 + */ + public static long[] append(final long[] array, final long... objs) { + if (array == null || array.length == 0) return objs; + if (objs == null || objs.length == 0) return array; + final long[] news = new long[array.length + objs.length]; + System.arraycopy(array, 0, news, 0, array.length); + System.arraycopy(objs, 0, news, array.length, objs.length); + return news; + } + + /** + * 灏嗕竴涓垨澶氫釜鏂板厓绱犳坊鍔犲埌鏁扮粍缁撳熬 + * + * @param 娉涘瀷 + * @param array 鍘熸暟缁 + * @param objs 寰呰拷鍔犳暟鎹 + * + * @return 鏂版暟缁 + */ + public static T[] append(final T[] array, final T... objs) { + if (array == null || array.length == 0) return objs; + if (objs == null || objs.length == 0) return array; + final T[] news = (T[]) Array.newInstance(array.getClass().getComponentType(), array.length + objs.length); + System.arraycopy(array, 0, news, 0, array.length); + System.arraycopy(objs, 0, news, array.length, objs.length); + return news; + } + + /** + * 灏嗕竴涓垨澶氫釜鏂板厓绱犳坊鍔犲埌鏁扮粍缁撳熬 + * + * @param 娉涘瀷 + * @param array 鍘熸暟缁 + * @param objs 寰呰拷鍔犳暟鎹 + * + * @return 鏂版暟缁 + */ + public static T[] append(final T[] array, final Collection objs) { + if (objs == null || objs.isEmpty()) return array; + if (array == null) { + T one = null; + for (T t : objs) { + if (t != null) one = t; + break; + } + if (one == null) return array; + T[] news = (T[]) Array.newInstance(one.getClass(), objs.size()); + return objs.toArray(news); + } + T[] news = (T[]) Array.newInstance(array.getClass().getComponentType(), array.length + objs.size()); + System.arraycopy(array, 0, news, 0, array.length); + int index = -1; + for (T t : objs) { + news[array.length + (++index)] = t; + } + return news; + } + + /** + * 灏唅nt鏁扮粍鍊掑簭 + * + * @param array 鍘熸暟缁 + * + * @return 鏂版暟缁 + */ + public static int[] reverseSort(final int[] array) { + if (array == null || array.length == 0) return array; + return Arrays.stream(array).boxed().sorted(Collections.reverseOrder()).mapToInt(x -> x).toArray(); + } + + /** + * 灏唋ong鏁扮粍鍊掑簭 + * + * @param array 鍘熸暟缁 + * + * @return 鏂版暟缁 + */ + public static long[] reverseSort(final long[] array) { + if (array == null || array.length == 0) return array; + return Arrays.stream(array).boxed().sorted(Collections.reverseOrder()).mapToLong(x -> x).toArray(); + } + + /** + * 灏嗗厓绱犱粠鏁扮粍涓垹闄 + * + * @param 娉涘瀷 + * @param array 鍘熸暟缁 + * @param item 鍏冪礌 + * + * @return 鏂版暟缁 + */ + public static T[] remove(final T[] array, final T item) { + return remove(array, (i) -> Objects.equals(i, item)); + } + + /** + * 灏嗙鍚堟潯浠剁殑鍏冪礌浠庢暟缁勪腑鍒犻櫎 + * + * @param 娉涘瀷 + * @param array 鍘熸暟缁 + * @param filter Predicate + * + * @return 鏂版暟缁 + */ + public static T[] remove(final T[] array, final Predicate filter) { + if (array == null || array.length == 0 || filter == null) return array; + final T[] news = (T[]) Array.newInstance(array.getClass().getComponentType(), array.length); + int index = 0; + for (int i = 0; i < news.length; i++) { + if (!filter.test(array[i])) { + news[index++] = array[i]; + } + } + if (index == array.length) return array; + final T[] rs = (T[]) Array.newInstance(array.getClass().getComponentType(), index); + System.arraycopy(news, 0, rs, 0, index); + return rs; + } + + /** + * 灏嗘寚瀹氱殑long鍏冪礌浠庢暟缁勪腑鍒犻櫎, 鐩稿悓鐨勫厓绱犱細鏍规嵁items閲岄噸澶嶆鏁版潵鎵ц鍒犻櫎
+ * 渚嬪:
+ * remove(new short[]{1, 1, 1, 2, 2, 3, 3, 3}, false, 1, 1, 2, 3, 3) = [1,2,3]
+ * + * @param array 鍘熸暟缁 + * @param items short[] + * + * @return 鏂版暟缁 + */ + public static short[] removeMatch(final short[] array, final short... items) { + return remove(array, false, items); + } + + /** + * 灏嗘寚瀹氱殑int鍏冪礌浠庢暟缁勪腑鍒犻櫎, repeat=true鏃剁浉鍚岀殑鍏冪礌浼氭牴鎹甶tems閲岄噸澶嶆鏁版潵鎵ц鍒犻櫎
+ * 渚嬪:
+ * remove(new short[]{1, 1, 1, 2, 2, 3, 3, 3}, true, 1, 1, 2, 3, 3) = []
+ * remove(new short[]{1, 1, 1, 2, 2, 3, 3, 3}, false, 1, 1, 2, 3, 3) = [1,2,3] + * + * @param array 鍘熸暟缁 + * @param repeat 鏄惁閲嶅鍒犻櫎鐩稿悓鐨勫厓绱 + * @param items short[] + * + * @return 鏂版暟缁 + */ + public static short[] remove(final short[] array, boolean repeat, final short... items) { + if (array == null || array.length == 0 || items == null || items.length == 0) return array; + final short[] news = new short[array.length]; + short[] subs = items; + int index = 0; + for (int i = 0; i < news.length; i++) { + if (subs.length > 0 && contains(subs, array[i])) { + if (!repeat) { + short[] newsubs = new short[subs.length - 1]; + int k = 0; + boolean done = false; + for (short v : subs) { + if (done) { + newsubs[k++] = v; + } else if (v == array[i]) { + done = true; + } else { + newsubs[k++] = v; + } + } + subs = newsubs; + } + } else { + news[index++] = array[i]; + } + } + if (index == array.length) return array; + final short[] rs = new short[index]; + System.arraycopy(news, 0, rs, 0, index); + return rs; + } + + /** + * 灏嗘寚瀹氱殑long鍏冪礌浠庢暟缁勪腑鍒犻櫎, 鐩稿悓鐨勫厓绱犱細鏍规嵁items閲岄噸澶嶆鏁版潵鎵ц鍒犻櫎
+ * 渚嬪:
+ * remove(new int[]{1, 1, 1, 2, 2, 3, 3, 3}, false, 1, 1, 2, 3, 3) = [1,2,3]
+ * + * @param array 鍘熸暟缁 + * @param items int[] + * + * @return 鏂版暟缁 + */ + public static int[] removeMatch(final int[] array, final int... items) { + return remove(array, false, items); + } + + /** + * 灏嗘寚瀹氱殑int鍏冪礌浠庢暟缁勪腑鍒犻櫎, repeat=false鏃剁浉鍚岀殑鍏冪礌浼氭牴鎹甶tems閲岄噸澶嶆鏁版潵鎵ц鍒犻櫎
+ * 渚嬪:
+ * remove(new int[]{1, 1, 1, 2, 2, 3, 3, 3}, true, 1, 1, 2, 3, 3) = []
+ * remove(new int[]{1, 1, 1, 2, 2, 3, 3, 3}, false, 1, 1, 2, 3, 3) = [1,2,3] + * + * @param array 鍘熸暟缁 + * @param repeat 鏄惁閲嶅鍒犻櫎鐩稿悓鐨勫厓绱 + * @param items int[] + * + * @return 鏂版暟缁 + */ + public static int[] remove(final int[] array, boolean repeat, final int... items) { + if (array == null || array.length == 0 || items == null || items.length == 0) return array; + final int[] news = new int[array.length]; + int[] subs = items; + int index = 0; + for (int i = 0; i < news.length; i++) { + if (subs.length > 0 && contains(subs, array[i])) { + if (!repeat) { + int[] newsubs = new int[subs.length - 1]; + int k = 0; + boolean done = false; + for (int v : subs) { + if (done) { + newsubs[k++] = v; + } else if (v == array[i]) { + done = true; + } else { + newsubs[k++] = v; + } + } + subs = newsubs; + } + } else { + news[index++] = array[i]; + } + } + if (index == array.length) return array; + final int[] rs = new int[index]; + System.arraycopy(news, 0, rs, 0, index); + return rs; + } + + /** + * 灏嗘寚瀹氱殑long鍏冪礌浠庢暟缁勪腑鍒犻櫎, 鐩稿悓鐨勫厓绱犱細鏍规嵁items閲岄噸澶嶆鏁版潵鎵ц鍒犻櫎
+ * 渚嬪:
+ * remove(new long[]{1, 1, 1, 2, 2, 3, 3, 3}, false, 1, 1, 2, 3, 3) = [1,2,3]
+ * + * @param array 鍘熸暟缁 + * @param items long[] + * + * @return 鏂版暟缁 + */ + public static long[] removeMatch(final long[] array, final long... items) { + return remove(array, false, items); + } + + /** + * 灏嗘寚瀹氱殑long鍏冪礌浠庢暟缁勪腑鍒犻櫎, repeat=false鏃剁浉鍚岀殑鍏冪礌浼氭牴鎹甶tems閲岄噸澶嶆鏁版潵鎵ц鍒犻櫎
+ * 渚嬪:
+ * remove(new long[]{1, 1, 1, 2, 2, 3, 3, 3}, true, 1, 1, 2, 3, 3) = []
+ * remove(new long[]{1, 1, 1, 2, 2, 3, 3, 3}, false, 1, 1, 2, 3, 3) = [1,2,3]
+ * + * @param array 鍘熸暟缁 + * @param repeat 鏄惁閲嶅鍒犻櫎鐩稿悓鐨勫厓绱 + * @param items long[] + * + * @return 鏂版暟缁 + */ + public static long[] remove(final long[] array, boolean repeat, final long... items) { + if (array == null || array.length == 0 || items == null || items.length == 0) return array; + final long[] news = new long[array.length]; + long[] subs = items; + int index = 0; + for (int i = 0; i < news.length; i++) { + if (subs.length > 0 && contains(subs, array[i])) { + if (!repeat) { + long[] newsubs = new long[subs.length - 1]; + int k = 0; + boolean done = false; + for (long v : subs) { + if (done) { + newsubs[k++] = v; + } else if (v == array[i]) { + done = true; + } else { + newsubs[k++] = v; + } + } + subs = newsubs; + } + } else { + news[index++] = array[i]; + } + } + if (index == array.length) return array; + final long[] rs = new long[index]; + System.arraycopy(news, 0, rs, 0, index); + return rs; + } + + /** + * 鍒ゆ柇瀛楃涓叉槸鍚﹀寘鍚寚瀹氱殑瀛楃锛屽寘鍚繑鍥瀟rue + * + * @param string 瀛楃涓 + * @param values 瀛楃闆嗗悎 + * + * @return boolean + */ + public static boolean contains(String string, char... values) { + if (string == null) return false; + for (char ch : Utility.charArray(string)) { + for (char ch2 : values) { + if (ch == ch2) return true; + } + } + return false; + } + + /** + * 姣旇緝涓ら泦鍚堝厓绱犳槸鍚︿竴鏍凤紝 椤哄簭涓嶈姹備竴鏍 + * + * @param 娉涘瀷 + * @param array1 闆嗗悎 + * @param array2 闆嗗悎 + * + * @return 鍏冪礌鏄惁瀹屽叏鐩稿悓 + */ + public static boolean equalsElement(T[] array1, T[] array2) { + if (array1 == null && array2 == null) return true; + if (array1 == null && array2 != null) return false; + if (array1 != null && array2 == null) return false; + if (array1.length != array2.length) return false; + return equalsElement(ofList(array1), ofList(array2)); + } + + /** + * 姣旇緝涓ら泦鍚堝厓绱犳槸鍚︿竴鏍凤紝 椤哄簭涓嶈姹備竴鏍 + * + * @param 娉涘瀷 + * @param col1 闆嗗悎 + * @param col2 闆嗗悎 + * + * @return 鍏冪礌鏄惁瀹屽叏鐩稿悓 + */ + public static boolean equalsElement(Collection col1, Collection col2) { + if (col1 == null && col2 == null) return true; + if (col1 == null && col2 != null) return false; + if (col1 != null && col2 == null) return false; + if (col1.size() != col2.size()) return false; + //{1,2,2}, {1,1,2} + List list = new ArrayList<>(col2); + for (T item : col1) { + if (!list.remove(item)) return false; + } + return list.isEmpty(); + } + + /** + * 姣旇緝涓ら泦鍚堝厓绱犳槸鍚︿竴鏍凤紝 椤哄簭涓嶈姹備竴鏍 + * + * @param 娉涘瀷 + * @param 娉涘瀷 + * @param map1 闆嗗悎 + * @param map2 闆嗗悎 + * + * @return 鍏冪礌鏄惁瀹屽叏鐩稿悓 + */ + public static boolean equalsElement(Map map1, Map map2) { + if (map1 == null && map2 == null) return true; + if (map1 == null && map2 != null) return false; + if (map1 != null && map2 == null) return false; + if (map1.size() != map2.size()) return false; + for (Map.Entry en : map1.entrySet()) { + if (!Objects.equals(en.getValue(), map2.get(en.getKey()))) return false; + } + return true; + } + + /** + * 鍒ゆ柇鎸囧畾鍊兼槸鍚﹀寘鍚寚瀹氱殑鏁扮粍涓紝鍖呭惈杩斿洖true + * + * @param values 闆嗗悎 + * @param value 鍗曞 + * + * @return boolean + */ + public static boolean contains(char[] values, char value) { + if (values == null) return false; + for (char v : values) { + if (v == value) return true; + } + return false; + } + + /** + * 鍒ゆ柇鎸囧畾鍊兼槸鍚﹀寘鍚寚瀹氱殑鏁扮粍涓紝鍖呭惈杩斿洖true + * + * @param values 闆嗗悎 + * @param value 鍗曞 + * + * @return boolean + */ + public static boolean contains(short[] values, short value) { + if (values == null) return false; + for (short v : values) { + if (v == value) return true; + } + return false; + } + + /** + * 鍒ゆ柇鎸囧畾鍊(涓嶈鍖呭惈鐩稿悓鐨勫厓绱)鏄惁鍖呭惈鎸囧畾鐨勬暟缁勪腑锛屽寘鍚繑鍥瀟rue + * + * @param values 闆嗗悎 + * @param items 澶氬 + * + * @return boolean + */ + public static boolean contains(short[] values, short... items) { + if (values == null) return false; + for (short item : items) { + if (!contains(values, item)) return false; + } + return true; + } + + /** + * 鍒ゆ柇鎸囧畾鍊兼槸鍚﹀寘鍚寚瀹氱殑鏁扮粍涓紝鍖呭惈杩斿洖true + * + * @param values 闆嗗悎 + * @param value 鍗曞 + * + * @return boolean + */ + public static boolean contains(int[] values, int value) { + if (values == null) return false; + for (int v : values) { + if (v == value) return true; + } + return false; + } + + /** + * 鍒ゆ柇鎸囧畾鍊(涓嶈鍖呭惈鐩稿悓鐨勫厓绱)鏄惁鍖呭惈鎸囧畾鐨勬暟缁勪腑锛屽寘鍚繑鍥瀟rue + * + * @param values 闆嗗悎 + * @param items 澶氬 + * + * @return boolean + */ + public static boolean contains(int[] values, int... items) { + if (values == null) return false; + for (int item : items) { + if (!contains(values, item)) return false; + } + return true; + } + + /** + * 鍒ゆ柇鎸囧畾鍊兼槸鍚﹀寘鍚寚瀹氱殑鏁扮粍涓紝鍖呭惈杩斿洖true + * + * @param values 闆嗗悎 + * @param value 鍗曞 + * + * @return boolean + */ + public static boolean contains(long[] values, long value) { + if (values == null) return false; + for (long v : values) { + if (v == value) return true; + } + return false; + } + + /** + * 鍒ゆ柇鎸囧畾鍊(涓嶈鍖呭惈鐩稿悓鐨勫厓绱)鏄惁鍖呭惈鎸囧畾鐨勬暟缁勪腑锛屽寘鍚繑鍥瀟rue + * + * @param values 闆嗗悎 + * @param items 澶氬 + * + * @return boolean + */ + public static boolean contains(long[] values, long... items) { + if (values == null) return false; + for (long item : items) { + if (!contains(values, item)) return false; + } + return true; + } + + /** + * 鍒ゆ柇鎸囧畾鍊兼槸鍚﹀寘鍚寚瀹氱殑鏁扮粍涓紝鍖呭惈杩斿洖true + * + * @param 娉涘瀷 + * @param values 闆嗗悎 + * @param value 鍗曞 + * + * @return boolean + */ + public static boolean contains(T[] values, T value) { + if (values == null) return false; + for (T v : values) { + if (Objects.equals(v, value)) return true; + } + return false; + } + + /** + * 鍒ゆ柇鎸囧畾鍊兼槸鍚﹀寘鍚寚瀹氱殑鏁扮粍涓紝鍖呭惈杩斿洖true + * + * @param 娉涘瀷 + * @param values 闆嗗悎 + * @param predicate 杩囨护鏉′欢 + * + * @return boolean + */ + public static boolean contains(T[] values, Predicate predicate) { + if (values == null) return false; + for (T v : values) { + if (predicate.test(v)) return true; + } + return false; + } + + /** + * 灏嗘寚瀹氱殑short鍏冪礌鏄惁鏁扮粍涓畬鍏ㄥ寘鍚紝閲嶅鍏冪礌鐨勬鏁颁篃瑕佺浉鍚
+ * 渚嬪:
+ * containsMatch(new short[]{1, 2, 2, 3, 3, 3}, 1, 2, 3, 3) = true
+ * containsMatch(new short[]{1, 2, 2, 3, 3, 3}, 1, 1, 2, 3, 3) = false
+ * + * @param array 鍘熸暟缁 + * @param items short[] + * + * @return 鏄惁瀹屽叏鍖呭惈 + */ + public static boolean containsMatch(final short[] array, final short... items) { + if (array == null) return false; + if (items == null || items.length == 0) return true; + if (array.length == 0 && items.length == 0) return true; + if (array.length < items.length) return false; + + short[] subs = array; + for (short item : items) { + if (!contains(subs, item)) return false; + short[] newsubs = new short[subs.length - 1]; + int k = 0; + boolean done = false; + for (short v : subs) { + if (done) { + newsubs[k++] = v; + } else if (v == item) { + done = true; + } else { + newsubs[k++] = v; + } + } + subs = newsubs; + } + return true; + } + + /** + * 灏嗘寚瀹氱殑int鍏冪礌鏄惁鏁扮粍涓畬鍏ㄥ寘鍚紝閲嶅鍏冪礌鐨勬鏁颁篃瑕佺浉鍚
+ * 渚嬪:
+ * containsMatch(new int[]{1, 2, 2, 3, 3, 3}, 1, 2, 3, 3) = true
+ * containsMatch(new int[]{1, 2, 2, 3, 3, 3}, 1, 1, 2, 3, 3) = false
+ * + * @param array 鍘熸暟缁 + * @param items int[] + * + * @return 鏄惁瀹屽叏鍖呭惈 + */ + public static boolean containsMatch(final int[] array, final int... items) { + if (array == null) return false; + if (items == null || items.length == 0) return true; + if (array.length == 0 && items.length == 0) return true; + if (array.length < items.length) return false; + + int[] subs = array; + for (int item : items) { + if (!contains(subs, item)) return false; + int[] newsubs = new int[subs.length - 1]; + int k = 0; + boolean done = false; + for (int v : subs) { + if (done) { + newsubs[k++] = v; + } else if (v == item) { + done = true; + } else { + newsubs[k++] = v; + } + } + subs = newsubs; + } + return true; + } + + /** + * 灏嗘寚瀹氱殑long鍏冪礌鏄惁鏁扮粍涓畬鍏ㄥ寘鍚紝閲嶅鍏冪礌鐨勬鏁颁篃瑕佺浉鍚
+ * 渚嬪:
+ * containsMatch(new long[]{1, 2, 2, 3, 3, 3}, 1, 2, 3, 3) = true
+ * containsMatch(new long[]{1, 2, 2, 3, 3, 3}, 1, 1, 2, 3, 3) = false
+ * + * @param array 鍘熸暟缁 + * @param items long[] + * + * @return 鏄惁瀹屽叏鍖呭惈 + */ + public static boolean containsMatch(final long[] array, final long... items) { + if (array == null) return false; + if (items == null || items.length == 0) return true; + if (array.length == 0 && items.length == 0) return true; + if (array.length < items.length) return false; + + long[] subs = array; + for (long item : items) { + if (!contains(subs, item)) return false; + long[] newsubs = new long[subs.length - 1]; + int k = 0; + boolean done = false; + for (long v : subs) { + if (done) { + newsubs[k++] = v; + } else if (v == item) { + done = true; + } else { + newsubs[k++] = v; + } + } + subs = newsubs; + } + return true; + } + + /** + * 鍒犻櫎鎺夊瓧绗︿覆鏁扮粍涓寘鍚寚瀹氱殑瀛楃涓 + * + * @param columns 寰呭垹闄ゆ暟缁 + * @param cols 闇鎺掗櫎鐨勫瓧绗︿覆 + * + * @return 鏂板瓧绗︿覆鏁扮粍 + */ + public static String[] exclude(final String[] columns, final String... cols) { + if (columns == null || columns.length == 0 || cols == null || cols.length == 0) return columns; + int count = 0; + for (String column : columns) { + boolean flag = false; + for (String col : cols) { + if (column != null && column.equals(col)) { + flag = true; + break; + } + } + if (flag) count++; + } + if (count == 0) return columns; + if (count == columns.length) return new String[0]; + final String[] newcols = new String[columns.length - count]; + count = 0; + for (String column : columns) { + boolean flag = false; + for (String col : cols) { + if (column != null && column.equals(col)) { + flag = true; + break; + } + } + if (!flag) newcols[count++] = column; + } + return newcols; + } + + /** + * 灏哹uffer鐨勫唴瀹硅浆鎹㈡垚瀛楃涓, string鍙傛暟涓嶄负绌烘椂浼氳拷鍔犲湪buffer鍐呭瀛楃涓蹭箣鍓 + * + * @param string 瀛楃涓插墠缂 + * @param buffer ByteBuffer + * + * @return 瀛楃涓 + */ + public static String toString(String string, ByteBuffer buffer) { + if (buffer == null || !buffer.hasRemaining()) return string; + int pos = buffer.position(); + int limit = buffer.limit(); + byte[] bytes = new byte[buffer.remaining()]; + buffer.get(bytes); + buffer.position(pos); + buffer.limit(limit); + if (string == null) return new String(bytes, UTF_8); + return string + new String(bytes, UTF_8); + } + + /** + * 灏哹uffer鐨勫唴瀹硅浆鎹㈡垚瀛楃涓插苟鎵撳嵃鍒版帶鍒跺彴, string鍙傛暟涓嶄负绌烘椂浼氳拷鍔犲湪buffer鍐呭瀛楃涓蹭箣鍓 + * + * @param string 瀛楃涓插墠缂 + * @param buffer ByteBuffer + * + */ + public static void println(String string, ByteBuffer buffer) { + if (buffer == null || !buffer.hasRemaining()) return; + int pos = buffer.position(); + int limit = buffer.limit(); + byte[] bytes = new byte[buffer.remaining()]; + buffer.get(bytes); + buffer.position(pos); + buffer.limit(limit); + println(string, bytes); + } + + /** + * 灏嗗瓧鑺傛暟缁勭殑鍐呭杞崲鎴愬瓧绗︿覆骞舵墦鍗板埌鎺у埗鍙, string鍙傛暟涓嶄负绌烘椂浼氳拷鍔犲湪瀛楄妭鏁扮粍鍐呭瀛楃涓蹭箣鍓 + * + * @param string 瀛楃涓插墠缂 + * @param bytes 瀛楄妭鏁扮粍 + * + */ + public static void println(String string, byte... bytes) { + if (bytes == null) return; + StringBuilder sb = new StringBuilder(); + if (string != null) sb.append(string); + sb.append(bytes.length).append(".["); + boolean last = false; + for (byte b : bytes) { + if (last) sb.append(','); + int v = b & 0xff; + sb.append("0x"); + if (v < 16) sb.append('0'); + sb.append(Integer.toHexString(v)); + last = true; + } + sb.append(']'); + (System.out).println(sb); + } + + /** + * 杩斿洖鏈満鐨勭涓涓唴缃慖Pv4鍦板潃锛 娌℃湁鍒欒繑鍥瀗ull + * + * @return IPv4鍦板潃 + */ + public static InetAddress localInetAddress() { + InetAddress back = null; + try { + Enumeration nifs = NetworkInterface.getNetworkInterfaces(); + while (nifs.hasMoreElements()) { + NetworkInterface nif = nifs.nextElement(); + if (!nif.isUp()) continue; + Enumeration eis = nif.getInetAddresses(); + while (eis.hasMoreElements()) { + InetAddress ia = eis.nextElement(); + if (ia.isLoopbackAddress() && ia instanceof Inet4Address) back = ia; + if (ia.isSiteLocalAddress() && ia instanceof Inet4Address) return ia; + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return back; + } + + /** + * 鍒涘缓 CompletionHandler 瀵硅薄 + * + * @param 缁撴灉瀵硅薄鐨勬硾鍨 + * @param 闄勪欢瀵硅薄鐨勬硾鍨 + * @param success 鎴愬姛鐨勫洖璋冨嚱鏁 + * @param fail 澶辫触鐨勫洖璋冨嚱鏁 + * + * @return CompletionHandler + */ + public static CompletionHandler createAsyncHandler(final BiConsumer success, final BiConsumer fail) { + return new CompletionHandler() { + @Override + public void completed(V result, A attachment) { + if (success != null) success.accept(result, attachment); + } + + @Override + public void failed(Throwable exc, A attachment) { + if (fail != null) fail.accept(exc, attachment); + } + }; + } + + /** + * 鍒涘缓娌℃湁杩斿洖缁撴灉鐨 CompletionHandler 瀵硅薄 + * + * @param 闄勪欢瀵硅薄鐨勬硾鍨 + * @param success 鎴愬姛鐨勫洖璋冨嚱鏁 + * @param fail 澶辫触鐨勫洖璋冨嚱鏁 + * + * @return CompletionHandler + */ + public static CompletionHandler createAsyncHandler(final Consumer success, final BiConsumer fail) { + return new CompletionHandler() { + @Override + public void completed(Void result, A attachment) { + if (success != null) success.accept(attachment); + } + + @Override + public void failed(Throwable exc, A attachment) { + if (fail != null) fail.accept(exc, attachment); + } + }; + } + + /** + * 鍒涘缓娌℃湁闄勪欢瀵硅薄鐨 CompletionHandler 瀵硅薄 + * + * @param 缁撴灉瀵硅薄鐨勬硾鍨 + * @param success 鎴愬姛鐨勫洖璋冨嚱鏁 + * @param fail 澶辫触鐨勫洖璋冨嚱鏁 + * + * @return CompletionHandler + */ + public static CompletionHandler createAsyncHandler(final Consumer success, final Consumer fail) { + return new CompletionHandler() { + @Override + public void completed(V result, Void attachment) { + if (success != null) success.accept(result); + } + + @Override + public void failed(Throwable exc, Void attachment) { + if (fail != null) fail.accept(exc); + } + }; + } + + /** + * 鑾峰彇鏍煎紡涓簓yyy-MM-dd HH:mm:ss鐨勫綋鍓嶆椂闂 + * + * @return 鏍煎紡涓簓yyy-MM-dd HH:mm:ss鐨勬椂闂村 + */ + public static String now() { + return String.format(format1, System.currentTimeMillis()); + } + + /** + * 鑾峰彇鏍煎紡涓簓yyy-MM-dd HH:mm:ss.fff鐨勫綋鍓嶆椂闂 + * + * @return 鏍煎紡涓簓yyy-MM-dd HH:mm:ss.fff鐨勬椂闂村 + */ + public static String nowMillis() { + return String.format(format2, System.currentTimeMillis()); + } + + /** + * 灏嗘寚瀹氭椂闂存牸寮忓寲涓 yyyy-MM-dd HH:mm:ss + * + * @param time 寰呮牸寮忓寲鐨勬椂闂 + * + * @return 鏍煎紡涓簓yyy-MM-dd HH:mm:ss鐨勬椂闂村 + */ + public static String formatTime(long time) { + return String.format(format1, time); + } + + /** + * 灏嗘椂闂村艰浆鎹负闀垮害涓9鐨36杩涘埗鍊 + * + * @param time 鏃堕棿鍊 + * + * @return 36杩涘埗鏃堕棿鍊 + */ + public static String format36time(long time) { + return Long.toString(time, 36); + } + + /** + * 鑾峰彇褰撳ぉ鍑屾櫒闆剁偣鐨勬牸鏋楁椂闂 + * + * @return 姣鏁 + */ + public static long midnight() { + return midnight(System.currentTimeMillis()); + } + + /** + * 鑾峰彇鎸囧畾鏃堕棿褰撳ぉ鍑屾櫒闆剁偣鐨勬牸鏋楁椂闂 + * + * @param time 鎸囧畾鏃堕棿 + * + * @return 姣鏁 + */ + public static long midnight(long time) { + return (time + zoneRawOffset) / 86400000 * 86400000 - zoneRawOffset; + } + + /** + * 鑾峰彇褰撳ぉ20151231鏍煎紡鐨刬nt鍊 + * + * @return 20151231鏍煎紡鐨刬nt鍊 + */ + public static int today() { + java.time.LocalDate today = java.time.LocalDate.now(); + return today.getYear() * 10000 + today.getMonthValue() * 100 + today.getDayOfMonth(); + } + + /** + * 鑾峰彇褰撳ぉ151231鏍煎紡鐨刬nt鍊 + * + * @return 151231鏍煎紡鐨刬nt鍊 + */ + public static int todayYYMMDD() { + java.time.LocalDate today = java.time.LocalDate.now(); + return today.getYear() % 100 * 10000 + today.getMonthValue() * 100 + today.getDayOfMonth(); + } + + /** + * 鑾峰彇褰撳ぉ1512312359鏍煎紡鐨刬nt鍊 + * + * @return 1512312359鏍煎紡鐨刬nt鍊 + */ + public static int todayYYMMDDHHmm() { + java.time.LocalDateTime today = java.time.LocalDateTime.now(); + return today.getYear() % 100 * 100_00_00_00 + today.getMonthValue() * 100_00_00 + today.getDayOfMonth() * 100_00 + + today.getHour() * 100 + today.getMinute(); + } + + /** + * 鑾峰彇褰撳ぉ20151231235959鏍煎紡鐨刬nt鍊 + * + * @return 20151231235959鏍煎紡鐨刬nt鍊 + */ + public static long todayYYYYMMDDHHmmss() { + java.time.LocalDateTime today = java.time.LocalDateTime.now(); + return today.getYear() * 100_00_00_00_00L + today.getMonthValue() * 100_00_00_00 + today.getDayOfMonth() * 100_00_00 + + today.getHour() * 100_00 + today.getMinute() * 100 + today.getSecond(); + } + + /** + * 鑾峰彇褰撳ぉ151231235959鏍煎紡鐨刬nt鍊 + * + * @return 151231235959鏍煎紡鐨刬nt鍊 + */ + public static long todayYYMMDDHHmmss() { + java.time.LocalDateTime today = java.time.LocalDateTime.now(); + return today.getYear() % 100 * 100_00_00_00_00L + today.getMonthValue() * 100_00_00_00 + today.getDayOfMonth() * 100_00_00 + + today.getHour() * 100_00 + today.getMinute() * 100 + today.getSecond(); + } + + /** + * 鑾峰彇鏄庡ぉ20151230鏍煎紡鐨刬nt鍊 + * + * @return 20151230鏍煎紡鐨刬nt鍊 + */ + public static int tomorrow() { + Calendar cal = Calendar.getInstance(); + cal.add(Calendar.DAY_OF_YEAR, 1); + return cal.get(Calendar.YEAR) * 10000 + (cal.get(Calendar.MONTH) + 1) * 100 + cal.get(Calendar.DAY_OF_MONTH); + } + + /** + * 鑾峰彇鏄庡ぉ151230鏍煎紡鐨刬nt鍊 + * + * @return 151230鏍煎紡鐨刬nt鍊 + */ + public static int tomorrowYYMMDD() { + Calendar cal = Calendar.getInstance(); + cal.add(Calendar.DAY_OF_YEAR, 1); + return cal.get(Calendar.YEAR) % 100 * 10000 + (cal.get(Calendar.MONTH) + 1) * 100 + cal.get(Calendar.DAY_OF_MONTH); + } + + /** + * 鑾峰彇鏄ㄥぉ20151230鏍煎紡鐨刬nt鍊 + * + * @return 20151230鏍煎紡鐨刬nt鍊 + */ + public static int yesterday() { + Calendar cal = Calendar.getInstance(); + cal.add(Calendar.DAY_OF_YEAR, -1); + return cal.get(Calendar.YEAR) * 10000 + (cal.get(Calendar.MONTH) + 1) * 100 + cal.get(Calendar.DAY_OF_MONTH); + } + + /** + * 鑾峰彇鏄ㄥぉ151230鏍煎紡鐨刬nt鍊 + * + * @return 151230鏍煎紡鐨刬nt鍊 + */ + public static int yesterdayYYMMDD() { + Calendar cal = Calendar.getInstance(); + cal.add(Calendar.DAY_OF_YEAR, -1); + return cal.get(Calendar.YEAR) % 100 * 10000 + (cal.get(Calendar.MONTH) + 1) * 100 + cal.get(Calendar.DAY_OF_MONTH); + } + + /** + * 鑾峰彇鎸囧畾鏃堕棿鐨20160202鏍煎紡鐨刬nt鍊 + * + * @param time 鎸囧畾鏃堕棿 + * + * @return 姣鏁 + */ + public static int yyyyMMdd(long time) { + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(time); + return cal.get(Calendar.YEAR) * 10000 + (cal.get(Calendar.MONTH) + 1) * 100 + cal.get(Calendar.DAY_OF_MONTH); + } + + /** + * 鑾峰彇鎸囧畾鏃堕棿鐨160202鏍煎紡鐨刬nt鍊 + * + * @param time 鎸囧畾鏃堕棿 + * + * @return 姣鏁 + */ + public static int yyMMdd(long time) { + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(time); + return cal.get(Calendar.YEAR) % 100 * 10000 + (cal.get(Calendar.MONTH) + 1) * 100 + cal.get(Calendar.DAY_OF_MONTH); + } + + /** + * 鑾峰彇褰撳ぉ16020223鏍煎紡鐨刬nt鍊 + * + * @param time 鎸囧畾鏃堕棿 + * + * @return 16020223鏍煎紡鐨刬nt鍊 + */ + public static int yyMMDDHHmm(long time) { + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(time); + return cal.get(Calendar.YEAR) % 100 * 100_00_00 + (cal.get(Calendar.MONTH) + 1) * 100_00 + cal.get(Calendar.DAY_OF_MONTH) * 100 + cal.get(Calendar.HOUR_OF_DAY); + } + + /** + * 鑾峰彇鏃堕棿鐐规墍鍦ㄦ槦鏈熺殑鍛ㄤ竴 + * + * @param time 鎸囧畾鏃堕棿 + * + * @return 姣鏁 + */ + public static long monday(long time) { + ZoneId zid = ZoneId.systemDefault(); + Instant instant = Instant.ofEpochMilli(time); + LocalDate ld = instant.atZone(zid).toLocalDate(); + ld = ld.minusDays(ld.getDayOfWeek().getValue() - 1); + return ld.atStartOfDay(zid).toInstant().toEpochMilli(); + } + + /** + * 鑾峰彇鏃堕棿鐐规墍鍦ㄦ槦鏈熺殑鍛ㄦ棩 + * + * @param time 鎸囧畾鏃堕棿 + * + * @return 姣鏁 + */ + public static long sunday(long time) { + ZoneId zid = ZoneId.systemDefault(); + Instant instant = Instant.ofEpochMilli(time); + LocalDate ld = instant.atZone(zid).toLocalDate(); + ld = ld.plusDays(7 - ld.getDayOfWeek().getValue()); + return ld.atStartOfDay(zid).toInstant().toEpochMilli(); + } + + /** + * 鑾峰彇鏃堕棿鐐规墍鍦ㄦ湀浠界殑1鍙 + * + * @param time 鎸囧畾鏃堕棿 + * + * @return 姣鏁 + */ + public static long monthFirstDay(long time) { + ZoneId zid = ZoneId.systemDefault(); + Instant instant = Instant.ofEpochMilli(time); + LocalDate ld = instant.atZone(zid).toLocalDate().withDayOfMonth(1); + return ld.atStartOfDay(zid).toInstant().toEpochMilli(); + } + + /** + * 鑾峰彇鏃堕棿鐐规墍鍦ㄦ湀浠界殑鏈鍚庝竴澶 + * + * @param time 鎸囧畾鏃堕棿 + * + * @return 姣鏁 + */ + public static long monthLastDay(long time) { + ZoneId zid = ZoneId.systemDefault(); + Instant instant = Instant.ofEpochMilli(time); + LocalDate ld = instant.atZone(zid).toLocalDate(); + ld = ld.withDayOfMonth(ld.lengthOfMonth()); + return ld.atStartOfDay(zid).toInstant().toEpochMilli(); + } + + /** + * 灏唅nt[]寮哄埗杞崲鎴恇yte[] + * + * @param value int[] + * + * @return byte[] + */ + public static byte[] intsToBytes(int[] value) { + if (value == null) return null; + byte[] bs = new byte[value.length]; + for (int i = 0; i < bs.length; i++) { + bs[i] = (byte) value[i]; + } + return bs; + } + + /** + * MD5鍔犲瘑 + * + * @param bs 寰呭姞瀵嗘暟鎹 + * + * @return md5鍊 + */ + public static String md5Hex(byte[] bs) { + return binToHexString(md5Bytes(bs)); + } + + /** + * MD5鍔犲瘑 + * + * @param bs 寰呭姞瀵嗘暟鎹 + * + * @return md5鍊 + */ + public static byte[] md5Bytes(byte[] bs) { + if (bs == null) return null; + MessageDigest md5; + try { + md5 = MessageDigest.getInstance("MD5"); + } catch (NoSuchAlgorithmException ex) { + throw new RuntimeException(ex); + } + return md5.digest(bs); + } + + /** + * MD5鍔犲瘑 + * + * @param str 寰呭姞瀵嗘暟鎹 + * + * @return md5鍊 + */ + public static String md5Hex(String str) { + return binToHexString(md5Bytes(str)); + } + + /** + * MD5鍔犲瘑 + * + * @param str 寰呭姞瀵嗘暟鎹 + * + * @return md5鍊 + */ + public static byte[] md5Bytes(String str) { + if (str == null) return null; + MessageDigest md5; + try { + md5 = MessageDigest.getInstance("MD5"); + } catch (NoSuchAlgorithmException ex) { + throw new RuntimeException(ex); + } + return md5.digest(str.getBytes()); + } + + /** + * SHA-256 + * + * @param bs 寰卙ash鏁版嵁 + * + * @return hash鍊 + */ + public static String sha256Hex(byte[] bs) { + return binToHexString(sha256Bytes(bs)); + } + + /** + * SHA-256 + * + * @param bs 寰卙ash鏁版嵁 + * + * @return hash鍊 + */ + public static byte[] sha256Bytes(byte[] bs) { + if (bs == null) return null; + MessageDigest digester; + try { + digester = MessageDigest.getInstance("SHA-256"); + } catch (NoSuchAlgorithmException ex) { + throw new RuntimeException(ex); + } + return digester.digest(bs); + } + + /** + * SHA-256 + * + * @param str 寰卙ash鏁版嵁 + * + * @return hash鍊 + */ + public static String sha256Hex(String str) { + return binToHexString(sha256Bytes(str)); + } + + /** + * SHA-256 + * + * @param str 寰卙ash鏁版嵁 + * + * @return hash鍊 + */ + public static byte[] sha256Bytes(String str) { + if (str == null) return null; + MessageDigest digester; + try { + digester = MessageDigest.getInstance("SHA-256"); + } catch (NoSuchAlgorithmException ex) { + throw new RuntimeException(ex); + } + return digester.digest(str.getBytes()); + } + + /** + * 灏嗗瓧鑺傛暟缁勮浆鎹负16杩涘埗瀛楃涓 + * + * @param bytes 瀛楄妭鏁扮粍 + * + * @return 16杩涘埗瀛楃涓 + */ + public static String binToHexString(byte[] bytes) { + return new String(binToHex(bytes)); + } + + /** + * 灏嗗瓧鑺傛暟缁勮浆鎹负16杩涘埗瀛楃鏁扮粍 + * + * @param bytes 瀛楄妭鏁扮粍 + * + * @return 16杩涘埗瀛楃涓茬殑瀛楃鏁扮粍 + */ + public static char[] binToHex(byte[] bytes) { + return binToHex(bytes, 0, bytes.length); + } + + /** + * 灏嗗瓧鑺傛暟缁勮浆鎹负16杩涘埗瀛楃涓 + * + * @param bytes 瀛楄妭鏁扮粍 + * @param offset 鍋忕Щ閲 + * @param len 闀垮害 + * + * @return 16杩涘埗瀛楃涓 + */ + public static String binToHexString(byte[] bytes, int offset, int len) { + return new String(binToHex(bytes, offset, len)); + } + + /** + * 灏嗗瓧鑺傛暟缁勮浆鎹负16杩涘埗瀛楃鏁扮粍 + * + * @param bytes 瀛楄妭鏁扮粍 + * @param offset 鍋忕Щ閲 + * @param len 闀垮害 + * + * @return 16杩涘埗瀛楃涓茬殑瀛楃鏁扮粍 + */ + public static char[] binToHex(byte[] bytes, int offset, int len) { + final char[] sb = new char[len * 2]; + final int end = offset + len; + int index = 0; + final char[] hexs = hex; + for (int i = offset; i < end; i++) { + byte b = bytes[i]; + sb[index++] = (hexs[((b >> 4) & 0xF)]); + sb[index++] = hexs[((b) & 0xF)]; + } + return sb; + } + + /** + * 灏16杩涘埗瀛楃涓茶浆鎹㈡垚瀛楄妭鏁扮粍 + * + * @param src 16杩涘埗瀛楃涓 + * + * @return 瀛楄妭鏁扮粍 + */ + public static byte[] hexToBin(CharSequence src) { + return hexToBin(src, 0, src.length()); + } + + /** + * + * 灏16杩涘埗瀛楃涓茶浆鎹㈡垚瀛楄妭鏁扮粍 + * + * @param src 16杩涘埗瀛楃涓 + * @param offset 鍋忕Щ閲 + * @param len 闀垮害 + * + * @return 瀛楄妭鏁扮粍 + */ + public static byte[] hexToBin(CharSequence src, int offset, int len) { + final int size = (len + 1) / 2; + final byte[] bytes = new byte[size]; + String digits = "0123456789abcdef"; + for (int i = 0; i < size; i++) { + int ch1 = src.charAt(offset + i * 2); + if ('A' <= ch1 && 'F' >= ch1) ch1 = ch1 - 'A' + 'a'; + int ch2 = src.charAt(offset + i * 2 + 1); + if ('A' <= ch2 && 'F' >= ch2) ch2 = ch2 - 'A' + 'a'; + int pos1 = digits.indexOf(ch1); + if (pos1 < 0) throw new NumberFormatException(); + int pos2 = digits.indexOf(ch2); + if (pos2 < 0) throw new NumberFormatException(); + bytes[i] = (byte) (pos1 * 0x10 + pos2); + } + return bytes; + } + + /** + * + * 灏16杩涘埗瀛楃涓茶浆鎹㈡垚瀛楄妭鏁扮粍 + * + * @param str 16杩涘埗瀛楃涓 + * + * @return 瀛楄妭鏁扮粍 + */ + public static byte[] hexToBin(String str) { + return hexToBin(charArray(str)); + } + + /** + * + * 灏16杩涘埗瀛楃鏁扮粍杞崲鎴愬瓧鑺傛暟缁 + * + * @param src 16杩涘埗瀛楃鏁扮粍 + * + * @return 瀛楄妭鏁扮粍 + */ + public static byte[] hexToBin(char[] src) { + return hexToBin(src, 0, src.length); + } + + /** + * 灏16杩涘埗瀛楃鏁扮粍杞崲鎴愬瓧鑺傛暟缁 + * + * @param src 16杩涘埗瀛楃鏁扮粍 + * @param offset 鍋忕Щ閲 + * @param len 闀垮害 + * + * @return 瀛楄妭鏁扮粍 + */ + public static byte[] hexToBin(char[] src, int offset, int len) { + final int size = (len + 1) / 2; + final byte[] bytes = new byte[size]; + String digits = "0123456789abcdef"; + for (int i = 0; i < size; i++) { + int ch1 = src[offset + i * 2]; + if ('A' <= ch1 && 'F' >= ch1) ch1 = ch1 - 'A' + 'a'; + int ch2 = src[offset + i * 2 + 1]; + if ('A' <= ch2 && 'F' >= ch2) ch2 = ch2 - 'A' + 'a'; + int pos1 = digits.indexOf(ch1); + if (pos1 < 0) throw new NumberFormatException(); + int pos2 = digits.indexOf(ch2); + if (pos2 < 0) throw new NumberFormatException(); + bytes[i] = (byte) (pos1 * 0x10 + pos2); + } + return bytes; + } + + //----------------------------------------------------------------------------- + /** + * 浣跨敤UTF-8缂栫爜灏哹yte[]杞崲鎴恈har[] + * + * @param array byte[] + * + * @return char[] + */ + public static char[] decodeUTF8(final byte[] array) { + return decodeUTF8(array, 0, array.length); + } + + public static char[] decodeUTF8(final byte[] array, final int start, final int len) { + byte b; + int size = len; + final byte[] bytes = array; + final int limit = start + len; + for (int i = start; i < limit; i++) { + b = bytes[i]; + if ((b >> 5) == -2) {// 2 bytes, 11 bits: 110xxxxx 10xxxxxx + size--; + } else if ((b >> 4) == -2) {// 3 bytes, 16 bits: 1110xxxx 10xxxxxx 10xxxxxx + size -= 2; + } else if ((b >> 3) == -2) {// 4 bytes, 21 bits: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + size -= 2; + } + } + final char[] text = new char[size]; + size = 0; + for (int i = start; i < limit;) { + b = bytes[i++]; + if (b >= 0) {// 1 byte, 7 bits: 0xxxxxxx + text[size++] = (char) b; + } else if ((b >> 5) == -2) {// 2 bytes, 11 bits: 110xxxxx 10xxxxxx + text[size++] = (char) (((b << 6) ^ bytes[i++]) ^ (((byte) 0xC0 << 6) ^ ((byte) 0x80))); + } else if ((b >> 4) == -2) {// 3 bytes, 16 bits: 1110xxxx 10xxxxxx 10xxxxxx + text[size++] = (char) ((b << 12) ^ (bytes[i++] << 6) ^ (bytes[i++] ^ (((byte) 0xE0 << 12) ^ ((byte) 0x80 << 6) ^ ((byte) 0x80)))); + } else if ((b >> 3) == -2) {// 4 bytes, 21 bits: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + int uc = ((b << 18) ^ (bytes[i++] << 12) ^ (bytes[i++] << 6) ^ (bytes[i++] ^ (((byte) 0xF0 << 18) ^ ((byte) 0x80 << 12) ^ ((byte) 0x80 << 6) ^ ((byte) 0x80)))); + text[size++] = Character.highSurrogate(uc); + text[size++] = Character.lowSurrogate(uc); + //娴嬭瘯浠g爜 byte[] bs = {(byte)34, (byte)76, (byte)105, (byte)108, (byte)121, (byte)240, (byte)159, (byte)146, (byte)171, (byte)34}; + } + } + return text; + } + + public static byte[] encodeUTF8(final String value) { + if (value == null) return new byte[0]; + if (strCharFunction == null) return encodeUTF8(value.toCharArray()); + return encodeUTF8((char[]) strCharFunction.apply(value)); + } + + public static byte[] encodeUTF8(final char[] array) { + return encodeUTF8(array, 0, array.length); + } + + public static byte[] encodeUTF8(final char[] text, final int start, final int len) { + char c; + int size = 0; + final char[] chs = text; + final int limit = start + len; + for (int i = start; i < limit; i++) { + c = chs[i]; + if (c < 0x80) { + size++; + } else if (c < 0x800) { + size += 2; + } else if (Character.isSurrogate(c)) { + size += 2; + } else { + size += 3; + } + } + final byte[] bytes = new byte[size]; + size = 0; + for (int i = start; i < limit; i++) { + c = chs[i]; + if (c < 0x80) { + bytes[size++] = (byte) c; + } else if (c < 0x800) { + bytes[size++] = (byte) (0xc0 | (c >> 6)); + bytes[size++] = (byte) (0x80 | (c & 0x3f)); + } else if (Character.isSurrogate(c)) { //杩炲彇涓や釜 + int uc = Character.toCodePoint(c, chs[i + 1]); + bytes[size++] = (byte) (0xf0 | ((uc >> 18))); + bytes[size++] = (byte) (0x80 | ((uc >> 12) & 0x3f)); + bytes[size++] = (byte) (0x80 | ((uc >> 6) & 0x3f)); + bytes[size++] = (byte) (0x80 | (uc & 0x3f)); + i++; + } else { + bytes[size++] = (byte) (0xe0 | ((c >> 12))); + bytes[size++] = (byte) (0x80 | ((c >> 6) & 0x3f)); + bytes[size++] = (byte) (0x80 | (c & 0x3f)); + } + } + return bytes; + } + + public static long getAddress(ByteBuffer buffer) { + return bufferAddrFunction.applyAsLong(buffer); + } + + public static boolean isLatin1(String value) { + if (value == null) return true; + if (strLatin1Function != null) { + return strLatin1Function.test(value); //LATIN1:0 UTF16:1 + } + char[] chs = charArray(value); + for (char ch : chs) { + if (ch >= 0x80) return false; + } + return true; + } + + public static char[] charArray(String value) { + if (value == null) return null; + if (strCharFunction == null) return value.toCharArray(); + return (char[]) strCharFunction.apply(value); + } + + public static char[] charArray(StringBuilder value) { + if (value == null) return null; + if (sbCharFunction == null) return value.toString().toCharArray(); + return (char[]) sbCharFunction.apply(value); + } + + //鍙兘鏄崟瀛楄妭瀛楃涓 + public static byte[] latin1ByteArray(String latin1Value) { + if (latin1Value == null) return null; + if (strByteFunction == null) return latin1Value.getBytes(); + return (byte[]) strByteFunction.apply(latin1Value); + } + + //鍙兘鏄崟瀛楄妭瀛楃涓 + public static byte[] latin1ByteArray(StringBuilder latin1Value) { + if (latin1Value == null) return null; + if (sbByteFunction == null) return latin1Value.toString().getBytes(); + return (byte[]) sbByteFunction.apply(latin1Value); + } + + public static ByteBuffer encodeUTF8(final ByteBuffer buffer, final char[] array) { + return encodeUTF8(buffer, array, 0, array.length); + } + + public static ByteBuffer encodeUTF8(final ByteBuffer buffer, int bytesLength, final char[] array) { + return encodeUTF8(buffer, bytesLength, array, 0, array.length); + } + + public static int encodeUTF8Length(String value) { + if (value == null) return -1; + if (strCharFunction == null) return encodeUTF8Length(value.toCharArray()); + return encodeUTF8Length((char[]) strCharFunction.apply(value)); + } + + public static int encodeUTF8Length(final char[] text) { + return encodeUTF8Length(text, 0, text.length); + } + + public static int encodeUTF8Length(final char[] text, final int start, final int len) { + char c; + int size = 0; + final char[] chs = text; + final int limit = start + len; + for (int i = start; i < limit; i++) { + c = chs[i]; + if (c < 0x80) { + size++; + } else if (c < 0x800) { + size += 2; + } else if (Character.isSurrogate(c)) { + size += 2; + } else { + size += 3; + } + } + return size; + } + + /** + * 灏嗕袱涓暟瀛楃粍瑁呮垚涓涓猯ong + * + * @param high 楂樹綅鍊 + * @param low 浣庝綅鍊 + * + * @return long鍊 + */ + public static long merge(int high, int low) { + return (0L + high) << 32 | low; + } + + public static ByteBuffer encodeUTF8(final ByteBuffer buffer, final char[] text, final int start, final int len) { + return encodeUTF8(buffer, encodeUTF8Length(text, start, len), text, start, len); + } + + //杩斿洖鐨凚yteBuffer涓烘墿灞昩uffer锛屼负null琛ㄧず鍙傛暟涓殑buffer瓒冲瀛樺偍鏁版嵁 + public static ByteBuffer encodeUTF8(final ByteBuffer buffer, int bytesLength, final char[] text, final int start, final int len) { + char c; + char[] chs = text; + final int limit = start + len; + int remain = buffer.remaining(); + final ByteBuffer buffer2 = remain >= bytesLength ? null : ByteBuffer.allocate(bytesLength - remain + 4); //鏈宸儏鍐礲uffer鏈鍚庝袱byte娌℃湁濉厖 + ByteBuffer buf = buffer; + for (int i = start; i < limit; i++) { + c = chs[i]; + if (c < 0x80) { + if (buf.remaining() < 1) buf = buffer2; + buf.put((byte) c); + } else if (c < 0x800) { + if (buf.remaining() < 2) buf = buffer2; + buf.put((byte) (0xc0 | (c >> 6))); + buf.put((byte) (0x80 | (c & 0x3f))); + } else if (Character.isSurrogate(c)) { //杩炲彇涓や釜 + if (buf.remaining() < 4) buf = buffer2; + int uc = Character.toCodePoint(c, chs[i + 1]); + buf.put((byte) (0xf0 | ((uc >> 18)))); + buf.put((byte) (0x80 | ((uc >> 12) & 0x3f))); + buf.put((byte) (0x80 | ((uc >> 6) & 0x3f))); + buf.put((byte) (0x80 | (uc & 0x3f))); + i++; + } else { + if (buf.remaining() < 3) buf = buffer2; + buf.put((byte) (0xe0 | ((c >> 12)))); + buf.put((byte) (0x80 | ((c >> 6) & 0x3f))); + buf.put((byte) (0x80 | (c & 0x3f))); + } + } + if (buffer2 != null) buffer2.flip(); + return buffer2; //杩斿洖鎵╁睍buffer + } + + public static String getTypeDescriptor(java.lang.reflect.Type type) { + if (type == null) return null; + if (type instanceof Class) { + Class d = (Class) type; + final StringBuilder sb = new StringBuilder(); + while (true) { + if (d.isPrimitive()) { + char car; + if (d == Integer.TYPE) { + car = 'I'; + } else if (d == Void.TYPE) { + car = 'V'; + } else if (d == Boolean.TYPE) { + car = 'Z'; + } else if (d == Byte.TYPE) { + car = 'B'; + } else if (d == Character.TYPE) { + car = 'C'; + } else if (d == Short.TYPE) { + car = 'S'; + } else if (d == Double.TYPE) { + car = 'D'; + } else if (d == Float.TYPE) { + car = 'F'; + } else /* if (d == Long.TYPE) */ { + car = 'J'; + } + return sb.append(car).toString(); + } else if (d.isArray()) { + sb.append('['); + d = d.getComponentType(); + } else { + sb.append('L'); + String name = d.getName(); + int len = name.length(); + for (int i = 0; i < len; ++i) { + char car = name.charAt(i); + sb.append(car == '.' ? '/' : car); + } + return sb.append(';').toString(); + } + } + } + if (type instanceof ParameterizedType) {// 渚嬪: Map + ParameterizedType pt = (ParameterizedType) type; + final StringBuilder sb = new StringBuilder(); + String raw = getTypeDescriptor(pt.getRawType()); + sb.append(raw.substring(0, raw.length() - 1)).append('<'); + for (java.lang.reflect.Type item : pt.getActualTypeArguments()) { + sb.append(getTypeDescriptor(item)); + } + return sb.append(">;").toString(); + } + if (type instanceof WildcardType) { // 渚嬪: + final WildcardType wt = (WildcardType) type; + final StringBuilder sb = new StringBuilder(); + java.lang.reflect.Type[] us = wt.getUpperBounds(); + java.lang.reflect.Type[] ls = wt.getLowerBounds(); + if (ls.length < 1) { + if (us.length == 1 && us[0] == Object.class) { + sb.append('*'); + } else { + for (java.lang.reflect.Type f : us) { + sb.append('+'); + sb.append(getTypeDescriptor(f)); + } + } + } + for (java.lang.reflect.Type f : ls) { + sb.append('-'); + sb.append(getTypeDescriptor(f)); + } + return sb.toString(); + } + //TypeVariable 涓嶆敮鎸 + return null; + } + + //----------------------------------------------------------------------------- +// public static javax.net.ssl.SSLContext getDefaultSSLContext() { +// return DEFAULTSSL_CONTEXT; +// } +// +// public static javax.net.ssl.HostnameVerifier getDefaultHostnameVerifier() { +// return defaultVerifier; +// } +// +// public static Socket createDefaultSSLSocket(InetSocketAddress address) throws IOException { +// return createDefaultSSLSocket(address.getAddress(), address.getPort()); +// } +// +// public static Socket createDefaultSSLSocket(InetAddress host, int port) throws IOException { +// Socket socket = DEFAULTSSL_CONTEXT.getSocketFactory().createSocket(host, port); +// return socket; +// } + // + public static String postHttpContent(String url) throws IOException { + return remoteHttpContent("POST", url, 0, null, null).toString(StandardCharsets.UTF_8); + } + + public static String postHttpContent(String url, int timeout) throws IOException { + return remoteHttpContent("POST", url, timeout, null, null).toString(StandardCharsets.UTF_8); + } + + public static String postHttpContent(String url, String body) throws IOException { + return remoteHttpContent("POST", url, 0, null, body).toString(StandardCharsets.UTF_8); + } + + public static String postHttpContent(String url, int timeout, String body) throws IOException { + return remoteHttpContent("POST", url, timeout, null, body).toString(StandardCharsets.UTF_8); + } + + public static String postHttpContent(String url, Map headers, String body) throws IOException { + return remoteHttpContent("POST", url, 0, headers, body).toString(StandardCharsets.UTF_8); + } + + public static String postHttpContent(String url, int timeout, Map headers, String body) throws IOException { + return remoteHttpContent("POST", url, timeout, headers, body).toString(StandardCharsets.UTF_8); + } + + public static String postHttpContent(String url, Charset charset) throws IOException { + return remoteHttpContent("POST", url, 0, null, null).toString(charset.name()); + } + + public static String postHttpContent(String url, int timeout, Charset charset) throws IOException { + return remoteHttpContent("POST", url, timeout, null, null).toString(charset.name()); + } + + public static String postHttpContent(String url, Charset charset, String body) throws IOException { + return remoteHttpContent("POST", url, 0, null, body).toString(charset.name()); + } + + public static String postHttpContent(String url, int timeout, Charset charset, String body) throws IOException { + return remoteHttpContent("POST", url, timeout, null, body).toString(charset.name()); + } + + public static String postHttpContent(String url, Charset charset, Map headers, String body) throws IOException { + return remoteHttpContent("POST", url, 0, headers, body).toString(charset.name()); + } + + public static String postHttpContent(String url, int timeout, Charset charset, Map headers, String body) throws IOException { + return remoteHttpContent("POST", url, timeout, headers, body).toString(charset.name()); + } + + public static byte[] postHttpBytesContent(String url) throws IOException { + return remoteHttpContent("POST", url, 0, null, null).toByteArray(); + } + + public static byte[] postHttpBytesContent(String url, int timeout) throws IOException { + return remoteHttpContent("POST", url, timeout, null, null).toByteArray(); + } + + public static byte[] postHttpBytesContent(String url, Map headers, String body) throws IOException { + return remoteHttpContent("POST", url, 0, headers, body).toByteArray(); + } + + public static byte[] postHttpBytesContent(String url, int timeout, Map headers, String body) throws IOException { + return remoteHttpContent("POST", url, timeout, headers, body).toByteArray(); + } + + public static String getHttpContent(String url) throws IOException { + return remoteHttpContent("GET", url, 0, null, null).toString(StandardCharsets.UTF_8); + } + + public static String getHttpContent(String url, int timeout) throws IOException { + return remoteHttpContent("GET", url, timeout, null, null).toString(StandardCharsets.UTF_8); + } + + public static String getHttpContent(String url, Map headers, String body) throws IOException { + return remoteHttpContent("GET", url, 0, headers, body).toString(StandardCharsets.UTF_8); + } + + public static String getHttpContent(String url, int timeout, Map headers, String body) throws IOException { + return remoteHttpContent("GET", url, timeout, headers, body).toString(StandardCharsets.UTF_8); + } + + public static String getHttpContent(String url, Charset charset) throws IOException { + return remoteHttpContent("GET", url, 0, null, null).toString(charset.name()); + } + + public static String getHttpContent(String url, int timeout, Charset charset) throws IOException { + return remoteHttpContent("GET", url, timeout, null, null).toString(charset.name()); + } + + public static String getHttpContent(String url, Charset charset, Map headers, String body) throws IOException { + return remoteHttpContent("GET", url, 0, headers, body).toString(charset.name()); + } + + public static String getHttpContent(String url, int timeout, Charset charset, Map headers, String body) throws IOException { + return remoteHttpContent("GET", url, timeout, headers, body).toString(charset.name()); + } + + public static byte[] getHttpBytesContent(String url) throws IOException { + return remoteHttpContent("GET", url, 0, null, null).toByteArray(); + } + + public static byte[] getHttpBytesContent(String url, int timeout) throws IOException { + return remoteHttpContent("GET", url, timeout, null, null).toByteArray(); + } + + public static byte[] getHttpBytesContent(String url, Map headers, String body) throws IOException { + return remoteHttpContent("GET", url, 0, headers, body).toByteArray(); + } + + public static byte[] getHttpBytesContent(String url, int timeout, Map headers, String body) throws IOException { + return remoteHttpContent("GET", url, timeout, headers, body).toByteArray(); + } + + public static ByteArrayOutputStream remoteHttpContent(String method, String url, Map headers, String body) throws IOException { + return remoteHttpContent(method, url, 0, headers, body); + } + + public static ByteArrayOutputStream remoteHttpContent(String method, String url, int timeout, Map headers, String body) throws IOException { + return remoteHttpContentAsync(method, url, timeout, headers, body).join(); + } + + public static CompletableFuture postHttpContentAsync(String url) { + return remoteHttpContentAsync("POST", url, 0, null, null).thenApply(out -> out.toString(StandardCharsets.UTF_8)); + } + + public static CompletableFuture postHttpContentAsync(String url, int timeout) { + return remoteHttpContentAsync("POST", url, timeout, null, null).thenApply(out -> out.toString(StandardCharsets.UTF_8)); + } + + public static CompletableFuture postHttpContentAsync(String url, String body) { + return remoteHttpContentAsync("POST", url, 0, null, body).thenApply(out -> out.toString(StandardCharsets.UTF_8)); + } + + public static CompletableFuture postHttpContentAsync(String url, int timeout, String body) { + return remoteHttpContentAsync("POST", url, timeout, null, body).thenApply(out -> out.toString(StandardCharsets.UTF_8)); + } + + public static CompletableFuture postHttpContentAsync(String url, Map headers, String body) { + return remoteHttpContentAsync("POST", url, 0, headers, body).thenApply(out -> out.toString(StandardCharsets.UTF_8)); + } + + public static CompletableFuture postHttpContentAsync(String url, int timeout, Map headers, String body) { + return remoteHttpContentAsync("POST", url, timeout, headers, body).thenApply(out -> out.toString(StandardCharsets.UTF_8)); + } + + public static CompletableFuture postHttpContentAsync(String url, Charset charset) { + return remoteHttpContentAsync("POST", url, 0, null, null).thenApply(out -> out.toString(charset)); + } + + public static CompletableFuture postHttpContentAsync(String url, int timeout, Charset charset) { + return remoteHttpContentAsync("POST", url, timeout, null, null).thenApply(out -> out.toString(charset)); + } + + public static CompletableFuture postHttpContentAsync(String url, Charset charset, String body) { + return remoteHttpContentAsync("POST", url, 0, null, body).thenApply(out -> out.toString(charset)); + } + + public static CompletableFuture postHttpContentAsync(HttpClient client, String url, Charset charset, String body) { + return remoteHttpContentAsync(client, "POST", url, 0, null, body).thenApply(out -> out.toString(charset)); + } + + public static CompletableFuture postHttpContentAsync(String url, int timeout, Charset charset, String body) { + return remoteHttpContentAsync("POST", url, timeout, null, body).thenApply(out -> out.toString(charset)); + } + + public static CompletableFuture postHttpContentAsync(String url, Charset charset, Map headers, String body) { + return remoteHttpContentAsync("POST", url, 0, headers, body).thenApply(out -> out.toString(charset)); + } + + public static CompletableFuture postHttpContentAsync(String url, int timeout, Charset charset, Map headers, String body) { + return remoteHttpContentAsync("POST", url, timeout, headers, body).thenApply(out -> out.toString(charset)); + } + + public static CompletableFuture postHttpBytesContentAsync(String url) { + return remoteHttpContentAsync("POST", url, 0, null, null).thenApply(out -> out.toByteArray()); + } + + public static CompletableFuture postHttpBytesContentAsync(String url, int timeout) { + return remoteHttpContentAsync("POST", url, timeout, null, null).thenApply(out -> out.toByteArray()); + } + + public static CompletableFuture postHttpBytesContentAsync(String url, Map headers, String body) { + return remoteHttpContentAsync("POST", url, 0, headers, body).thenApply(out -> out.toByteArray()); + } + + public static CompletableFuture postHttpBytesContentAsync(String url, int timeout, Map headers, String body) { + return remoteHttpContentAsync("POST", url, timeout, headers, body).thenApply(out -> out.toByteArray()); + } + + public static CompletableFuture getHttpContentAsync(String url) { + return remoteHttpContentAsync("GET", url, 0, null, null).thenApply(out -> out.toString(StandardCharsets.UTF_8)); + } + + public static CompletableFuture getHttpContentAsync(String url, int timeout) { + return remoteHttpContentAsync("GET", url, timeout, null, null).thenApply(out -> out.toString(StandardCharsets.UTF_8)); + } + + public static CompletableFuture getHttpContentAsync(String url, Map headers, String body) { + return remoteHttpContentAsync("GET", url, 0, headers, body).thenApply(out -> out.toString(StandardCharsets.UTF_8)); + } + + public static CompletableFuture getHttpContentAsync(String url, int timeout, Map headers, String body) { + return remoteHttpContentAsync("GET", url, timeout, headers, body).thenApply(out -> out.toString(StandardCharsets.UTF_8)); + } + + public static CompletableFuture getHttpContentAsync(String url, Charset charset) { + return remoteHttpContentAsync("GET", url, 0, null, null).thenApply(out -> out.toString(charset)); + } + + public static CompletableFuture getHttpContentAsync(String url, int timeout, Charset charset) { + return remoteHttpContentAsync("GET", url, timeout, null, null).thenApply(out -> out.toString(charset)); + } + + public static CompletableFuture getHttpContentAsync(String url, Charset charset, Map headers, String body) { + return remoteHttpContentAsync("GET", url, 0, headers, body).thenApply(out -> out.toString(charset)); + } + + public static CompletableFuture getHttpContentAsync(String url, int timeout, Charset charset, Map headers, String body) { + return remoteHttpContentAsync("GET", url, timeout, headers, body).thenApply(out -> out.toString(charset)); + } + + public static CompletableFuture getHttpBytesContentAsync(String url) { + return remoteHttpContentAsync("GET", url, 0, null, null).thenApply(out -> out.toByteArray()); + } + + public static CompletableFuture getHttpBytesContentAsync(String url, int timeout) { + return remoteHttpContentAsync("GET", url, timeout, null, null).thenApply(out -> out.toByteArray()); + } + + public static CompletableFuture getHttpBytesContentAsync(String url, Map headers, String body) { + return remoteHttpContentAsync("GET", url, 0, headers, body).thenApply(out -> out.toByteArray()); + } + + public static CompletableFuture getHttpBytesContentAsync(String url, int timeout, Map headers, String body) { + return remoteHttpContentAsync("GET", url, timeout, headers, body).thenApply(out -> out.toByteArray()); + } + + public static CompletableFuture remoteHttpContentAsync(String method, String url, Map headers, String body) { + return remoteHttpContentAsync(method, url, 0, headers, body); + } + + public static CompletableFuture remoteHttpContentAsync(String method, String url, int timeout, Map headers, String body) { + return remoteHttpContentAsync(httpClient, method, url, timeout, headers, body); + } + + public static CompletableFuture remoteHttpContentAsync(java.net.http.HttpClient client, String method, String url, int timeout, Map headers, String body) { + java.net.http.HttpRequest.Builder builder = java.net.http.HttpRequest.newBuilder().uri(URI.create(url)) + .timeout(Duration.ofMillis(timeout > 0 ? timeout : 6000)) + .method(method, body == null ? java.net.http.HttpRequest.BodyPublishers.noBody() : java.net.http.HttpRequest.BodyPublishers.ofString(body)); + if (headers != null) headers.forEach((n, v) -> builder.header(n, v)); + java.net.http.HttpClient c = client == null ? httpClient : client; + if (c == null) { + synchronized (clientLock) { + if (httpClient == null) { + httpClient = java.net.http.HttpClient.newHttpClient(); + } + } + c = httpClient; + } + return c.sendAsync(builder.build(), java.net.http.HttpResponse.BodyHandlers.ofByteArray()) + .thenCompose((java.net.http.HttpResponse resp) -> { + final int rs = resp.statusCode(); + if (rs == 301 || rs == 302) { + Optional opt = resp.headers().firstValue("Location"); + if (opt.isPresent()) { + return remoteHttpContentAsync(client, method, opt.get(), timeout, headers, body); + } else { + return CompletableFuture.failedFuture(new IOException(url + " httpcode = " + rs + ", but not found Localtion")); + } + } + byte[] result = resp.body(); + if (rs == 200 || result != null) { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + if (result != null) { + if ("gzip".equalsIgnoreCase(resp.headers().firstValue("content-encoding").orElse(null))) { + try { + GZIPInputStream in = new GZIPInputStream(new ByteArrayInputStream(result)); + in.transferTo(out); + } catch (IOException e) { + return CompletableFuture.failedFuture(e); + } + } else { + out.writeBytes(result); + } + } + return CompletableFuture.completedFuture(out); + } + return CompletableFuture.failedFuture(new IOException(url + " httpcode = " + rs)); + }); + } +// +// public static ByteArrayOutputStream remoteHttpContent(SSLContext ctx, String method, String url, int timeout, Map headers, String body) throws IOException { +// HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection(); +// boolean opening = true; +// try { +// conn.setConnectTimeout(timeout > 0 ? timeout : 3000); +// conn.setReadTimeout(timeout > 0 ? timeout : 3000); +// if (conn instanceof HttpsURLConnection) { +// HttpsURLConnection httpsconn = ((HttpsURLConnection) conn); +// httpsconn.setSSLSocketFactory((ctx == null ? DEFAULTSSL_CONTEXT : ctx).getSocketFactory()); +// httpsconn.setHostnameVerifier(defaultVerifier); +// } +// conn.setRequestMethod(method); +// if (headers != null) { +// for (Map.Entry en : headers.entrySet()) { +// conn.setRequestProperty(en.getKey(), en.getValue()); +// } +// } +// if (body != null && !body.isEmpty()) { //conn.getOutputStream()浼氬皢GET寮哄埗鍙樻垚POST +// conn.setDoInput(true); +// conn.setDoOutput(true); +// conn.getOutputStream().write(body.getBytes(UTF_8)); +// } +// conn.connect(); +// int rs = conn.getResponseCode(); +// if (rs == 301 || rs == 302) { +// String newurl = conn.getHeaderField("Location"); +// conn.disconnect(); +// opening = false; +// return remoteHttpContent(ctx, method, newurl, timeout, headers, body); +// } +// InputStream in = (rs < 400 || rs == 404) && rs != 405 ? conn.getInputStream() : conn.getErrorStream(); +// if ("gzip".equalsIgnoreCase(conn.getContentEncoding())) in = new GZIPInputStream(in); +// ByteArrayOutputStream out = new ByteArrayOutputStream(1024); +// byte[] bytes = new byte[1024]; +// int pos; +// while ((pos = in.read(bytes)) != -1) { +// out.write(bytes, 0, pos); +// } +// in.close(); +// return out; +// } finally { +// if (opening) conn.disconnect(); +// } +// } + + public static String read(InputStream in) throws IOException { + return read(in, StandardCharsets.UTF_8, false); + } + + public static String readThenClose(InputStream in) throws IOException { + return read(in, StandardCharsets.UTF_8, true); + } + + public static String read(InputStream in, String charsetName) throws IOException { + return read(in, Charset.forName(charsetName), false); + } + + public static String read(InputStream in, Charset charset) throws IOException { + return read(in, charset, false); + } + + private static String read(InputStream in, Charset charset, boolean close) throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(1024); + byte[] bytes = new byte[1024]; + int pos; + while ((pos = in.read(bytes)) != -1) { + out.write(bytes, 0, pos); + } + if (close) in.close(); + return charset == null ? out.toString() : out.toString(charset); + } + + public static ByteArrayOutputStream readStream(InputStream in) throws IOException { + return readStream(in, false); + } + + public static ByteArrayOutputStream readStreamThenClose(InputStream in) throws IOException { + return readStream(in, true); + } + + private static ByteArrayOutputStream readStream(InputStream in, boolean close) throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(1024); + byte[] bytes = new byte[1024]; + int pos; + while ((pos = in.read(bytes)) != -1) { + out.write(bytes, 0, pos); + } + if (close) in.close(); + return out; + } + + public static byte[] readBytes(File file) throws IOException { + return readBytesThenClose(new FileInputStream(file)); + } + + public static byte[] readBytes(InputStream in) throws IOException { + return readStream(in).toByteArray(); + } + + public static byte[] readBytesThenClose(InputStream in) throws IOException { + return readStreamThenClose(in).toByteArray(); + } +} diff --git a/src/main/java/org/redkale/util/Version.java b/src/main/java/org/redkale/util/Version.java index a4f0ecbf0..2165d3fc7 100644 --- a/src/main/java/org/redkale/util/Version.java +++ b/src/main/java/org/redkale/util/Version.java @@ -1,29 +1,29 @@ -/* - * 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.util; - -import java.lang.annotation.*; -import static java.lang.annotation.ElementType.*; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * 鐗堟湰, 鍙敤浜庢爣璁癝ervice鐨勬帴鍙g増鏈彉鍖 - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @since 2.1.0 - * - * @author zhangjx - */ -@Inherited -@Documented -@Target({TYPE, METHOD}) -@Retention(RUNTIME) -public @interface Version { - - int value(); -} +/* + * 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.util; + +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * 鐗堟湰, 鍙敤浜庢爣璁癝ervice鐨勬帴鍙g増鏈彉鍖 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @since 2.1.0 + * + * @author zhangjx + */ +@Inherited +@Documented +@Target({TYPE, METHOD}) +@Retention(RUNTIME) +public @interface Version { + + int value(); +} diff --git a/src/main/java/org/redkale/util/package-info.java b/src/main/java/org/redkale/util/package-info.java index 2b8f05886..1b87e373b 100644 --- a/src/main/java/org/redkale/util/package-info.java +++ b/src/main/java/org/redkale/util/package-info.java @@ -1,4 +1,4 @@ -/** - * Redkale宸ュ叿鍖 - */ -package org.redkale.util; +/** + * Redkale宸ュ叿鍖 + */ +package org.redkale.util; diff --git a/src/main/java/org/redkale/watch/WatchFilter.java b/src/main/java/org/redkale/watch/WatchFilter.java index 27d060849..2050e5b49 100644 --- a/src/main/java/org/redkale/watch/WatchFilter.java +++ b/src/main/java/org/redkale/watch/WatchFilter.java @@ -1,18 +1,18 @@ -/* - * 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.watch; - -import org.redkale.net.http.HttpFilter; - -/** - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public abstract class WatchFilter extends HttpFilter { - -} +/* + * 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.watch; + +import org.redkale.net.http.HttpFilter; + +/** + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public abstract class WatchFilter extends HttpFilter { + +} diff --git a/src/main/java/org/redkale/watch/WatchService.java b/src/main/java/org/redkale/watch/WatchService.java index 6f22776c5..bf6f32fb8 100644 --- a/src/main/java/org/redkale/watch/WatchService.java +++ b/src/main/java/org/redkale/watch/WatchService.java @@ -1,20 +1,20 @@ -/* - * 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.watch; - -import org.redkale.service.*; - -/** - * 鍙粰WATCH鍗忚鐨凷erver鎵嶈兘鍔犺浇鐨凷ervice锛屽叾浠栧崗璁殑Server鍧囦笉鑳借嚜鍔ㄥ姞杞絎atchService - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public interface WatchService extends Service { - -} +/* + * 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.watch; + +import org.redkale.service.*; + +/** + * 鍙粰WATCH鍗忚鐨凷erver鎵嶈兘鍔犺浇鐨凷ervice锛屽叾浠栧崗璁殑Server鍧囦笉鑳借嚜鍔ㄥ姞杞絎atchService + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public interface WatchService extends Service { + +} diff --git a/src/main/java/org/redkale/watch/WatchServlet.java b/src/main/java/org/redkale/watch/WatchServlet.java index e8d3838a0..4739f3513 100644 --- a/src/main/java/org/redkale/watch/WatchServlet.java +++ b/src/main/java/org/redkale/watch/WatchServlet.java @@ -1,19 +1,19 @@ -/* - * 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.watch; - -import org.redkale.net.http.HttpServlet; - -/** - * - *

- * 璇︽儏瑙: https://redkale.org - * - * @author zhangjx - */ -public class WatchServlet extends HttpServlet { - -} +/* + * 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.watch; + +import org.redkale.net.http.HttpServlet; + +/** + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public class WatchServlet extends HttpServlet { + +} diff --git a/src/main/java/org/redkale/watch/package-info.java b/src/main/java/org/redkale/watch/package-info.java index a110591db..eb4698e86 100644 --- a/src/main/java/org/redkale/watch/package-info.java +++ b/src/main/java/org/redkale/watch/package-info.java @@ -1,4 +1,4 @@ -/** - * 鎻愪緵Redkale鏈嶅姟鐨勭洃鎺с佸姩鎬侀儴缃层佹暟鎹敹闆嗗姛鑳 - */ -package org.redkale.watch; +/** + * 鎻愪緵Redkale鏈嶅姟鐨勭洃鎺с佸姩鎬侀儴缃层佹暟鎹敹闆嗗姛鑳 + */ +package org.redkale.watch;