diff --git a/bin/apidoc.bat b/bin/apidoc.bat deleted file mode 100644 index 786c57d26..000000000 --- a/bin/apidoc.bat +++ /dev/null @@ -1,7 +0,0 @@ -@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.cmd b/bin/apidoc.cmd new file mode 100644 index 000000000..2a3b99748 --- /dev/null +++ b/bin/apidoc.cmd @@ -0,0 +1,7 @@ +@ECHO OFF + +SET APP_HOME=%~dp0 + +IF NOT EXIST "%APP_HOME%\conf\application.xml" SET APP_HOME=%~dp0.. + +java -DAPP_HOME="%APP_HOME%" -classpath "%APP_HOME%"\lib\* org.redkale.boot.Application apidoc diff --git a/bin/apidoc.sh b/bin/apidoc.sh index 60137bf28..93e8b7ab1 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` @@ -15,4 +15,4 @@ do done export CLASSPATH=$CLASSPATH:$lib echo "$APP_HOME" -java -DCMD=APIDOC -DAPP_HOME="$APP_HOME" org.redkale.boot.Application +java -DAPP_HOME="$APP_HOME" org.redkale.boot.Application apidoc diff --git a/bin/command.bat b/bin/command.bat deleted file mode 100644 index 93ad7ab8b..000000000 --- a/bin/command.bat +++ /dev/null @@ -1,7 +0,0 @@ -@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/redkale.cmd b/bin/redkale.cmd new file mode 100644 index 000000000..beaa6053e --- /dev/null +++ b/bin/redkale.cmd @@ -0,0 +1,7 @@ +@ECHO OFF + +SET APP_HOME=%~dp0 + +IF NOT EXIST "%APP_HOME%\conf\application.xml" SET APP_HOME=%~dp0.. + +java -DAPP_HOME="%APP_HOME%" -classpath "%APP_HOME%"\lib\* org.redkale.boot.Application %* diff --git a/bin/command.sh b/bin/redkale.sh similarity index 82% rename from bin/command.sh rename to bin/redkale.sh index 2e0005106..777aaa99b 100644 --- a/bin/command.sh +++ b/bin/redkale.sh @@ -20,4 +20,4 @@ done export CLASSPATH=$CLASSPATH:$lib echo "$APP_HOME" -java -DCMD=$1 -DAPP_HOME="$APP_HOME" org.redkale.boot.Application +java -DAPP_HOME="$APP_HOME" org.redkale.boot.Application $@ & diff --git a/bin/restart.bat b/bin/restart.cmd similarity index 57% rename from bin/restart.bat rename to bin/restart.cmd index 3a1247088..501970793 100644 --- a/bin/restart.bat +++ b/bin/restart.cmd @@ -4,6 +4,6 @@ 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\shutdown.cmd" -call "%APP_HOME%\bin\start.bat" \ No newline at end of file +call "%APP_HOME%\bin\start.cmd" \ No newline at end of file diff --git a/bin/shutdown.bat b/bin/shutdown.cmd similarity index 100% rename from bin/shutdown.bat rename to bin/shutdown.cmd diff --git a/bin/start.bat b/bin/start.cmd similarity index 100% rename from bin/start.bat rename to bin/start.cmd diff --git a/conf/application.xml b/conf/application.xml index f89296ce4..8932fe984 100644 --- a/conf/application.xml +++ b/conf/application.xml @@ -2,16 +2,17 @@ - - + + + + - - + - + @@ -24,8 +25,7 @@ - - + diff --git a/conf/config.properties b/conf/config.properties new file mode 100644 index 000000000..fb0d77bb4 --- /dev/null +++ b/conf/config.properties @@ -0,0 +1,2 @@ + +# \ No newline at end of file diff --git a/conf/logging.properties b/conf/logging.properties index 895431bc2..d1d5acccf 100644 --- a/conf/logging.properties +++ b/conf/logging.properties @@ -18,8 +18,8 @@ java.util.logging.FileHandler.level = FINER java.util.logging.FileHandler.limit = 10M java.util.logging.FileHandler.count = 20 java.util.logging.FileHandler.encoding = UTF-8 -java.util.logging.FileHandler.pattern = ${APP_HOME}/logs-%m/log-%d.log -java.util.logging.FileHandler.unusual = ${APP_HOME}/logs-%m/log-warnerr-%d.log +java.util.logging.FileHandler.pattern = ${APP_HOME}/logs-%tY%tm/log-%tY%tm%td.log +java.util.logging.FileHandler.unusual = ${APP_HOME}/logs-%tY%tm/log-warnerr-%tY%tm%td.log java.util.logging.FileHandler.append = true java.util.logging.ConsoleHandler.level = FINEST diff --git a/conf/persistence.xml b/conf/persistence.xml deleted file mode 100644 index e9b34ce6b..000000000 --- a/conf/persistence.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - - ALL - - - - - - - - - - diff --git a/conf/source.properties b/conf/source.properties new file mode 100644 index 000000000..aed0fe221 --- /dev/null +++ b/conf/source.properties @@ -0,0 +1,13 @@ + +############ DataSource @Resource(name="platf") ############ +#redkale.datasource[platf].url = jdbc:mysql://127.0.0.1:3306/platf?allowPublicKeyRetrieval=true&rewriteBatchedStatements=true&serverTimezone=UTC&characterEncoding=utf8 +#redkale.datasource[platf].user = root +#redkale.datasource[platf].password = 12345678 +### true: auto ddl; +#redkale.datasource[platf].table-autoddl = true + + +############ CacheSource @Resource(name="usersession") ############ +#redkale.cachesource[usersession].node[0].url = redis://127.0.0.1:6363 +#redkale.cachesource[usersession].node[0].password = 12345678 +#redkale.cachesource[usersession].node[0].db = 0 \ No newline at end of file diff --git a/my/gitrun.sh b/my/gitrun.sh new file mode 100644 index 000000000..a4747fd4c --- /dev/null +++ b/my/gitrun.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +export LC_ALL="zh_CN.UTF-8" + +rm -fr redkale + +rm -fr src +rm -fr bin +rm -fr conf + +git clone https://gitee.com/redkale/redkale.git + +cp -fr redkale/src ./ +cp -fr redkale/bin ./ +cp -fr redkale/conf ./ + +mvn clean +mvn deploy diff --git a/my/pom.xml b/my/pom.xml index 723f63a72..76815823f 100644 --- a/my/pom.xml +++ b/my/pom.xml @@ -7,19 +7,26 @@ RedkaleProject http://redkale.org redkale -- java framework - 2.5.0 + 2.7.0-SNAPSHOT UTF-8 11 11 + + 5.7.0 + 3.2.0 + 3.0.1 + 3.8.0 + 3.0.0-M5 + 3.0.0-M5 org.junit.jupiter junit-jupiter - 5.7.0 + ${junit.version} test @@ -74,7 +81,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.8.0 + ${maven-compiler-plugin.version} -parameters UTF-8 @@ -87,7 +94,7 @@ org.apache.maven.plugins maven-jar-plugin - 3.2.0 + ${maven-plugin.version} false @@ -101,7 +108,7 @@ org.apache.maven.plugins maven-gpg-plugin - 1.6 + ${maven-gpg-plugin.version} sign-artifacts @@ -116,7 +123,7 @@ org.apache.maven.plugins maven-source-plugin - 3.2.0 + ${maven-plugin.version} @@ -129,7 +136,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.2.0 + ${maven-plugin.version} @@ -142,7 +149,7 @@ org.apache.maven.plugins maven-assembly-plugin - 3.2.0 + ${maven-plugin.version} false diff --git a/my/readme.txt b/my/readme.txt index 824f3e2b7..87c2134b9 100644 --- a/my/readme.txt +++ b/my/readme.txt @@ -1 +1,9 @@ -此目录下的文件是用来发布到sonatype时使用, 不能用于工程创建。 \ No newline at end of file +此目录下的文件是用来发布到sonatype时使用, 不能用于工程创建。 + +使用gpg生成sonatype秘钥: + +1、 gpg –-gen-key +2、 gpg --keyserver keys.openpgp.org --send-keys 你的公钥(一串十六进制的数字,例:DE346FA5) + 提示: gpg: 从公钥服务器接收失败:Server indicated a failure 表示服务器不可用 + + \ No newline at end of file diff --git a/my/settings.xml b/my/settings.xml index 1a4f1b695..e336ae95f 100644 --- a/my/settings.xml +++ b/my/settings.xml @@ -20,7 +20,7 @@ - release + release - + + - + - - - - - - + - + @@ -286,6 +277,7 @@ --> + + @@ -38,7 +41,7 @@ - + diff --git a/src/main/java/META-INF/source-template.properties b/src/main/java/META-INF/source-template.properties new file mode 100644 index 000000000..abffc7ed6 --- /dev/null +++ b/src/main/java/META-INF/source-template.properties @@ -0,0 +1,50 @@ + +# CacheSource @Resource(name="usersession") +# type\u53ef\u4ee5\u4e0d\u7528\u8bbe\u7f6e\uff0c\u6846\u67b6\u4f1a\u6839\u636eurl\u5224\u65ad\u4f7f\u7528\u54ea\u4e2aCacheSource\u5b9e\u73b0\u7c7b +redkale.cachesource[usersession].type = org.redkalex.cache.redis.RedisCacheSource +# \u6700\u5927\u8fde\u63a5\u6570 +redkale.cachesource[usersession].maxconns = 16 +# \u8282\u70b9\u5730\u5740 +redkale.cachesource[usersession].node[0].url = redis://127.0.0.1:6363 +# \u8282\u70b9\u5bc6\u7801 +redkale.cachesource[usersession].node[0].password = 12345678 +# \u8282\u70b9db +redkale.cachesource[usersession].node[0].db = 0 + +#\u7b80\u5316\u5199\u6cd5: \u53ef\u4ee5\u4e0d\u7528.node[0], \u5c06\u53c2\u6570\u90fd\u5408\u5e76\u5230url\u4e2d +redkale.cachesource[usersession].url = redis://user:123456@127.0.0.1:6363?db=0 + + +# DataSource @Resource(name="platf") +# type\u53ef\u4ee5\u4e0d\u7528\u8bbe\u7f6e\uff0c\u6846\u67b6\u4f1a\u6839\u636eurl\u5224\u65ad\u4f7f\u7528\u54ea\u4e2aDataSource\u5b9e\u73b0\u7c7b\uff0c\u9ed8\u8ba4\u503c: org.redkale.source.DataJdbcSource +redkale.datasource[platf].type = org.redkale.source.DataJdbcSource +# \u662f\u5426\u5f00\u542f\u7f13\u5b58(\u6807\u8bb0\u4e3a@Cacheable\u7684Entity\u7c7b)\uff0c\u503c\u76ee\u524d\u53ea\u652f\u6301\u4e24\u79cd\uff1a ALL: \u6240\u6709\u5f00\u542f\u7f13\u5b58\u3002 NONE: \u5173\u95ed\u6240\u6709\u7f13\u5b58\uff0c \u975eNONE\u5b57\u6837\u7edf\u4e00\u89c6\u4e3aALL +redkale.datasource[platf].cachemode = ALL +# \u662f\u5426\u81ea\u52a8\u5efa\u8868\u5f53\u8868\u4e0d\u5b58\u5728\u7684\u65f6\u5019\uff0c \u76ee\u524d\u53ea\u652f\u6301mysql\u3001postgres\uff0c \u9ed8\u8ba4\u4e3afalse +redkale.datasource[platf].table-autoddl = false +# \u7528\u6237 +redkale.datasource[platf].user = root +# \u5bc6\u7801 +redkale.datasource[platf].password = 12345678 +# \u591a\u4e2aURL\u7528;\u9694\u5f00\uff0c\u5982\u5206\u5e03\u5f0fSearchSource\u9700\u8981\u914d\u591a\u4e2aURL +redkale.datasource[platf].url = jdbc:mysql://127.0.0.1:3306/platf?allowPublicKeyRetrieval=true&rewriteBatchedStatements=true&serverTimezone=UTC&characterEncoding=utf8 +# \u6700\u5927\u8fde\u63a5\u6570\uff0c\u9ed8\u8ba4\u503c\uff1aCPU\u6570 +redkale.datasource[platf].maxconns = 16 +# \u5305\u542b\u7684SQL\u6a21\u677f\uff0c\u76f8\u5f53\u4e8e\u53cd\u5411LIKE\uff0c\u4e0d\u540c\u7684JDBC\u9a71\u52a8\u7684SQL\u8bed\u53e5\u4e0d\u4e00\u6837\uff0cRedkale\u5185\u7f6e\u4e86MySQL\u7684\u8bed\u53e5 +redkale.datasource[platf].contain-sqltemplate = LOCATE(${keystr}, ${column}) > 0 +# \u5305\u542b\u7684SQL\u6a21\u677f\uff0c\u76f8\u5f53\u4e8e\u53cd\u5411LIKE\uff0c\u4e0d\u540c\u7684JDBC\u9a71\u52a8\u7684SQL\u8bed\u53e5\u4e0d\u4e00\u6837\uff0cRedkale\u5185\u7f6e\u4e86MySQL\u7684\u8bed\u53e5 +redkale.datasource[platf].notcontain-sqltemplate = LOCATE(${keystr}, ${column}) = 0 +# \u590d\u5236\u8868\u7ed3\u6784\u7684SQL\u6a21\u677f\uff0cRedkale\u5185\u7f6e\u4e86MySQL\u7684\u8bed\u53e5 +redkale.datasource[platf].tablenotexist-sqlstates = 42000;42S02 +# \u590d\u5236\u8868\u7ed3\u6784\u7684SQL\u6a21\u677f\uff0cRedkale\u5185\u7f6e\u4e86MySQL\u7684\u8bed\u53e5 +redkale.datasource[platf].tablecopy-sqltemplate = CREATE TABLE IF NOT EXISTS ${newtable} LIKE ${oldtable} + + +# DataSource \u8bfb\u5199\u5206\u79bb +redkale.datasource[platf].read.url = jdbc:mysql://127.0.0.1:3306/platf_r?allowPublicKeyRetrieval=true&rewriteBatchedStatements=true&serverTimezone=UTC&characterEncoding=utf8 +redkale.datasource[platf].read.user = root +redkale.datasource[platf].read.password = 12345678 + +redkale.datasource[platf].write.url = jdbc:mysql://127.0.0.1:3306/platf_w?allowPublicKeyRetrieval=true&rewriteBatchedStatements=true&serverTimezone=UTC&characterEncoding=utf8 +redkale.datasource[platf].write.user = root +redkale.datasource[platf].write.password = 12345678 \ No newline at end of file diff --git a/src/main/java/javax/annotation/Resource.java b/src/main/java/javax/annotation/Resource.java index 7105c2e4c..fc879c954 100644 --- a/src/main/java/javax/annotation/Resource.java +++ b/src/main/java/javax/annotation/Resource.java @@ -17,20 +17,20 @@ import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) public @interface Resource { - /** - * AuthenticationType - */ - @Deprecated - public enum AuthenticationType { - /** - * @deprecated - */ - CONTAINER, - /** - * @deprecated - */ - APPLICATION - } +// /** +// * AuthenticationType +// */ +// @Deprecated +// public enum AuthenticationType { +// /** +// * @deprecated +// */ +// CONTAINER, +// /** +// * @deprecated +// */ +// APPLICATION +// } /** * 璧勬簮鍚嶇О @@ -45,39 +45,39 @@ public @interface Resource { * @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 ""; +// +// /** +// * +// * @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/Column.java b/src/main/java/javax/persistence/Column.java index 5e3f7ec54..ba1bfc25f 100644 --- a/src/main/java/javax/persistence/Column.java +++ b/src/main/java/javax/persistence/Column.java @@ -89,11 +89,11 @@ public @interface Column { /** * for OpenAPI Specification 3 - * + * * @return String */ - String example() default ""; - + String example() default ""; + /** * (Optional) Whether the column is included in SQL INSERT * statements generated by the persistence provider. @@ -122,7 +122,12 @@ public @interface Column { /** * (Optional) The column length. (Applies only if a * string-valued column is used.) - * if type==String and length == 65535 then sqltype is text + * if type==String and length == 65535 then sqltype is TEXT
+ * if type==String and length <= 16777215 then sqltype is MEDIUMTEXT
+ * if type==String and length > 16777215 then sqltype is LONGTEXT
+ * if type==byte[] and length <= 65535 then sqltype is BLOB
+ * if type==byte[] and length <= 16777215 then sqltype is MEDIUMBLOB
+ * if type==byte[] and length > 16777215 then sqltype is LONGBLOB
* * @return int */ diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index aad1ec72a..e91bd4a50 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -39,6 +39,6 @@ module redkale { uses org.redkale.convert.ConvertProvider; uses org.redkale.source.CacheSourceProvider; uses org.redkale.source.DataSourceProvider; - uses org.redkale.util.ResourceInjectLoader; + uses org.redkale.util.ResourceAnnotationProvider; } diff --git a/src/main/java/org/redkale/boot/ApiDocsService.java b/src/main/java/org/redkale/boot/ApiDocCommand.java similarity index 72% rename from src/main/java/org/redkale/boot/ApiDocsService.java rename to src/main/java/org/redkale/boot/ApiDocCommand.java index 12a65df87..c530e9692 100644 --- a/src/main/java/org/redkale/boot/ApiDocsService.java +++ b/src/main/java/org/redkale/boot/ApiDocCommand.java @@ -10,6 +10,7 @@ import java.lang.reflect.*; import java.math.*; import java.nio.charset.StandardCharsets; import java.util.*; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.*; import java.util.logging.*; import javax.persistence.*; @@ -31,7 +32,7 @@ import org.redkale.util.*; * * @author zhangjx */ -public final class ApiDocsService { +public final class ApiDocCommand { private static final java.lang.reflect.Type TYPE_RETRESULT_OBJECT = new TypeToken>() { }.getType(); @@ -47,13 +48,26 @@ public final class ApiDocsService { private final Application app; //Application鍏ㄥ眬瀵硅薄 - public ApiDocsService(Application app) { + public ApiDocCommand(Application app) { this.app = app; } - public void run(String[] args) throws Exception { + public String command(String cmd, String[] params) throws Exception { //鏄惁璺宠繃RPC鎺ュ彛 - final boolean skipRPC = Arrays.toString(args).toLowerCase().contains("skip-rpc") && !Arrays.toString(args).toLowerCase().contains("skip-rpc=false"); + boolean skipRPC = true; + String apiHost = "http://localhost"; + + if (params != null && params.length > 0) { + for (String param : params) { + if (param == null) continue; + param = param.toLowerCase(); + if (param.startsWith("--api-skiprpc=")) { + skipRPC = "true".equalsIgnoreCase(param.substring("--api-skiprpc=".length())); + } else if (param.startsWith("--api-host=")) { + apiHost = param.substring("--api-host=".length()); + } + } + } List serverList = new ArrayList<>(); Field __prefix = HttpServlet.class.getDeclaredField("_prefix"); @@ -70,7 +84,7 @@ public final class ApiDocsService { serverList.add(map); HttpServer server = node.getServer(); map.put("address", server.getSocketAddress()); - swaggerServers.add(Utility.ofMap("url", "http://localhost:" + server.getSocketAddress().getPort())); + swaggerServers.add(Utility.ofMap("url", apiHost + ":" + server.getSocketAddress().getPort())); List> servletsList = new ArrayList<>(); map.put("servlets", servletsList); String plainContentType = server.getResponseConfig() == null ? "application/json" : server.getResponseConfig().plainContentType; @@ -200,7 +214,7 @@ public final class ApiDocsService { f.setAccessible(true); paramGenericType = (Type) f.get(servlet); } - simpleSchemaType(node.getLogger(), swaggerComponentsMap, param.type(), paramGenericType, paramSchemaMap, true); + simpleSchemaType(null, 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))); @@ -217,9 +231,10 @@ public final class ApiDocsService { 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()) { + Object example = formatExample(null, param.example(), param.type(), paramGenericType); + if (example != null) { + swaggerParamMap.put("example", example); + } else if (!param.example().isEmpty()) { swaggerParamMap.put("example", param.example()); } swaggerParamsList.add(swaggerParamMap); @@ -276,12 +291,13 @@ public final class ApiDocsService { swaggerOperatMap.put("deprecated", true); } Map respSchemaMap = new LinkedHashMap<>(); - simpleSchemaType(node.getLogger(), swaggerComponentsMap, action.result(), resultType, respSchemaMap, true); + JsonFactory returnFactory = Rest.createJsonFactory(false, method.getAnnotationsByType(RestConvert.class), method.getAnnotationsByType(RestConvertCoder.class)); + simpleSchemaType(returnFactory, 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); + Object example = formatExample(returnFactory, action.example(), action.result(), resultType); + if (example != null) respSchemaMap.put("example", example); if (!swaggerRequestBody.isEmpty()) swaggerOperatMap.put("requestBody", swaggerRequestBody); swaggerOperatMap.put("parameters", swaggerParamsList); String actiondesc = action.comment(); @@ -335,16 +351,18 @@ public final class ApiDocsService { 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(); + if (in != null) { + 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(); + } } + return "apidoc success"; } - private static void simpleSchemaType(Logger logger, Map> componentsMap, Class type, Type genericType, Map schemaMap, boolean recursive) { + private static void simpleSchemaType(JsonFactory factory, 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"); @@ -368,13 +386,13 @@ public final class ApiDocsService { schemaMap.put("type", "array"); Map sbumap = new LinkedHashMap<>(); if (type.isArray()) { - simpleSchemaType(logger, componentsMap, type.getComponentType(), type.getComponentType(), sbumap, false); + simpleSchemaType(factory, 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); + simpleSchemaType(factory, 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); + simpleSchemaType(factory, logger, componentsMap, (Class) ((ParameterizedType) subpt).getOwnerType(), subpt, sbumap, false); } else { sbumap.put("type", "object"); } @@ -383,7 +401,7 @@ public final class ApiDocsService { } schemaMap.put("items", sbumap); } else if (!type.getName().startsWith("java.") && !type.getName().startsWith("javax.")) { - String ct = simpleComponentType(logger, componentsMap, type, genericType); + String ct = simpleComponentType(factory, logger, componentsMap, type, genericType); if (ct == null) { schemaMap.put("type", "object"); } else { @@ -394,10 +412,11 @@ public final class ApiDocsService { } } - private static String simpleComponentType(Logger logger, Map> componentsMap, Class type, Type genericType) { + private static String simpleComponentType(JsonFactory factory, Logger logger, Map> componentsMap, Class type, Type genericType) { try { + Set types = new HashSet<>(); Encodeable encodeable = JsonFactory.root().loadEncoder(genericType); - String ct = componentKey(logger, componentsMap, null, encodeable, true); + String ct = componentKey(factory, logger, types, componentsMap, null, encodeable, true); if (ct == null || ct.length() == 0) return null; if (componentsMap.containsKey(ct)) return ct; Map cmap = new LinkedHashMap<>(); @@ -409,7 +428,7 @@ public final class ApiDocsService { 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); + simpleSchemaType(factory, 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); @@ -455,35 +474,41 @@ public final class ApiDocsService { } } - private static String componentKey(Logger logger, Map> componentsMap, EnMember field, Encodeable encodeable, boolean first) { + private static String componentKey(JsonFactory factory, Logger logger, Set types, Map> componentsMap, EnMember field, Encodeable encodeable, boolean first) { if (encodeable instanceof ObjectEncoder) { + if (types.contains(encodeable.getType())) return ""; + types.add(encodeable.getType()); 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); + String subsb = componentKey(factory, logger, types, 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 (field == null && encodeable.getType() instanceof Class) 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 (types.contains(member.getEncoder().getType())) continue; + types.add(member.getEncoder().getType()); if (member.getEncoder() instanceof SimpledCoder) { - simpleSchemaType(logger, componentsMap, ((SimpledCoder) member.getEncoder()).getType(), ((SimpledCoder) member.getEncoder()).getType(), new LinkedHashMap<>(), true); + simpleSchemaType(factory, 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); + simpleSchemaType(factory, 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); + String subsb = componentKey(factory, logger, types, componentsMap, member, member.getEncoder(), false); if (subsb == null) return null; + if (field == null && member.getEncoder().getType() instanceof Class) continue; if (sb.length() > 0 && subsb.length() > 0) sb.append("_"); sb.append(subsb); } else if (member.getEncoder() instanceof MapEncoder) { @@ -497,7 +522,7 @@ public final class ApiDocsService { 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); + final String sb = componentKey(factory, logger, types, componentsMap, null, subEncodeable, false); if (sb == null || sb.isEmpty()) return sb; if (field != null && field.getField() != null && field.getField().getDeclaringClass() == Sheet.class) { return sb; @@ -516,8 +541,9 @@ public final class ApiDocsService { } } - private static Object formatExample(String example, Class type, Type genericType) { - if (example == null || example.isEmpty()) return null; + private static Object formatExample(JsonFactory factory, String example, Class type, Type genericType) { + if (example != null && !example.isEmpty()) return example; + JsonFactory jsonFactory = factory == null || factory == JsonFactory.root() ? exampleFactory : factory; if (type == Flipper.class) { return new Flipper(); } else if (TYPE_RETRESULT_OBJECT.equals(genericType)) { @@ -528,8 +554,103 @@ public final class ApiDocsService { return RetResult.success(0); } else if (TYPE_RETRESULT_LONG.equals(genericType)) { return RetResult.success(0L); + } else if (type == boolean.class || type == Boolean.class) { + return true; + } else if (type.isPrimitive()) { + return 0; + } else if (type == boolean[].class || type == Boolean[].class) { + return new boolean[]{true, false}; + } else if (type == byte[].class || type == Byte[].class) { + return new byte[]{0, 0}; + } else if (type == char[].class || type == Character[].class) { + return new char[]{'a', 'b'}; + } else if (type == short[].class || type == Short[].class) { + return new short[]{0, 0}; + } else if (type == int[].class || type == Integer[].class) { + return new int[]{0, 0}; + } else if (type == long[].class || type == Long[].class) { + return new long[]{0, 0}; + } else if (type == float[].class || type == Float[].class) { + return new float[]{0, 0}; + } else if (type == double[].class || type == Double[].class) { + return new double[]{0, 0}; + } else if (Number.class.isAssignableFrom(type)) { + return 0; + } else if (CharSequence.class.isAssignableFrom(type)) { + return ""; + } else if (CompletableFuture.class.isAssignableFrom(type)) { + if (genericType instanceof ParameterizedType) { + try { + ParameterizedType pt = (ParameterizedType) genericType; + Type valType = pt.getActualTypeArguments()[0]; + return formatExample(factory, example, valType instanceof ParameterizedType ? (Class) ((ParameterizedType) valType).getRawType() : ((Class) valType), valType); + } catch (Throwable t) { + } + } + } else if (Sheet.class.isAssignableFrom(type)) { //瑕佸湪Collection鍓嶉潰 + if (genericType instanceof ParameterizedType) { + try { + ParameterizedType pt = (ParameterizedType) genericType; + Type valType = pt.getActualTypeArguments()[0]; + Class valClass = valType instanceof ParameterizedType ? (Class) ((ParameterizedType) valType).getRawType() : (Class) valType; + Object val = formatExample(factory, example, valClass, valType); + return new StringWrapper(jsonFactory.getConvert().convertTo(jsonFactory.getConvert().convertFrom(genericType, "{'rows':[" + val + "," + val + "]}"))); + } catch (Throwable t) { + } + } + } else if (type.isArray()) { + try { + Object val = formatExample(factory, example, type.getComponentType(), type.getComponentType()); + return new StringWrapper(jsonFactory.getConvert().convertTo(jsonFactory.getConvert().convertFrom(genericType, "[" + val + "," + val + "]"))); + } catch (Throwable t) { + } + } else if (Collection.class.isAssignableFrom(type)) { + if (genericType instanceof ParameterizedType) { + try { + ParameterizedType pt = (ParameterizedType) genericType; + Type valType = pt.getActualTypeArguments()[0]; + Class valClass = valType instanceof ParameterizedType ? (Class) ((ParameterizedType) valType).getRawType() : (Class) valType; + Object val = formatExample(factory, example, valClass, valType); + return new StringWrapper(jsonFactory.getConvert().convertTo(jsonFactory.getConvert().convertFrom(genericType, "[" + val + "," + val + "]"))); + } catch (Throwable t) { + } + } + } else if (type == RetResult.class) { + if (genericType instanceof ParameterizedType) { + try { + ParameterizedType pt = (ParameterizedType) genericType; + Type valType = pt.getActualTypeArguments()[0]; + Class valClass = valType instanceof ParameterizedType ? (Class) ((ParameterizedType) valType).getRawType() : (Class) valType; + Object val = formatExample(factory, example, valClass, valType); + return new StringWrapper(jsonFactory.getConvert().convertTo(jsonFactory.getConvert().convertFrom(genericType, "{'result':" + val + "}"))); + } catch (Throwable t) { + } + } + } else if (type != void.class) { + try { + Decodeable decoder = jsonFactory.loadDecoder(genericType); + if (decoder instanceof ObjectDecoder) { + StringBuilder json = new StringBuilder(); + json.append("{"); + int index = 0; + for (DeMember member : ((ObjectDecoder) decoder).getMembers()) { + if (!(member.getDecoder() instanceof ObjectDecoder)) continue; + if (index > 0) json.append(","); + json.append('"').append(member.getAttribute().field()).append("\":{}"); + index++; + } + json.append("}"); + Object val = jsonFactory.getConvert().convertFrom(genericType, json.toString()); + return new StringWrapper(jsonFactory.getConvert().convertTo(val)); + } + Creator creator = Creator.create(type); + return new StringWrapper(jsonFactory.getConvert().convertTo(creator.create())); + } catch (Throwable t) { + } } return example; } + private static final JsonFactory exampleFactory = JsonFactory.create().tiny(false); + } diff --git a/src/main/java/org/redkale/boot/Application.java b/src/main/java/org/redkale/boot/Application.java index 6376a6179..9b2ec0242 100644 --- a/src/main/java/org/redkale/boot/Application.java +++ b/src/main/java/org/redkale/boot/Application.java @@ -19,6 +19,7 @@ import java.nio.file.Path; import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.*; +import java.util.function.Consumer; import java.util.logging.*; import javax.annotation.*; import javax.net.ssl.SSLContext; @@ -33,7 +34,6 @@ import org.redkale.net.http.*; import org.redkale.net.sncp.*; import org.redkale.service.Service; import org.redkale.source.*; -import static org.redkale.source.DataSources.DATASOURCE_CONFPATH; import org.redkale.util.AnyValue.DefaultAnyValue; import org.redkale.util.*; import org.redkale.watch.*; @@ -61,7 +61,7 @@ public final class Application { public static final String RESNAME_APP_TIME = "APP_TIME"; /** - * 褰撳墠杩涚▼鐨勫悕绉帮紝 绫诲瀷锛歋tring + * 褰撳墠杩涚▼鏈嶅姟鐨勫悕绉帮紝 绫诲瀷锛歋tring */ public static final String RESNAME_APP_NAME = "APP_NAME"; @@ -74,7 +74,13 @@ public final class Application { * 褰撳墠杩涚▼鐨勯厤缃洰褰昒RI锛屽鏋滀笉鏄粷瀵硅矾寰勫垯瑙嗕负HOME鐩綍涓嬬殑鐩稿璺緞 绫诲瀷锛歋tring銆乁RI銆丗ile銆丳ath
* 鑻ラ厤缃洰褰曚笉鏄湰鍦版枃浠跺す锛 鍒橣ile銆丳ath绫诲瀷鐨勫间负null */ - public static final String RESNAME_APP_CONF = "APP_CONF"; + public static final String RESNAME_APP_CONF_DIR = "APP_CONF_DIR"; + + /** + * 褰撳墠杩涚▼鐨勯厤缃枃浠讹紝 绫诲瀷锛歋tring銆乁RI銆丗ile銆丳ath
+ * 涓鑸懡鍚嶄负: application.xml銆乤pplication.properties锛 鑻ラ厤缃枃浠朵笉鏄湰鍦版枃浠讹紝 鍒橣ile銆丳ath绫诲瀷鐨勫间负null + */ + public static final String RESNAME_APP_CONF_FILE = "APP_CONF_FILE"; /** * application.xml 鏂囦欢涓璻esources鑺傜偣鐨勫唴瀹癸紝 绫诲瀷锛 AnyValue @@ -125,6 +131,11 @@ public final class Application { */ public static final String RESNAME_SERVER_RESFACTORY = Server.RESNAME_SERVER_RESFACTORY; + private static final int UDP_CAPACITY = 1024; + + //浠呬粎鐢ㄤ簬浼犻掔粰LoggingSearchHandler浣跨敤 + static Application currentApplication; + //鏈繘绋嬭妭鐐笽D final int nodeid; @@ -138,6 +149,15 @@ public final class Application { //@since 2.3.0 final ExecutorService workExecutor; + //Source 鍘熷鐨勯厤缃祫婧 + final Properties sourceProperties = new Properties(); + + //CacheSource 閰嶇疆淇℃伅 + final Map cacheResources = new ConcurrentHashMap<>(); + + //DataSource 閰嶇疆淇℃伅 + final Map dataResources = new ConcurrentHashMap<>(); + //CacheSource 璧勬簮 final List cacheSources = new CopyOnWriteArrayList<>(); @@ -153,6 +173,12 @@ public final class Application { //缁欏鎴风浣跨敤锛屽寘鍚玈NCP瀹㈡埛绔佽嚜瀹氫箟鏁版嵁搴撳鎴风杩炴帴姹 final AsyncGroup asyncGroup; + //閰嶇疆婧愮鐞嗘帴鍙 + //@since 2.7.0 + private PropertiesAgent propertiesAgent; + + final Properties appProperties = new Properties(); + //绗笁鏂规湇鍔″彂鐜扮鐞嗘帴鍙 //@since 2.1.0 final ClusterAgent clusterAgent; @@ -204,7 +230,7 @@ public final class Application { private final long startTime = System.currentTimeMillis(); //Server鍚姩鐨勮鏁板櫒锛岀敤浜庣‘淇濇墍鏈塖erver閮藉惎鍔ㄥ畬鍚庡啀杩涜涓嬩竴姝ュ鐞 - private final CountDownLatch serversLatch; + private final CountDownLatch shutdownLatch; //鏍笴lassLoader private final RedkaleClassLoader classLoader; @@ -236,7 +262,7 @@ public final class Application { System.setProperty(RESNAME_APP_HOME, root.getCanonicalPath()); } this.home = root.getCanonicalFile(); - String confDir = System.getProperty(RESNAME_APP_CONF, "conf"); + String confDir = System.getProperty(RESNAME_APP_CONF_DIR, "conf"); if (confDir.contains("://") || confDir.startsWith("file:") || confDir.startsWith("resource:") || confDir.contains("!")) { //graalvm native-image startwith resource:META-INF this.confPath = new URI(confDir); if (confDir.startsWith("file:")) { @@ -259,11 +285,11 @@ public final class Application { this.resourceFactory.register(RESNAME_APP_ADDR, InetAddress.class, addr); this.resourceFactory.register(RESNAME_APP_ADDR, InetSocketAddress.class, this.localAddress); - this.resourceFactory.register(RESNAME_APP_CONF, URI.class, this.confPath); - this.resourceFactory.register(RESNAME_APP_CONF, String.class, this.confPath.toString()); + this.resourceFactory.register(RESNAME_APP_CONF_DIR, URI.class, this.confPath); + this.resourceFactory.register(RESNAME_APP_CONF_DIR, String.class, this.confPath.toString()); if (confFile != null) { - this.resourceFactory.register(RESNAME_APP_CONF, File.class, confFile); - this.resourceFactory.register(RESNAME_APP_CONF, Path.class, confFile.toPath()); + this.resourceFactory.register(RESNAME_APP_CONF_DIR, File.class, confFile); + this.resourceFactory.register(RESNAME_APP_CONF_DIR, Path.class, confFile.toPath()); } { @@ -322,11 +348,21 @@ public final class Application { try { final String rootpath = root.getCanonicalPath().replace('\\', '/'); InputStream fin = logConfURI.toURL().openStream(); - Properties properties = new Properties(); - properties.load(fin); + Properties properties0 = new Properties(); + properties0.load(fin); fin.close(); - properties.entrySet().forEach(x -> x.setValue(x.getValue().toString().replace("${APP_HOME}", rootpath))); - + String searchRawHandler = "java.util.logging.SearchHandler"; + String searchReadHandler = LoggingSearchHandler.class.getName(); + Properties properties = new Properties(); + properties0.entrySet().forEach(x -> { + properties.put(x.getKey().toString().replace(searchRawHandler, searchReadHandler), + x.getValue().toString() + .replace("%m", "%tY%tm").replace("%d", "%tY%tm%td") //鍏煎鏃ф椂闂存牸寮 + .replace("${" + RESNAME_APP_NAME + "}", getName()) + .replace("${" + RESNAME_APP_HOME + "}", rootpath) + .replace(searchRawHandler, searchReadHandler) + ); + }); if (properties.getProperty("java.util.logging.FileHandler.formatter") == null) { if (compileMode) { properties.setProperty("java.util.logging.FileHandler.formatter", SimpleFormatter.class.getName()); @@ -347,8 +383,14 @@ public final class Application { properties.setProperty("java.util.logging.ConsoleHandler.formatter", LoggingFileHandler.LoggingFormater.class.getName()); } } + if (properties.getProperty("java.util.logging.ConsoleHandler.denyreg") != null && !compileMode) { + final String handlers = properties.getProperty("handlers"); + if (handlers != null && handlers.contains("java.util.logging.ConsoleHandler")) { + properties.setProperty("handlers", handlers.replace("java.util.logging.ConsoleHandler", LoggingFileHandler.LoggingConsoleHandler.class.getName())); + } + } String fileHandlerPattern = properties.getProperty("java.util.logging.FileHandler.pattern"); - if (fileHandlerPattern != null && fileHandlerPattern.contains("%d")) { + if (fileHandlerPattern != null && fileHandlerPattern.contains("%")) { //甯︽棩鏈熸牸寮 final String fileHandlerClass = LoggingFileHandler.class.getName(); Properties prop = new Properties(); final String handlers = properties.getProperty("handlers"); @@ -388,10 +430,20 @@ public final class Application { Logger.getLogger(this.getClass().getSimpleName()).log(Level.WARNING, "init logger configuration error", e); } } + + if (compileMode) { + RedkaleClassLoader.putReflectionClass(java.lang.Class.class.getName()); + RedkaleClassLoader.putReflectionPublicConstructors(SimpleFormatter.class, SimpleFormatter.class.getName()); + RedkaleClassLoader.putReflectionPublicConstructors(LoggingSearchHandler.class, LoggingSearchHandler.class.getName()); + RedkaleClassLoader.putReflectionPublicConstructors(LoggingFileHandler.class, LoggingFileHandler.class.getName()); + RedkaleClassLoader.putReflectionPublicConstructors(LoggingFileHandler.LoggingFormater.class, LoggingFileHandler.LoggingFormater.class.getName()); + RedkaleClassLoader.putReflectionPublicConstructors(LoggingFileHandler.LoggingConsoleHandler.class, LoggingFileHandler.LoggingConsoleHandler.class.getName()); + RedkaleClassLoader.putReflectionPublicConstructors(LoggingFileHandler.LoggingSncpFileHandler.class, LoggingFileHandler.LoggingSncpFileHandler.class.getName()); + } } this.logger = Logger.getLogger(this.getClass().getSimpleName()); - this.serversLatch = new CountDownLatch(config.getAnyValues("server").length + 1); - logger.log(Level.INFO, "------------------------- Redkale " + Redkale.getDotedVersion() + " -------------------------"); + this.shutdownLatch = new CountDownLatch(config.getAnyValues("server").length + 1); + logger.log(Level.INFO, colorMessage(logger, 36, 1, "-------------------------------- Redkale " + Redkale.getDotedVersion() + " --------------------------------")); //------------------閰嶇疆 鑺傜偣 ------------------ final AnyValue resources = config.getAnyValue("resources"); TransportStrategy strategy = null; @@ -422,7 +474,7 @@ public final class Application { AnyValue clusterConf = resources.getAnyValue("cluster"); if (clusterConf != null) { try { - String classval = clusterConf.getValue("value"); + String classval = clusterConf.getValue("type", clusterConf.getValue("value")); //鍏煎value瀛楁 if (classval == null || classval.isEmpty()) { Iterator it = ServiceLoader.load(ClusterAgentProvider.class, classLoader).iterator(); RedkaleClassLoader.putServiceLoader(ClusterAgentProvider.class); @@ -443,9 +495,9 @@ public final class Application { cluster.setConfig(clusterConf); } } - if (cluster == null) logger.log(Level.SEVERE, "load application cluster resource, but not found name='value' value error: " + clusterConf); + if (cluster == null) logger.log(Level.SEVERE, "load application cluster resource, but not found name='type' value error: " + clusterConf); } else { - Class type = classLoader.loadClass(clusterConf.getValue("value")); + Class type = classLoader.loadClass(classval); if (!ClusterAgent.class.isAssignableFrom(type)) { logger.log(Level.SEVERE, "load application cluster resource, but not found " + ClusterAgent.class.getSimpleName() + " implements class error: " + clusterConf); } else { @@ -454,6 +506,7 @@ public final class Application { cluster.setConfig(clusterConf); } } + //姝ゆ椂涓嶈兘鎵цcluster.init锛屽洜鍐呯疆鐨勫璞″彲鑳戒緷璧朿onfig.properties閰嶇疆椤 } catch (Exception e) { logger.log(Level.SEVERE, "load application cluster resource error: " + clusterConf, e); } @@ -477,7 +530,7 @@ public final class Application { } } try { - String classval = mqConf.getValue("value"); + String classval = mqConf.getValue("type", mqConf.getValue("value")); //鍏煎value瀛楁 if (classval == null || classval.isEmpty()) { Iterator it = ServiceLoader.load(MessageAgentProvider.class, classLoader).iterator(); RedkaleClassLoader.putServiceLoader(MessageAgentProvider.class); @@ -502,6 +555,7 @@ public final class Application { mqs[i].setConfig(mqConf); } } + //姝ゆ椂涓嶈兘鎵цmq.init锛屽洜鍐呯疆鐨勫璞″彲鑳戒緷璧朿onfig.properties閰嶇疆椤 } catch (Exception e) { logger.log(Level.SEVERE, "load application mq resource error: " + mqs[i], e); } @@ -559,17 +613,1190 @@ public final class Application { } } + private static String colorMessage(Logger logger, int color, int type, String msg) { + final boolean linux = System.getProperty("os.name").toLowerCase(Locale.ENGLISH).contains("linux"); + if (linux) { //Windows PowerShell 涔熻兘姝e父鐫鑹 + boolean supported = true; + Logger l = logger; + do { + if (l.getHandlers() == null) break; + for (Handler handler : l.getHandlers()) { + if (!(handler instanceof ConsoleHandler)) { + supported = false; + break; + } + } + if (!supported) break; + } while ((l = l.getParent()) != null); + //colour 棰滆壊浠e彿锛氳儗鏅鑹蹭唬鍙(41-46)锛涘墠鏅壊浠e彿(31-36) + //type 鏍峰紡浠e彿锛0鏃狅紱1鍔犵矖锛3鏂滀綋锛4涓嬪垝绾 + //String.format("\033[%d;%dm%s\033[0m", colour, type, content) + if (supported) msg = "\033[" + color + (type > 0 ? (";" + type) : "") + "m" + msg + "\033[0m"; + } + return msg; + } + private String checkName(String name) { //涓嶈兘鍚壒娈婂瓧绗 if (name == null || 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"); + if (!((ch >= '0' && ch <= '9') || ch == '_' || ch == '.' || 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; } + public void init() throws Exception { + System.setProperty("redkale.net.transport.poolmaxconns", "100"); + System.setProperty("redkale.net.transport.pinginterval", "30"); + System.setProperty("redkale.net.transport.checkinterval", "30"); + System.setProperty("redkale.convert.tiny", "true"); + System.setProperty("redkale.convert.pool.size", "128"); + System.setProperty("redkale.convert.writer.buffer.defsize", "4096"); + + final String confDir = this.confPath.toString(); + final String homepath = this.home.getCanonicalPath(); +// String pidstr = ""; +// try { //JDK 9+ +// Class phclass = Thread.currentThread().getContextClassLoader().loadClass("java.lang.ProcessHandle"); +// Object phobj = phclass.getMethod("current").invoke(null); +// Object pid = phclass.getMethod("pid").invoke(phobj); +// pidstr = "APP_PID = " + pid + "\r\n"; +// } catch (Throwable t) { +// } + + logger.log(Level.INFO, "APP_OS = " + System.getProperty("os.name") + " " + System.getProperty("os.version") + " " + System.getProperty("os.arch") + "\r\n" + + "APP_JAVA = " + System.getProperty("java.runtime.name", System.getProperty("org.graalvm.nativeimage.kind") != null ? "Nativeimage" : "") + + " " + System.getProperty("java.runtime.version", System.getProperty("java.vendor.version", System.getProperty("java.vm.version"))) + "\r\n" //graalvm.nativeimage 妯″紡涓嬫棤 java.runtime.xxx 灞炴 + + "APP_PID = " + ProcessHandle.current().pid() + "\r\n" + + RESNAME_APP_NODEID + " = " + this.nodeid + "\r\n" + + "APP_LOADER = " + this.classLoader.getClass().getSimpleName() + "\r\n" + + RESNAME_APP_ADDR + " = " + this.localAddress.getHostString() + ":" + this.localAddress.getPort() + "\r\n" + + RESNAME_APP_HOME + " = " + homepath + "\r\n" + + RESNAME_APP_CONF_DIR + " = " + confDir.substring(confDir.indexOf('!') + 1)); + + if (!compileMode && !(classLoader instanceof RedkaleClassLoader.RedkaleCacheClassLoader)) { + String lib = config.getValue("lib", "${APP_HOME}/libs/*").trim().replace("${APP_HOME}", homepath); + lib = lib.isEmpty() ? confDir : (lib + ";" + confDir); + Server.loadLib(classLoader, logger, lib); + } + + //---------------------------- 璇诲彇 DataSource銆丆acheSource 閰嶇疆 -------------------------------------------- + if ("file".equals(this.confPath.getScheme())) { + File sourceFile = new File(new File(confPath), "source.properties"); + if (sourceFile.isFile() && sourceFile.canRead()) { + InputStream in = new FileInputStream(sourceFile); + sourceProperties.load(in); + in.close(); + } else { + //鍏煎 persistence.xml 銆愬凡搴熷純銆 + File persist = new File(new File(confPath), "persistence.xml"); + if (persist.isFile() && persist.canRead()) { + logger.log(Level.WARNING, "persistence.xml is deprecated, replaced by source.properties"); + InputStream in = new FileInputStream(persist); + dataResources.putAll(DataSources.loadAnyValuePersistenceXml(in)); + in.close(); + } + } + } else { + try { + final URI sourceURI = RedkaleClassLoader.getConfResourceAsURI(configFromCache ? null : confDir, "source.properties"); + InputStream in = sourceURI.toURL().openStream(); + sourceProperties.load(in); + in.close(); + } catch (Exception e) { //娌℃湁鏂囦欢 璺宠繃 + } + //鍏煎 persistence.xml 銆愬凡搴熷純銆 + try { + final URI xmlURI = RedkaleClassLoader.getConfResourceAsURI(configFromCache ? null : confDir, "persistence.xml"); + InputStream in = xmlURI.toURL().openStream(); + dataResources.putAll(DataSources.loadAnyValuePersistenceXml(in)); + in.close(); + logger.log(Level.WARNING, "persistence.xml is deprecated, replaced by source.properties"); + } catch (Exception e) { //娌℃湁鏂囦欢 璺宠繃 + } + } + + //------------------------------------------------------------------------ + final AnyValue resources = config.getAnyValue("resources"); + if (resources != null) { + resourceFactory.register(RESNAME_APP_GRES, AnyValue.class, resources); + final AnyValue propertiesConf = resources.getAnyValue("properties"); + if (propertiesConf != null) { + for (AnyValue prop : propertiesConf.getAnyValues("property")) { + String key = prop.getValue("name"); + String value = prop.getValue("value"); + if (key == null || value == null) continue; + appProperties.put(key, value); + value = value.replace("${APP_HOME}", homepath); + if (key.startsWith("redkale.datasource[") || key.startsWith("redkale.cachesource[")) { + sourceProperties.put(key, value); + } else if (key.startsWith("system.property.")) { + System.setProperty(key.substring("system.property.".length()), value); + } else if (key.startsWith("mimetype.property.")) { + MimeType.add(key.substring("mimetype.property.".length()), value); + } else if (key.startsWith("property.")) { + resourceFactory.register(key, value); + } else { + resourceFactory.register("property." + key, value); + } + } + String dfloads = propertiesConf.getValue("load"); + if (dfloads != null) { + for (String dfload : dfloads.split(";")) { + if (dfload.trim().isEmpty()) continue; + final URI df = RedkaleClassLoader.getConfResourceAsURI(configFromCache ? null : confDir, dfload.trim()); + if (df != null && (!"file".equals(df.getScheme()) || df.toString().contains("!") || new File(df).isFile())) { + Properties ps = new Properties(); + try { + InputStream in = df.toURL().openStream(); + ps.load(in); + in.close(); + if (logger.isLoggable(Level.FINEST)) logger.log(Level.FINEST, "load properties(" + dfload + ") size = " + ps.size()); + appProperties.putAll(ps); + ps.forEach((x, y) -> { + if (x.toString().startsWith("redkale.datasource[") || x.toString().startsWith("redkale.cachesource[")) { + sourceProperties.put(x, y.toString().replace("${APP_HOME}", homepath)); + } else { + resourceFactory.register("property." + x, y.toString().replace("${APP_HOME}", homepath)); + } + }); + } catch (Exception e) { + logger.log(Level.WARNING, "load properties(" + dfload + ") error", e); + } + } + } + } + + String agent = propertiesConf.getValue("agent"); + if (agent != null && !agent.isEmpty() && !PropertiesAgent.class.getName().equals(agent)) { + Class clazz = (Class) classLoader.loadClass(agent); + if (!PropertiesAgent.class.isAssignableFrom(clazz)) { + throw new RuntimeException("PropertiesAgent class (" + agent + ") is not " + PropertiesAgent.class.getName() + " impl class"); + } + RedkaleClassLoader.putReflectionPublicConstructors(clazz, clazz.getName()); + this.propertiesAgent = clazz.getConstructor().newInstance(); + this.resourceFactory.inject(this.propertiesAgent); + if (compileMode) { + this.propertiesAgent.compile(propertiesConf); + } else { + this.propertiesAgent.init(resourceFactory, appProperties, propertiesConf); + } + } + } + final AnyValue[] sourceConfs = resources.getAnyValues("source"); + if (sourceConfs != null && sourceConfs.length > 0) { + //鍏煎 鑺傜偣 銆愬凡搴熷純銆 + logger.log(Level.WARNING, " in application.xml is deprecated, replaced by source.properties"); + for (AnyValue sourceConf : sourceConfs) { + cacheResources.put(sourceConf.getValue("name"), sourceConf); + } + } + } + if (!sourceProperties.isEmpty()) { + AnyValue propConf = AnyValue.loadFromProperties(sourceProperties); + AnyValue redNode = propConf.getAnyValue("redkale"); + if (redNode != null) { + AnyValue cacheNode = redNode.getAnyValue("cachesource"); + if (cacheNode != null) cacheNode.forEach(null, (k, v) -> { + if (v.getValue("name") != null) logger.log(Level.WARNING, "cachesource[" + k + "].name " + v.getValue("name") + " replaced by " + k); + ((DefaultAnyValue) v).setValue("name", k); + cacheResources.put(k, v); + }); + AnyValue dataNode = redNode.getAnyValue("datasource"); + if (dataNode != null) dataNode.forEach(null, (k, v) -> { + if (v.getValue("name") != null) logger.log(Level.WARNING, "datasource[" + k + "].name " + v.getValue("name") + " replaced by " + k); + ((DefaultAnyValue) v).setValue("name", k); + dataResources.put(k, v); + }); + } + } + + this.resourceFactory.register(BsonFactory.root()); + this.resourceFactory.register(JsonFactory.root()); + this.resourceFactory.register(BsonFactory.root().getConvert()); + this.resourceFactory.register(JsonFactory.root().getConvert()); + this.resourceFactory.register("bsonconvert", Convert.class, BsonFactory.root().getConvert()); + this.resourceFactory.register("jsonconvert", Convert.class, JsonFactory.root().getConvert()); + //鍙湁WatchService鎵嶈兘鍔犺浇Application銆乄atchFactory + final Application application = this; + this.resourceFactory.register(new ResourceTypeLoader() { + + @Override + public void load(ResourceFactory rf, String srcResourceName, final Object srcObj, String resourceName, Field field, final Object attachment) { + try { + Resource res = field.getAnnotation(Resource.class); + if (res == null) return; + if (srcObj instanceof Service && Sncp.isRemote((Service) srcObj)) return; //杩滅▼妯″紡涓嶅緱娉ㄥ叆 + Class type = field.getType(); + if (type == Application.class) { + field.set(srcObj, application); + } else if (type == ResourceFactory.class) { + boolean serv = RESNAME_SERVER_RESFACTORY.equals(res.name()) || res.name().equalsIgnoreCase("server"); + field.set(srcObj, serv ? rf : (res.name().isEmpty() ? application.resourceFactory : null)); + } else if (type == TransportFactory.class) { + field.set(srcObj, application.sncpTransportFactory); + } else if (type == NodeSncpServer.class) { + NodeServer server = null; + for (NodeServer ns : application.getNodeServers()) { + if (ns.getClass() != NodeSncpServer.class) continue; + if (res.name().equals(ns.server.getName())) { + server = ns; + break; + } + } + field.set(srcObj, server); + } else if (type == NodeHttpServer.class) { + NodeServer server = null; + for (NodeServer ns : application.getNodeServers()) { + if (ns.getClass() != NodeHttpServer.class) continue; + if (res.name().equals(ns.server.getName())) { + server = ns; + break; + } + } + field.set(srcObj, server); + } else if (type == NodeWatchServer.class) { + NodeServer server = null; + for (NodeServer ns : application.getNodeServers()) { + if (ns.getClass() != NodeWatchServer.class) continue; + if (res.name().equals(ns.server.getName())) { + server = ns; + break; + } + } + field.set(srcObj, server); + } +// if (type == WatchFactory.class) { +// field.set(src, application.watchFactory); +// } + } catch (Exception e) { + logger.log(Level.SEVERE, "Resource inject error", e); + } + } + + @Override + public boolean autoNone() { + return false; + } + + }, Application.class, ResourceFactory.class, TransportFactory.class, NodeSncpServer.class, NodeHttpServer.class, NodeWatchServer.class); + + //------------------------------------- 娉ㄥ唽 java.net.http.HttpClient -------------------------------------------------------- + resourceFactory.register((ResourceFactory rf, String srcResourceName, final Object srcObj, String resourceName, Field field, final Object attachment) -> { + try { + if (field.getAnnotation(Resource.class) == null) return; + java.net.http.HttpClient.Builder builder = java.net.http.HttpClient.newBuilder(); + if (resourceName.endsWith(".1.1")) { + builder.version(HttpClient.Version.HTTP_1_1); + } else if (resourceName.endsWith(".2")) { + builder.version(HttpClient.Version.HTTP_2); + } + java.net.http.HttpClient httpClient = builder.build(); + field.set(srcObj, httpClient); + rf.inject(resourceName, httpClient, null); // 缁欏叾鍙兘鍖呭惈@Resource鐨勫瓧娈佃祴鍊; + rf.register(resourceName, java.net.http.HttpClient.class, httpClient); + } catch (Exception e) { + logger.log(Level.SEVERE, "[" + Thread.currentThread().getName() + "] java.net.http.HttpClient inject error", e); + } + }, java.net.http.HttpClient.class); + //------------------------------------- 娉ㄥ唽 HttpSimpleClient -------------------------------------------------------- + resourceFactory.register((ResourceFactory rf, String srcResourceName, final Object srcObj, String resourceName, Field field, final Object attachment) -> { + try { + if (field.getAnnotation(Resource.class) == null) return; + HttpSimpleClient httpClient = HttpSimpleClient.create(asyncGroup); + field.set(srcObj, httpClient); + rf.inject(resourceName, httpClient, null); // 缁欏叾鍙兘鍖呭惈@Resource鐨勫瓧娈佃祴鍊; + rf.register(resourceName, HttpSimpleClient.class, httpClient); + } catch (Exception e) { + logger.log(Level.SEVERE, "[" + Thread.currentThread().getName() + "] HttpClient inject error", e); + } + }, HttpSimpleClient.class); + //-------------------------------------------------------------------------- + if (this.asyncGroup != null) { + ((AsyncIOGroup) this.asyncGroup).start(); + } + if (this.clusterAgent != null) { + if (logger.isLoggable(Level.FINER)) logger.log(Level.FINER, "ClusterAgent (type = " + this.clusterAgent.getClass().getSimpleName() + ") initing"); + long s = System.currentTimeMillis(); + if (this.clusterAgent instanceof CacheClusterAgent) { + String sourceName = ((CacheClusterAgent) clusterAgent).getSourceName(); //蹇呴』鍦╥nject鍓嶈皟鐢紝闇瑕佽祴鍊糝esourcable.name + loadCacheSource(sourceName, false); + } + clusterAgent.setTransportFactory(this.sncpTransportFactory); + this.resourceFactory.inject(clusterAgent); + clusterAgent.init(this.resourceFactory, clusterAgent.getConfig()); + this.resourceFactory.register(ClusterAgent.class, clusterAgent); + logger.info("ClusterAgent (type = " + this.clusterAgent.getClass().getSimpleName() + ") init in " + (System.currentTimeMillis() - s) + " ms"); + } + if (this.messageAgents != null) { + if (logger.isLoggable(Level.FINER)) logger.log(Level.FINER, "MessageAgent initing"); + long s = System.currentTimeMillis(); + for (MessageAgent agent : this.messageAgents) { + this.resourceFactory.inject(agent); + agent.init(this.resourceFactory, agent.getConfig()); + this.resourceFactory.register(agent.getName(), MessageAgent.class, agent); + this.resourceFactory.register(agent.getName(), HttpMessageClient.class, agent.getHttpMessageClient()); + //this.resourceFactory.register(agent.getName(), SncpMessageClient.class, agent.getSncpMessageClient()); //涓嶉渶瑕佺粰寮鍙戣呬娇鐢 + } + logger.info("MessageAgent init in " + (System.currentTimeMillis() - s) + " ms"); + } + //------------------------------------- 娉ㄥ唽 HttpMessageClient -------------------------------------------------------- + resourceFactory.register((ResourceFactory rf, String srcResourceName, final Object srcObj, String resourceName, Field field, final Object attachment) -> { + try { + if (field.getAnnotation(Resource.class) == null) return; + if (clusterAgent == null) { + HttpMessageClient messageClient = new HttpMessageLocalClient(application, resourceName); + field.set(srcObj, messageClient); + rf.inject(resourceName, messageClient, null); // 缁欏叾鍙兘鍖呭惈@Resource鐨勫瓧娈佃祴鍊; + rf.register(resourceName, HttpMessageClient.class, messageClient); + return; + } + HttpMessageClient messageClient = new HttpMessageClusterClient(application, resourceName, clusterAgent); + field.set(srcObj, messageClient); + rf.inject(resourceName, messageClient, null); // 缁欏叾鍙兘鍖呭惈@Resource鐨勫瓧娈佃祴鍊; + rf.register(resourceName, HttpMessageClient.class, messageClient); + } catch (Exception e) { + logger.log(Level.SEVERE, "[" + Thread.currentThread().getName() + "] HttpMessageClient inject error", e); + } + }, HttpMessageClient.class); + initResources(); + } + + CacheSource loadCacheSource(final String sourceName, boolean autoMemory) { + CacheSource old = resourceFactory.find(sourceName, CacheSource.class); + if (old != null) return old; + final AnyValue sourceConf = cacheResources.get(sourceName); + if (sourceConf == null) { + if (!autoMemory) return null; + CacheSource source = new CacheMemorySource(sourceName); + cacheSources.add(source); + resourceFactory.register(sourceName, CacheSource.class, source); + resourceFactory.inject(sourceName, source); + if (!compileMode && source instanceof Service) ((Service) source).init(sourceConf); + logger.info("[" + Thread.currentThread().getName() + "] Load CacheSource resourceName = " + sourceName + ", source = " + source); + return source; + } + String classval = sourceConf.getValue("type"); + try { + Class sourceType = null; + if (classval == null || classval.isEmpty()) { + RedkaleClassLoader.putServiceLoader(CacheSourceProvider.class); + List providers = new ArrayList<>(); + Iterator it = ServiceLoader.load(CacheSourceProvider.class, serverClassLoader).iterator(); + while (it.hasNext()) { + CacheSourceProvider s = it.next(); + if (s != null) RedkaleClassLoader.putReflectionPublicConstructors(s.getClass(), s.getClass().getName()); + if (s != null && s.acceptsConf(sourceConf)) { + providers.add(s); + } + } + 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 (CacheSourceProvider provider : providers) { + sourceType = provider.sourceClass(); + if (sourceType != null) break; + } + if (sourceType == null) { + if (CacheMemorySource.acceptsConf(sourceConf)) { + sourceType = CacheMemorySource.class; + } + } + } else { + sourceType = serverClassLoader.loadClass(classval); + } + if (sourceType == null) throw new RuntimeException("Not found CacheSourceProvider for config=" + sourceConf); + + RedkaleClassLoader.putReflectionPublicConstructors(sourceType, sourceType.getName()); + CacheSource source = sourceType == CacheMemorySource.class ? new CacheMemorySource(sourceName) : (CacheSource) sourceType.getConstructor().newInstance(); + cacheSources.add(source); + resourceFactory.register(sourceName, source); + resourceFactory.inject(sourceName, source); + if (!compileMode && source instanceof Service) ((Service) source).init(sourceConf); + logger.info("[" + Thread.currentThread().getName() + "] Load CacheSource resourceName = " + sourceName + ", source = " + source); + return source; + } catch (Exception e) { + logger.log(Level.SEVERE, "load application CaheSource error: " + sourceConf, e); + } + return null; + } + + DataSource loadDataSource(final String sourceName, boolean autoMemory) { + DataSource old = resourceFactory.find(sourceName, DataSource.class); + if (old != null) return old; + final AnyValue sourceConf = dataResources.get(sourceName); + if (sourceConf == null) { + if (!autoMemory) return null; + DataSource source = new DataMemorySource(sourceName); + dataSources.add(source); + resourceFactory.register(sourceName, DataSource.class, source); + resourceFactory.inject(sourceName, source); + if (!compileMode && source instanceof Service) ((Service) source).init(sourceConf); + logger.info("[" + Thread.currentThread().getName() + "] Load DataSource resourceName = " + sourceName + ", source = " + source); + return source; + } + String classval = sourceConf.getValue("type"); + try { + Class sourceType = null; + if (classval == null || classval.isEmpty()) { + if (DataJdbcSource.acceptsConf(sourceConf)) { + sourceType = DataJdbcSource.class; + } else { + RedkaleClassLoader.putServiceLoader(DataSourceProvider.class); + List providers = new ArrayList<>(); + Iterator it = ServiceLoader.load(DataSourceProvider.class, serverClassLoader).iterator(); + while (it.hasNext()) { + DataSourceProvider s = it.next(); + if (s != null) RedkaleClassLoader.putReflectionPublicConstructors(s.getClass(), s.getClass().getName()); + if (s != null && s.acceptsConf(sourceConf)) { + providers.add(s); + } + } + 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) { + sourceType = provider.sourceClass(); + if (sourceType != null) break; + } + if (sourceType == null) { + if (DataMemorySource.acceptsConf(sourceConf)) { + sourceType = DataMemorySource.class; + } + } + } + } else { + sourceType = serverClassLoader.loadClass(classval); + } + if (sourceType == null) throw new RuntimeException("Not found DataSourceProvider for config=" + sourceConf); + + RedkaleClassLoader.putReflectionPublicConstructors(sourceType, sourceType.getName()); + DataSource source = sourceType == DataMemorySource.class ? new DataMemorySource(sourceName) : (DataSource) sourceType.getConstructor().newInstance(); + dataSources.add(source); + if (sourceType == DataMemorySource.class && DataMemorySource.isSearchType(sourceConf)) { + resourceFactory.register(sourceName, SearchSource.class, source); + } else { + resourceFactory.register(sourceName, source); + } + resourceFactory.inject(sourceName, source); + if (!compileMode && source instanceof Service) ((Service) source).init(sourceConf); + logger.info("[" + Thread.currentThread().getName() + "] Load DataSource resourceName = " + sourceName + ", source = " + source); + return source; + } catch (RuntimeException ex) { + throw ex; + } catch (Exception e) { + logger.log(Level.SEVERE, "load application DataSource error: " + sourceConf, e); + } + return null; + } + + private void initResources() throws Exception { + //------------------------------------------------------------------------- + final AnyValue resources = config.getAnyValue("resources"); + if (resources != null) { + //------------------------------------------------------------------------ + for (AnyValue conf : resources.getAnyValues("group")) { + final String group = conf.getValue("name", ""); + final String protocol = conf.getValue("protocol", Transport.DEFAULT_NETPROTOCOL).toUpperCase(); + if (!"TCP".equalsIgnoreCase(protocol) && !"UDP".equalsIgnoreCase(protocol)) { + throw new RuntimeException("Not supported Transport Protocol " + conf.getValue("protocol")); + } + TransportGroupInfo ginfo = new TransportGroupInfo(group, protocol, new LinkedHashSet<>()); + for (AnyValue node : conf.getAnyValues("node")) { + final InetSocketAddress addr = new InetSocketAddress(node.getValue("addr"), node.getIntValue("port")); + ginfo.putAddress(addr); + } + sncpTransportFactory.addGroupInfo(ginfo); + } + for (AnyValue conf : resources.getAnyValues("listener")) { + final String listenClass = conf.getValue("value", ""); + if (listenClass.isEmpty()) continue; + Class clazz = classLoader.loadClass(listenClass); + if (!ApplicationListener.class.isAssignableFrom(clazz)) continue; + RedkaleClassLoader.putReflectionDeclaredConstructors(clazz, clazz.getName()); + @SuppressWarnings("unchecked") + ApplicationListener listener = (ApplicationListener) clazz.getDeclaredConstructor().newInstance(); + resourceFactory.inject(listener); + listener.init(config); + this.listeners.add(listener); + } + } + //------------------------------------------------------------------------ + } + + private void startSelfServer() throws Exception { + final Application application = this; + new Thread() { + { + setName("Redkale-Application-SelfServer-Thread"); + } + + @Override + public void run() { + try { + DatagramChannel channel = DatagramChannel.open(); + channel.configureBlocking(true); + channel.socket().setSoTimeout(3000); + channel.bind(new InetSocketAddress("127.0.0.1", config.getIntValue("port"))); + if (!singletonMode) signalShutdownHandle(); + boolean loop = true; + final ByteBuffer buffer = ByteBuffer.allocateDirect(UDP_CAPACITY); + while (loop) { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + SocketAddress address = readUdpData(channel, buffer, out); + String[] args = JsonConvert.root().convertFrom(String[].class, out.toString(StandardCharsets.UTF_8)); + final String cmd = args[0]; + String[] params = args.length == 1 ? new String[0] : Arrays.copyOfRange(args, 1, args.length); + //鎺ユ敹鍒板懡浠ゅ繀椤昏鏈夊洖搴, 鏃犵粨鏋滆緭鍑哄垯鍥炲簲鍥炶溅鎹㈣绗 + if ("SHUTDOWN".equalsIgnoreCase(cmd)) { + try { + long s = System.currentTimeMillis(); + logger.info(application.getClass().getSimpleName() + " shutdowning"); + application.shutdown(); + sendUdpData(channel, address, buffer, "--- shutdown finish ---".getBytes(StandardCharsets.UTF_8)); + long e = System.currentTimeMillis() - s; + logger.info(application.getClass().getSimpleName() + " shutdown in " + e + " ms"); + channel.close(); + } catch (Exception ex) { + logger.log(Level.INFO, "shutdown fail", ex); + sendUdpData(channel, address, buffer, "shutdown fail".getBytes(StandardCharsets.UTF_8)); + } finally { + loop = false; + application.shutdownLatch.countDown(); + } + } else if ("APIDOC".equalsIgnoreCase(cmd)) { + try { + String rs = new ApiDocCommand(application).command(cmd, params); + if (rs == null || rs.isEmpty()) rs = "\r\n"; + sendUdpData(channel, address, buffer, rs.getBytes(StandardCharsets.UTF_8)); + } catch (Exception ex) { + sendUdpData(channel, address, buffer, "apidoc fail".getBytes(StandardCharsets.UTF_8)); + } + } else { + long s = System.currentTimeMillis(); + logger.info(application.getClass().getSimpleName() + " command " + cmd); + List rs = application.command(cmd, params); + StringBuilder sb = new StringBuilder(); + if (rs != null) { + for (Object o : rs) { + if (o instanceof CharSequence) { + sb.append(o).append("\r\n"); + } else { + sb.append(JsonConvert.root().convertTo(o)).append("\r\n"); + } + } + } + if (sb.length() == 0) sb.append("\r\n"); + sendUdpData(channel, address, buffer, sb.toString().getBytes(StandardCharsets.UTF_8)); + long e = System.currentTimeMillis() - s; + logger.info(application.getClass().getSimpleName() + " command in " + e + " ms"); + } + } + } catch (Exception e) { + logger.log(Level.INFO, "Control fail", e); + System.exit(1); + } + } + }.start(); + } + + //鏁版嵁鍖呭墠4涓瓧鑺備负鏁版嵁鍐呭鐨勯暱搴 + private static void sendUdpData(final DatagramChannel channel, SocketAddress dest, ByteBuffer buffer, byte[] bytes) throws IOException { + buffer.clear(); + int count = (bytes.length + 4) / UDP_CAPACITY + ((bytes.length + 4) % UDP_CAPACITY > 0 ? 1 : 0); + int start = 0; + for (int i = 0; i < count; i++) { + if (start == 0) buffer.putInt(bytes.length); + int len = Math.min(buffer.remaining(), bytes.length - start); + buffer.put(bytes, start, len); + buffer.flip(); + boolean first = true; + while (buffer.hasRemaining()) { + if (!first) Utility.sleep(10); + if (dest == null) { + channel.write(buffer); + } else { + channel.send(buffer, dest); + } + first = false; + } + start += len; + buffer.clear(); + } + } + + private static SocketAddress readUdpData(final DatagramChannel channel, ByteBuffer buffer, ByteArrayOutputStream out) throws IOException { + out.reset(); + buffer.clear(); + SocketAddress src = null; + if (channel.isConnected()) { + channel.read(buffer); + while (buffer.position() < 4) channel.read(buffer); + } else { + src = channel.receive(buffer); + while (buffer.position() < 4) src = channel.receive(buffer); + } + buffer.flip(); + final int dataSize = buffer.getInt(); + while (buffer.hasRemaining()) { + out.write(buffer.get()); + } + while (out.size() < dataSize) { + buffer.clear(); + channel.receive(buffer); + buffer.flip(); + while (buffer.hasRemaining()) { + out.write(buffer.get()); + } + } + return src; + } + + private static void sendCommand(Logger logger, int port, String cmd, String[] params) throws Exception { + final DatagramChannel channel = DatagramChannel.open(); + channel.configureBlocking(true); + channel.socket().setSoTimeout(3000); + SocketAddress dest = new InetSocketAddress("127.0.0.1", port); + channel.connect(dest); + //鍛戒护鍜屽弬鏁板悎鎴愪竴涓暟缁 + String[] args = new String[1 + (params == null ? 0 : params.length)]; + args[0] = cmd; + if (params != null) System.arraycopy(params, 0, args, 1, params.length); + final ByteBuffer buffer = ByteBuffer.allocateDirect(UDP_CAPACITY); + try { + sendUdpData(channel, dest, buffer, JsonConvert.root().convertToBytes(args)); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + readUdpData(channel, buffer, out); + channel.close(); + String rs = out.toString(StandardCharsets.UTF_8).trim(); + if (logger != null) logger.info("Send: " + cmd + ", Reply: " + rs); + System.out.println(rs); + } catch (Exception e) { + if (e instanceof PortUnreachableException) { + if ("APIDOC".equalsIgnoreCase(cmd)) { + final Application application = new Application(false, true, Application.loadAppConfig()); + application.init(); + application.start(); + String rs = new ApiDocCommand(application).command(cmd, params); + application.shutdown(); + if (logger != null) logger.info(rs); + System.out.println(rs); + return; + } + //if ("SHUTDOWN".equalsIgnoreCase(cmd)) { + // System.out.println("--- application not running ---"); + //} else { + System.err.println("--- application not running ---"); + //} + return; + } + throw e; + } + } + + /** + * 鍚姩 + * + * @throws Exception 寮傚父 + */ + public void start() throws Exception { + if (!singletonMode && !compileMode && this.clusterAgent != null) { + this.clusterAgent.register(this); + } + final AnyValue[] entrys = config.getAnyValues("server"); + CountDownLatch timecd = new CountDownLatch(entrys.length); + final List sncps = new ArrayList<>(); + final List others = new ArrayList<>(); + final List watchs = new ArrayList<>(); + for (final AnyValue entry : entrys) { + if (entry.getValue("protocol", "").toUpperCase().startsWith("SNCP")) { + sncps.add(entry); + } else if (entry.getValue("protocol", "").toUpperCase().startsWith("WATCH")) { + watchs.add(entry); + } else { + others.add(entry); + } + } + if (watchs.size() > 1) throw new RuntimeException("Found one more WATCH Server"); + this.watching = !watchs.isEmpty(); + + runServers(timecd, sncps); //蹇呴』纭繚SNCP鏈嶅姟閮藉惎鍔ㄥ悗鍐嶅惎鍔ㄥ叾浠栨湇鍔 + runServers(timecd, others); + runServers(timecd, watchs); //蹇呴』鍦ㄦ墍鏈夋湇鍔¢兘鍚姩鍚庡啀鍚姩WATCH鏈嶅姟 + timecd.await(); + if (this.clusterAgent != null) this.clusterAgent.start(); + if (this.messageAgents != null) { + if (logger.isLoggable(Level.FINER)) logger.log(Level.FINER, "MessageAgent starting"); + long s = System.currentTimeMillis(); + final StringBuffer sb = new StringBuffer(); + Set names = new HashSet<>(); + for (MessageAgent agent : this.messageAgents) { + names.add(agent.getName()); + Map map = agent.start().join(); + AtomicInteger maxlen = new AtomicInteger(); + map.keySet().forEach(str -> { + if (str.length() > maxlen.get()) maxlen.set(str.length()); + }); + new TreeMap<>(map).forEach((topic, ms) -> sb.append("MessageConsumer(topic=").append(alignString(topic, maxlen.get())).append(") init and start in ").append(ms).append(" ms\r\n") + ); + } + if (sb.length() > 0) logger.info(sb.toString().trim()); + logger.info("MessageAgent(names=" + JsonConvert.root().convertTo(names) + ") start in " + (System.currentTimeMillis() - s) + " ms"); + } + long intms = System.currentTimeMillis() - startTime; + String ms = String.valueOf(intms); + int repeat = ms.length() > 7 ? 0 : (7 - ms.length()) / 2; + logger.info(colorMessage(logger, 36, 1, "-".repeat(repeat) + "------------------------ Redkale started in " + ms + " ms " + (ms.length() / 2 == 0 ? " " : "") + "-".repeat(repeat) + "------------------------") + "\r\n"); + LoggingFileHandler.traceflag = true; + + for (ApplicationListener listener : this.listeners) { + listener.postStart(this); + } + if (!singletonMode && !compileMode) this.shutdownLatch.await(); + } + + private static String alignString(String value, int maxlen) { + StringBuilder sb = new StringBuilder(maxlen); + sb.append(value); + for (int i = 0; i < maxlen - value.length(); i++) { + sb.append(' '); + } + return sb.toString(); + } + + //浣跨敤浜唍ohup鎴栦娇鐢ㄤ簡鍚庡彴&锛孯untime.getRuntime().addShutdownHook澶辨晥 + private void signalShutdownHandle() { + Consumer> signalShutdownConsumer = Utility.signalShutdownConsumer(); + if (signalShutdownConsumer == null) return; + signalShutdownConsumer.accept(sig -> { + try { + long s = System.currentTimeMillis(); + logger.info(Application.this.getClass().getSimpleName() + " shutdowning " + sig); + shutdown(); + long e = System.currentTimeMillis() - s; + logger.info(Application.this.getClass().getSimpleName() + " shutdown in " + e + " ms"); + } catch (Exception ex) { + logger.log(Level.INFO, "shutdown fail", ex); + } finally { + shutdownLatch.countDown(); + } + }); + } + + @SuppressWarnings("unchecked") + private void runServers(CountDownLatch timecd, final List serconfs) throws Exception { + this.servicecdl = new CountDownLatch(serconfs.size()); + CountDownLatch sercdl = new CountDownLatch(serconfs.size()); + final AtomicBoolean inited = new AtomicBoolean(false); + final Map> nodeClasses = new HashMap<>(); + for (final AnyValue serconf : serconfs) { + Thread thread = new Thread() { + { + setName("Redkale-" + serconf.getValue("protocol", "Server").toUpperCase().replaceFirst("\\..+", "") + ":" + serconf.getIntValue("port") + "-Thread"); + this.setDaemon(true); + } + + @Override + public void run() { + try { + //Thread ctd = Thread.currentThread(); + //ctd.setContextClassLoader(new URLClassLoader(new URL[0], ctd.getContextClassLoader())); + final String protocol = serconf.getValue("protocol", "").replaceFirst("\\..+", "").toUpperCase(); + NodeServer server = null; + if ("SNCP".equals(protocol)) { + server = NodeSncpServer.createNodeServer(Application.this, serconf); + } else if ("WATCH".equalsIgnoreCase(protocol)) { + DefaultAnyValue serconf2 = (DefaultAnyValue) serconf; + DefaultAnyValue rest = (DefaultAnyValue) serconf2.getAnyValue("rest"); + if (rest == null) { + rest = new DefaultAnyValue(); + serconf2.addValue("rest", rest); + } + rest.setValue("base", WatchServlet.class.getName()); + server = new NodeWatchServer(Application.this, serconf); + } else if ("HTTP".equalsIgnoreCase(protocol)) { + server = new NodeHttpServer(Application.this, serconf); + } else { + if (!inited.get()) { + synchronized (nodeClasses) { + if (!inited.getAndSet(true)) { //鍔犺浇鑷畾涔夌殑鍗忚锛屽锛歋OCKS + ClassFilter profilter = new ClassFilter(classLoader, NodeProtocol.class, NodeServer.class, (Class[]) null); + ClassFilter.Loader.load(home, classLoader, ((excludelibs != null ? (excludelibs + ";") : "") + serconf.getValue("excludelibs", "")).split(";"), profilter); + final Set> entrys = profilter.getFilterEntrys(); + for (FilterEntry entry : entrys) { + final Class type = entry.getType(); + NodeProtocol pros = type.getAnnotation(NodeProtocol.class); + String p = pros.value().toUpperCase(); + if ("SNCP".equals(p) || "HTTP".equals(p)) continue; + final Class old = nodeClasses.get(p); + if (old != null && old != type) { + throw new RuntimeException("Protocol(" + p + ") had NodeServer-Class(" + old.getName() + ") but repeat NodeServer-Class(" + type.getName() + ")"); + } + nodeClasses.put(p, type); + } + } + } + } + Class nodeClass = nodeClasses.get(protocol); + if (nodeClass != null) server = NodeServer.create(nodeClass, Application.this, serconf); + } + if (server == null) { + logger.log(Level.SEVERE, "Not found Server Class for protocol({0})", serconf.getValue("protocol")); + System.exit(0); + } + server.init(serconf); + if (!singletonMode && !compileMode) { + server.start(); + } else if (compileMode) { + server.getServer().getPrepareServlet().init(server.getServer().getContext(), serconf); + } + servers.add(server); + timecd.countDown(); + sercdl.countDown(); + } catch (Exception ex) { + logger.log(Level.WARNING, serconf + " runServers error", ex); + Application.this.shutdownLatch.countDown(); + } + } + }; + thread.start(); + } + sercdl.await(); + } + + /** + * 瀹炰緥鍖栧崟涓猄ervice + * + * @param 娉涘瀷 + * @param serviceClass 鎸囧畾鐨剆ervice绫 + * @param extServiceClasses 闇瑕佹帓闄ょ殑service绫 + * + * @return Service瀵硅薄 + * @throws Exception 寮傚父 + */ + public static T singleton(Class serviceClass, Class... extServiceClasses) throws Exception { + return singleton("", serviceClass, extServiceClasses); + } + + /** + * 瀹炰緥鍖栧崟涓猄ervice + * + * @param 娉涘瀷 + * @param name Service鐨勮祫婧愬悕 + * @param serviceClass 鎸囧畾鐨剆ervice绫 + * @param extServiceClasses 闇瑕佹帓闄ょ殑service绫 + * + * @return Service瀵硅薄 + * @throws Exception 寮傚父 + */ + public static T singleton(String name, Class serviceClass, Class... extServiceClasses) throws Exception { + if (serviceClass == null) throw new IllegalArgumentException("serviceClass is null"); + final Application application = Application.create(true); + System.setProperty("red" + "kale.singleton.serviceclass", serviceClass.getName()); + if (extServiceClasses != null && extServiceClasses.length > 0) { + StringBuilder sb = new StringBuilder(); + for (Class clazz : extServiceClasses) { + if (sb.length() > 0) sb.append(','); + sb.append(clazz.getName()); + } + System.setProperty("red" + "kale.singleton.extserviceclasses", sb.toString()); + } + application.init(); + application.start(); + for (NodeServer server : application.servers) { + T service = server.resourceFactory.find(name, serviceClass); + if (service != null) return service; + } + if (Modifier.isAbstract(serviceClass.getModifiers())) throw new IllegalArgumentException("abstract class not allowed"); + if (serviceClass.isInterface()) throw new IllegalArgumentException("interface class not allowed"); + throw new IllegalArgumentException(serviceClass.getName() + " maybe have zero not-final public method"); + } + + public static Application create(final boolean singleton) throws IOException { + return new Application(singleton, false, loadAppConfig()); + } + + static AnyValue loadAppConfig() throws IOException { + final String home = new File(System.getProperty(RESNAME_APP_HOME, "")).getCanonicalPath().replace('\\', '/'); + System.setProperty(RESNAME_APP_HOME, home); + String sysConfFile = System.getProperty(RESNAME_APP_CONF_FILE); + if (sysConfFile != null) { + String text; + if (sysConfFile.contains("://")) { + text = Utility.readThenClose(URI.create(sysConfFile).toURL().openStream()); + } else { + File f = new File(sysConfFile); + if (f.isFile() && f.canRead()) { + text = Utility.readThenClose(new FileInputStream(f)); + } else { + throw new IOException("Read application conf file (" + sysConfFile + ") error "); + } + } + return text.trim().startsWith("<") ? AnyValue.loadFromXml(text, (k, v) -> v.replace("${APP_HOME}", home)).getAnyValue("application") : AnyValue.loadFromProperties(text).getAnyValue("redkale"); + } + String confDir = System.getProperty(RESNAME_APP_CONF_DIR, "conf"); + URI appConfFile; + boolean fromcache = false; + if (confDir.contains("://")) { //jar鍐呴儴璧勬簮 + appConfFile = URI.create(confDir + (confDir.endsWith("/") ? "" : "/") + "application.xml"); + try { + appConfFile.toURL().openStream().close(); + } catch (IOException e) { //娌℃湁application.xml灏卞皾璇曡application.properties + appConfFile = URI.create(confDir + (confDir.endsWith("/") ? "" : "/") + "application.properties"); + } + } else if (confDir.charAt(0) == '/' || confDir.indexOf(':') > 0) { //缁濆璺緞 + File f = new File(confDir, "application.xml"); + if (f.isFile() && f.canRead()) { + appConfFile = f.toURI(); + confDir = f.getParentFile().getCanonicalPath(); + } else { + f = new File(confDir, "application.properties"); + if (f.isFile() && f.canRead()) { + appConfFile = f.toURI(); + confDir = f.getParentFile().getCanonicalPath(); + } else { + appConfFile = RedkaleClassLoader.getConfResourceAsURI(null, "application.xml"); //涓嶈兘浼燾onfDir + try { + appConfFile.toURL().openStream().close(); + } catch (IOException e) { //娌℃湁application.xml灏卞皾璇曡application.properties + appConfFile = RedkaleClassLoader.getConfResourceAsURI(null, "application.properties"); + } + confDir = appConfFile.toString().replace("/application.xml", "").replace("/application.properties", ""); + fromcache = true; + } + } + } else { //鐩稿璺緞 + File f = new File(new File(home, confDir), "application.xml"); + if (f.isFile() && f.canRead()) { + appConfFile = f.toURI(); + confDir = f.getParentFile().getCanonicalPath(); + } else { + f = new File(new File(home, confDir), "application.properties"); + if (f.isFile() && f.canRead()) { + appConfFile = f.toURI(); + confDir = f.getParentFile().getCanonicalPath(); + } else { + appConfFile = RedkaleClassLoader.getConfResourceAsURI(null, "application.xml"); //涓嶈兘浼燾onfDir + try { + appConfFile.toURL().openStream().close(); + } catch (IOException e) { //娌℃湁application.xml灏卞皾璇曡application.properties + appConfFile = RedkaleClassLoader.getConfResourceAsURI(null, "application.properties"); + } + confDir = appConfFile.toString().replace("/application.xml", "").replace("/application.properties", ""); + fromcache = true; + } + } + } + System.setProperty(RESNAME_APP_CONF_DIR, confDir); + String text = Utility.readThenClose(appConfFile.toURL().openStream()); + AnyValue conf = text.trim().startsWith("<") ? AnyValue.loadFromXml(text, (k, v) -> v.replace("${APP_HOME}", home)).getAnyValue("application") : AnyValue.loadFromProperties(text).getAnyValue("redkale"); + if (fromcache) ((DefaultAnyValue) conf).addValue("[config-from-cache]", "true"); + return conf; + } + + public static void main(String[] args) throws Exception { + Utility.midnight(); //鍏堝垵濮嬪寲涓涓婾tility + Thread.currentThread().setName("Redkale-Application-Main-Thread"); + //杩愯涓荤▼搴 + { + String cmd = System.getProperty("cmd", System.getProperty("CMD")); + String[] params = args; + if (args != null && args.length > 0) { + for (int i = 0; i < args.length; i++) { + if (args[i] != null && args[i].toLowerCase().startsWith("--conf-file=")) { + System.setProperty(RESNAME_APP_CONF_FILE, args[i].substring("--conf-file=".length())); + String[] newargs = new String[args.length - 1]; + System.arraycopy(args, 0, newargs, 0, i); + System.arraycopy(args, i + 1, newargs, i, args.length - 1 - i); + args = newargs; + break; + } + } + if (cmd == null) { + for (int i = 0; i < args.length; i++) { + if (args[i] != null && !args[i].startsWith("-")) { //闈-寮澶寸殑绗竴涓涓哄懡浠ゅ彿 + cmd = args[i]; + if ("start".equalsIgnoreCase(cmd) || "startup".equalsIgnoreCase(cmd)) { + cmd = null; + } + params = new String[args.length - 1]; + System.arraycopy(args, 0, params, 0, i); + System.arraycopy(args, i + 1, params, i, args.length - 1 - i); + break; + } + } + } + if (cmd == null) { + if (args.length == 1 && ("--help".equalsIgnoreCase(args[0]) || "-h".equalsIgnoreCase(args[0]))) { + cmd = args[0]; + } + } + } + if (cmd != null) { + if ("stop".equalsIgnoreCase(cmd)) { + cmd = "shutdown"; + } + if ("help".equalsIgnoreCase(cmd) || "--help".equalsIgnoreCase(cmd) || "-h".equalsIgnoreCase(cmd)) { + System.out.println(generateHelp()); + return; + } + boolean restart = "restart".equalsIgnoreCase(cmd); + AnyValue config = loadAppConfig(); + Application.sendCommand(null, config.getIntValue("port"), restart ? "SHUTDOWN" : cmd, params); + if (!restart) return; + } + } + //PrepareCompiler.main(args); //娴嬭瘯浠g爜 + + final Application application = Application.create(false); + currentApplication = application; + application.init(); + application.startSelfServer(); + try { + for (ApplicationListener listener : application.listeners) { + listener.preStart(application); + } + application.start(); + } catch (Exception e) { + application.logger.log(Level.SEVERE, "Application start error", e); + System.exit(1); + } + System.exit(0); //蹇呴』瑕佹湁 + } + + private static String generateHelp() { + return "" + + "Usage: redkale [command] [arguments]\r\n" + + "Command: \r\n" + + " start, startup start one process\r\n" + + " --conf-file=[file] application config file, eg. application.xml銆乤pplication.properties\r\n" + + " shutdown, stop shutdown one process\r\n" + + " --conf-file=[file] application config file, eg. application.xml銆乤pplication.properties\r\n" + + " restart restart one process\r\n" + + " --conf-file=[file] application config file, eg. application.xml銆乤pplication.properties\r\n" + + " apidoc generate apidoc\r\n" + + " --api-skiprpc=[true|false] skip @RestService(rpconly=true) service or @RestMapping(rpconly=true) method, default is true\r\n" + + " --api-host=[url] api root url, default is http://localhost\r\n" + + " help, -h, --help show this help\r\n"; + } + + NodeSncpServer findNodeSncpServer(final InetSocketAddress sncpAddr) { + for (NodeServer node : servers) { + if (node.isSNCP() && sncpAddr.equals(node.getSncpAddress())) { + return (NodeSncpServer) node; + } + } + return null; + } + + public List command(String cmd, String[] params) { + List localServers = new ArrayList<>(servers); //椤哄簭sncps, others, watchs + List results = new ArrayList<>(); + localServers.stream().forEach((server) -> { + try { + List rs = server.command(cmd, params); + if (rs != null) results.addAll(rs); + } catch (Exception t) { + logger.log(Level.WARNING, " command server(" + server.getSocketAddress() + ") error", t); + } + }); + return results; + } + + public void shutdown() throws Exception { + for (ApplicationListener listener : this.listeners) { + try { + listener.preShutdown(this); + } catch (Exception e) { + logger.log(Level.WARNING, listener.getClass() + " preShutdown erroneous", e); + } + } + List localServers = new ArrayList<>(servers); //椤哄簭sncps, others, watchs + Collections.reverse(localServers); //鍊掑簭锛 蹇呴』璁﹚atchs鍏堝叧闂紝watch鍖呭惈鏈嶅姟鍙戠幇鍜屾敞閿閫昏緫 + if (isCompileMode() && this.messageAgents != null) { + Set names = new HashSet<>(); + if (logger.isLoggable(Level.FINER)) logger.log(Level.FINER, "MessageAgent stopping"); + long s = System.currentTimeMillis(); + for (MessageAgent agent : this.messageAgents) { + names.add(agent.getName()); + agent.stop().join(); + } + logger.info("MessageAgent(names=" + JsonConvert.root().convertTo(names) + ") stop in " + (System.currentTimeMillis() - s) + " ms"); + } + if (!isCompileMode() && clusterAgent != null) { + if (logger.isLoggable(Level.FINER)) logger.log(Level.FINER, "ClusterAgent destroying"); + long s = System.currentTimeMillis(); + clusterAgent.deregister(this); + clusterAgent.destroy(clusterAgent.getConfig()); + logger.info("ClusterAgent destroy in " + (System.currentTimeMillis() - s) + " ms"); + } + localServers.stream().forEach((server) -> { + try { + server.shutdown(); + } catch (Exception t) { + logger.log(Level.WARNING, " shutdown server(" + server.getSocketAddress() + ") error", t); + } finally { + shutdownLatch.countDown(); + } + }); + if (this.messageAgents != null) { + Set names = new HashSet<>(); + if (logger.isLoggable(Level.FINER)) logger.log(Level.FINER, "MessageAgent destroying"); + long s = System.currentTimeMillis(); + for (MessageAgent agent : this.messageAgents) { + names.add(agent.getName()); + agent.destroy(agent.getConfig()); + } + logger.info("MessageAgent(names=" + JsonConvert.root().convertTo(names) + ") destroy in " + (System.currentTimeMillis() - s) + " ms"); + } + for (DataSource source : dataSources) { + if (source == null) continue; + try { + if (source instanceof Service) { + long s = System.currentTimeMillis(); + ((Service) source).destroy(Sncp.isSncpDyn((Service) source) ? Sncp.getConf((Service) source) : null); + logger.info(source + " destroy in " + (System.currentTimeMillis() - s) + " ms"); +// } else { +// source.getClass().getMethod("close").invoke(source); +// RedkaleClassLoader.putReflectionMethod(source.getClass().getName(), source.getClass().getMethod("close")); + } + } catch (Exception e) { + logger.log(Level.FINER, source.getClass() + " close DataSource erroneous", e); + } + } + for (CacheSource source : cacheSources) { + if (source == null) continue; + try { + if (source instanceof Service) { + long s = System.currentTimeMillis(); + ((Service) source).destroy(Sncp.isSncpDyn((Service) source) ? Sncp.getConf((Service) source) : null); + logger.info(source + " destroy in " + (System.currentTimeMillis() - s) + " ms"); +// } else { +// source.getClass().getMethod("close").invoke(source); +// RedkaleClassLoader.putReflectionMethod(source.getClass().getName(), source.getClass().getMethod("close")); + } + } catch (Exception e) { + logger.log(Level.FINER, source.getClass() + " close CacheSource erroneous", e); + } + } + if (this.propertiesAgent != null) { + long s = System.currentTimeMillis(); + this.propertiesAgent.destroy(config.getAnyValue("resources").getAnyValue("properties")); + logger.info(this.propertiesAgent.getClass().getSimpleName() + " destroy in " + (System.currentTimeMillis() - s) + " ms"); + } + if (this.asyncGroup != null) { + long s = System.currentTimeMillis(); + ((AsyncIOGroup) this.asyncGroup).close(); + logger.info("AsyncGroup destroy in " + (System.currentTimeMillis() - s) + " ms"); + } + this.sncpTransportFactory.shutdownNow(); + } + public ExecutorService getWorkExecutor() { return workExecutor; } @@ -654,896 +1881,6 @@ public final class Application { return singletonMode; } - public void init() throws Exception { - System.setProperty("redkale.net.transport.poolmaxconns", "100"); - System.setProperty("redkale.net.transport.pinginterval", "30"); - System.setProperty("redkale.net.transport.checkinterval", "30"); - System.setProperty("redkale.convert.tiny", "true"); - System.setProperty("redkale.convert.pool.size", "128"); - System.setProperty("redkale.convert.writer.buffer.defsize", "4096"); - - final String confDir = this.confPath.toString(); - final String homepath = this.home.getCanonicalPath(); - if ("file".equals(this.confPath.getScheme())) { - File persist = new File(new File(confPath), "persistence.xml"); - if (persist.isFile()) System.setProperty(DataSources.DATASOURCE_CONFPATH, persist.getCanonicalPath()); - } else { - System.setProperty(DataSources.DATASOURCE_CONFPATH, confDir + (confDir.endsWith("/") ? "" : "/") + "persistence.xml"); - } -// String pidstr = ""; -// try { //JDK 9+ -// Class phclass = Thread.currentThread().getContextClassLoader().loadClass("java.lang.ProcessHandle"); -// Object phobj = phclass.getMethod("current").invoke(null); -// Object pid = phclass.getMethod("pid").invoke(phobj); -// pidstr = "APP_PID = " + pid + "\r\n"; -// } catch (Throwable t) { -// } - - logger.log(Level.INFO, "APP_OSNAME = " + System.getProperty("os.name") + " " + System.getProperty("os.version") + " " + System.getProperty("os.arch") + "\r\n" - + "APP_JAVA = " + System.getProperty("java.runtime.name", System.getProperty("org.graalvm.nativeimage.kind") != null ? "Nativeimage" : "") - + " " + System.getProperty("java.runtime.version", System.getProperty("java.vendor.version", System.getProperty("java.vm.version"))) + "\r\n" //graalvm.nativeimage 妯″紡涓嬫棤 java.runtime.xxx 灞炴 - + "APP_PID = " + ProcessHandle.current().pid() + "\r\n" - + RESNAME_APP_NODEID + " = " + this.nodeid + "\r\n" - + "APP_LOADER = " + this.classLoader.getClass().getSimpleName() + "\r\n" - + RESNAME_APP_ADDR + " = " + this.localAddress.getHostString() + ":" + this.localAddress.getPort() + "\r\n" - + RESNAME_APP_HOME + " = " + homepath + "\r\n" - + RESNAME_APP_CONF + " = " + confDir.substring(confDir.indexOf('!') + 1)); - - if (!compileMode && !(classLoader instanceof RedkaleClassLoader.RedkaleCacheClassLoader)) { - String lib = config.getValue("lib", "${APP_HOME}/libs/*").trim().replace("${APP_HOME}", homepath); - lib = lib.isEmpty() ? confDir : (lib + ";" + confDir); - Server.loadLib(classLoader, logger, lib); - } - - //------------------------------------------------------------------------ - final AnyValue resources = config.getAnyValue("resources"); - if (resources != null) { - resourceFactory.register(RESNAME_APP_GRES, AnyValue.class, resources); - final AnyValue properties = resources.getAnyValue("properties"); - if (properties != null) { - String dfloads = properties.getValue("load"); - if (dfloads != null) { - for (String dfload : dfloads.split(";")) { - if (dfload.trim().isEmpty()) continue; - final URI df = RedkaleClassLoader.getConfResourceAsURI(configFromCache ? null : confDir, dfload.trim()); - if (df != null && (!"file".equals(df.getScheme()) || df.toString().contains("!") || new File(df).isFile())) { - Properties ps = new Properties(); - try { - InputStream in = df.toURL().openStream(); - ps.load(in); - in.close(); - ps.forEach((x, y) -> resourceFactory.register("property." + x, y.toString().replace("${APP_HOME}", homepath))); - } catch (Exception e) { - logger.log(Level.WARNING, "load properties(" + dfload + ") error", e); - } - } - } - } - for (AnyValue prop : properties.getAnyValues("property")) { - String name = prop.getValue("name"); - String value = prop.getValue("value"); - if (name == null || value == null) continue; - value = value.replace("${APP_HOME}", homepath); - if (name.startsWith("system.property.")) { - System.setProperty(name.substring("system.property.".length()), value); - } else if (name.startsWith("mimetype.property.")) { - MimeType.add(name.substring("mimetype.property.".length()), value); - } else if (name.startsWith("property.")) { - resourceFactory.register(name, value); - } else { - resourceFactory.register("property." + name, value); - } - } - } - } - this.resourceFactory.register(BsonFactory.root()); - this.resourceFactory.register(JsonFactory.root()); - this.resourceFactory.register(BsonFactory.root().getConvert()); - this.resourceFactory.register(JsonFactory.root().getConvert()); - this.resourceFactory.register("bsonconvert", Convert.class, BsonFactory.root().getConvert()); - this.resourceFactory.register("jsonconvert", Convert.class, JsonFactory.root().getConvert()); - //鍙湁WatchService鎵嶈兘鍔犺浇Application銆乄atchFactory - final Application application = this; - this.resourceFactory.register(new ResourceFactory.ResourceLoader() { - - @Override - public void load(ResourceFactory rf, final Object src, String resourceName, Field field, final Object attachment) { - try { - Resource res = field.getAnnotation(Resource.class); - if (res == null) return; - if (src instanceof Service && Sncp.isRemote((Service) src)) return; //杩滅▼妯″紡涓嶅緱娉ㄥ叆 - Class type = field.getType(); - if (type == Application.class) { - field.set(src, application); - } else if (type == ResourceFactory.class) { - boolean serv = RESNAME_SERVER_RESFACTORY.equals(res.name()) || res.name().equalsIgnoreCase("server"); - field.set(src, serv ? rf : (res.name().isEmpty() ? application.resourceFactory : null)); - } else if (type == TransportFactory.class) { - field.set(src, application.sncpTransportFactory); - } else if (type == NodeSncpServer.class) { - NodeServer server = null; - for (NodeServer ns : application.getNodeServers()) { - if (ns.getClass() != NodeSncpServer.class) continue; - if (res.name().equals(ns.server.getName())) { - server = ns; - break; - } - } - field.set(src, server); - } else if (type == NodeHttpServer.class) { - NodeServer server = null; - for (NodeServer ns : application.getNodeServers()) { - if (ns.getClass() != NodeHttpServer.class) continue; - if (res.name().equals(ns.server.getName())) { - server = ns; - break; - } - } - field.set(src, server); - } else if (type == NodeWatchServer.class) { - NodeServer server = null; - for (NodeServer ns : application.getNodeServers()) { - if (ns.getClass() != NodeWatchServer.class) continue; - if (res.name().equals(ns.server.getName())) { - server = ns; - break; - } - } - field.set(src, server); - } -// if (type == WatchFactory.class) { -// field.set(src, application.watchFactory); -// } - } catch (Exception e) { - logger.log(Level.SEVERE, "Resource inject error", e); - } - } - - @Override - public boolean autoNone() { - return false; - } - - }, Application.class, ResourceFactory.class, TransportFactory.class, NodeSncpServer.class, NodeHttpServer.class, NodeWatchServer.class); - - //------------------------------------- 娉ㄥ唽 java.net.http.HttpClient -------------------------------------------------------- - resourceFactory.register((ResourceFactory rf, final Object src, String resourceName, Field field, final Object attachment) -> { - try { - if (field.getAnnotation(Resource.class) == null) return; - java.net.http.HttpClient.Builder builder = java.net.http.HttpClient.newBuilder(); - if (resourceName.endsWith(".1.1")) { - builder.version(HttpClient.Version.HTTP_1_1); - } else if (resourceName.endsWith(".2")) { - builder.version(HttpClient.Version.HTTP_2); - } - java.net.http.HttpClient httpClient = builder.build(); - field.set(src, httpClient); - rf.inject(httpClient, null); // 缁欏叾鍙兘鍖呭惈@Resource鐨勫瓧娈佃祴鍊; - rf.register(resourceName, java.net.http.HttpClient.class, httpClient); - } catch (Exception e) { - logger.log(Level.SEVERE, "[" + Thread.currentThread().getName() + "] java.net.http.HttpClient inject error", e); - } - }, java.net.http.HttpClient.class); - //------------------------------------- 娉ㄥ唽 HttpSimpleClient -------------------------------------------------------- - resourceFactory.register((ResourceFactory rf, final Object src, String resourceName, Field field, final Object attachment) -> { - try { - if (field.getAnnotation(Resource.class) == null) return; - HttpSimpleClient httpClient = HttpSimpleClient.create(asyncGroup); - field.set(src, httpClient); - rf.inject(httpClient, null); // 缁欏叾鍙兘鍖呭惈@Resource鐨勫瓧娈佃祴鍊; - rf.register(resourceName, HttpSimpleClient.class, httpClient); - } catch (Exception e) { - logger.log(Level.SEVERE, "[" + Thread.currentThread().getName() + "] HttpClient inject error", e); - } - }, HttpSimpleClient.class); - //-------------------------------------------------------------------------- - if (this.asyncGroup != null) { - ((AsyncIOGroup) this.asyncGroup).start(); - } - if (this.clusterAgent != null) { - if (logger.isLoggable(Level.FINER)) logger.log(Level.FINER, "ClusterAgent initing"); - long s = System.currentTimeMillis(); - if (this.clusterAgent instanceof CacheClusterAgent) { - String sourceName = ((CacheClusterAgent) clusterAgent).getSourceName(); //蹇呴』鍦╥nject鍓嶈皟鐢紝闇瑕佽祴鍊糝esourcable.name - loadCacheSource(sourceName); - } - clusterAgent.setTransportFactory(this.sncpTransportFactory); - this.resourceFactory.inject(clusterAgent); - clusterAgent.init(clusterAgent.getConfig()); - this.resourceFactory.register(ClusterAgent.class, clusterAgent); - logger.info("ClusterAgent init in " + (System.currentTimeMillis() - s) + " ms"); - } - if (this.messageAgents != null) { - if (logger.isLoggable(Level.FINER)) logger.log(Level.FINER, "MessageAgent initing"); - long s = System.currentTimeMillis(); - for (MessageAgent agent : this.messageAgents) { - this.resourceFactory.inject(agent); - agent.init(agent.getConfig()); - this.resourceFactory.register(agent.getName(), MessageAgent.class, agent); - this.resourceFactory.register(agent.getName(), HttpMessageClient.class, agent.getHttpMessageClient()); - //this.resourceFactory.register(agent.getName(), SncpMessageClient.class, agent.getSncpMessageClient()); //涓嶉渶瑕佺粰寮鍙戣呬娇鐢 - } - logger.info("MessageAgent init in " + (System.currentTimeMillis() - s) + " ms"); - - } - //------------------------------------- 娉ㄥ唽 HttpMessageClient -------------------------------------------------------- - resourceFactory.register((ResourceFactory rf, final Object src, String resourceName, Field field, final Object attachment) -> { - try { - if (field.getAnnotation(Resource.class) == null) return; - if (clusterAgent == null) { - HttpMessageClient messageClient = new HttpMessageLocalClient(application, resourceName); - field.set(src, messageClient); - rf.inject(messageClient, null); // 缁欏叾鍙兘鍖呭惈@Resource鐨勫瓧娈佃祴鍊; - rf.register(resourceName, HttpMessageClient.class, messageClient); - return; - } - HttpMessageClient messageClient = new HttpMessageClusterClient(application, resourceName, clusterAgent); - field.set(src, messageClient); - rf.inject(messageClient, null); // 缁欏叾鍙兘鍖呭惈@Resource鐨勫瓧娈佃祴鍊; - rf.register(resourceName, HttpMessageClient.class, messageClient); - } catch (Exception e) { - logger.log(Level.SEVERE, "[" + Thread.currentThread().getName() + "] HttpMessageClient inject error", e); - } - }, HttpMessageClient.class); - initResources(); - } - - private void loadCacheSource(final String sourceName) { - final AnyValue resources = config.getAnyValue("resources"); - for (AnyValue sourceConf : resources.getAnyValues("source")) { - if (!sourceName.equals(sourceConf.getValue("name"))) continue; - String classval = sourceConf.getValue("value"); - try { - Class sourceType = CacheMemorySource.class; - if (classval == null || classval.isEmpty()) { - RedkaleClassLoader.putServiceLoader(CacheSourceProvider.class); - List providers = new ArrayList<>(); - Iterator it = ServiceLoader.load(CacheSourceProvider.class, serverClassLoader).iterator(); - while (it.hasNext()) { - CacheSourceProvider s = it.next(); - if (s != null) RedkaleClassLoader.putReflectionPublicConstructors(s.getClass(), s.getClass().getName()); - if (s != null && s.acceptsConf(sourceConf)) { - providers.add(s); - } - } - 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 (CacheSourceProvider provider : providers) { - sourceType = provider.sourceClass(); - if (sourceType != null) break; - } - } else { - sourceType = serverClassLoader.loadClass(classval); - } - RedkaleClassLoader.putReflectionPublicConstructors(sourceType, sourceType.getName()); - CacheSource source = sourceType == CacheMemorySource.class ? new CacheMemorySource(sourceName) - : Modifier.isFinal(sourceType.getModifiers()) ? (CacheSource) sourceType.getConstructor().newInstance() - : (CacheSource) Sncp.createLocalService(serverClassLoader, sourceName, sourceType, null, resourceFactory, sncpTransportFactory, null, null, sourceConf); - cacheSources.add((CacheSource) source); - resourceFactory.register(sourceName, CacheSource.class, source); - resourceFactory.inject(source); - if (!compileMode && source instanceof Service) ((Service) source).init(sourceConf); - logger.info("[" + Thread.currentThread().getName() + "] Load Source resourceName = " + sourceName + ", source = " + source); - } catch (Exception e) { - logger.log(Level.SEVERE, "load application source resource error: " + sourceConf, e); - } - return; - } - } - - private void initResources() throws Exception { - //------------------------------------------------------------------------- - final AnyValue resources = config.getAnyValue("resources"); - if (!compileMode && !singletonMode && configFromCache) { - System.setProperty(DATASOURCE_CONFPATH, ""); //蹇呴』瑕佹竻绌 - } - if (resources != null) { - //------------------------------------------------------------------------ - for (AnyValue conf : resources.getAnyValues("group")) { - final String group = conf.getValue("name", ""); - final String protocol = conf.getValue("protocol", Transport.DEFAULT_NETPROTOCOL).toUpperCase(); - if (!"TCP".equalsIgnoreCase(protocol) && !"UDP".equalsIgnoreCase(protocol)) { - throw new RuntimeException("Not supported Transport Protocol " + conf.getValue("protocol")); - } - TransportGroupInfo ginfo = new TransportGroupInfo(group, protocol, new LinkedHashSet<>()); - for (AnyValue node : conf.getAnyValues("node")) { - final InetSocketAddress addr = new InetSocketAddress(node.getValue("addr"), node.getIntValue("port")); - ginfo.putAddress(addr); - } - sncpTransportFactory.addGroupInfo(ginfo); - } - for (AnyValue conf : resources.getAnyValues("listener")) { - final String listenClass = conf.getValue("value", ""); - if (listenClass.isEmpty()) continue; - Class clazz = classLoader.loadClass(listenClass); - if (!ApplicationListener.class.isAssignableFrom(clazz)) continue; - RedkaleClassLoader.putReflectionDeclaredConstructors(clazz, clazz.getName()); - @SuppressWarnings("unchecked") - ApplicationListener listener = (ApplicationListener) clazz.getDeclaredConstructor().newInstance(); - resourceFactory.inject(listener); - listener.init(config); - this.listeners.add(listener); - } - } - //------------------------------------------------------------------------ - } - - private void startSelfServer() throws Exception { - final Application application = this; - new Thread() { - { - setName("Redkale-Application-SelfServer-Thread"); - } - - @Override - public void run() { - try { - final DatagramChannel channel = DatagramChannel.open(); - channel.configureBlocking(true); - channel.socket().setSoTimeout(3000); - channel.bind(new InetSocketAddress("127.0.0.1", config.getIntValue("port"))); - boolean loop = true; - ByteBuffer buffer = ByteBuffer.allocateDirect(1024); - while (loop) { - buffer.clear(); - SocketAddress address = channel.receive(buffer); - buffer.flip(); - byte[] bytes = new byte[buffer.remaining()]; - buffer.get(bytes); - String[] param = JsonConvert.root().convertFrom(String[].class, bytes); - final String cmd = param[0]; - if ("SHUTDOWN".equalsIgnoreCase(cmd)) { - try { - long s = System.currentTimeMillis(); - logger.info(application.getClass().getSimpleName() + " shutdowning"); - application.shutdown(); - buffer.clear(); - buffer.put("SHUTDOWN OK".getBytes()); - buffer.flip(); - channel.send(buffer, address); - long e = System.currentTimeMillis() - s; - logger.info(application.getClass().getSimpleName() + " shutdown in " + e + " ms"); - application.serversLatch.countDown(); - System.exit(0); - } catch (Exception ex) { - logger.log(Level.INFO, "SHUTDOWN FAIL", ex); - buffer.clear(); - buffer.put("SHUTDOWN FAIL".getBytes()); - buffer.flip(); - channel.send(buffer, address); - } - } else if ("APIDOC".equalsIgnoreCase(cmd)) { - try { - String[] args = new String[param.length - 1]; - if (param.length > 1) System.arraycopy(param, 1, args, 0, args.length); - new ApiDocsService(application).run(args); - buffer.clear(); - buffer.put("APIDOC OK".getBytes()); - buffer.flip(); - channel.send(buffer, address); - } catch (Exception ex) { - buffer.clear(); - buffer.put("APIDOC FAIL".getBytes()); - buffer.flip(); - channel.send(buffer, address); - } - } else { - long s = System.currentTimeMillis(); - logger.info(application.getClass().getSimpleName() + " command " + cmd); - application.command(cmd); - buffer.clear(); - buffer.put("COMMAND OK".getBytes()); - buffer.flip(); - channel.send(buffer, address); - long e = System.currentTimeMillis() - s; - logger.info(application.getClass().getSimpleName() + " command in " + e + " ms"); - } - } - } catch (Exception e) { - logger.log(Level.INFO, "Control fail", e); - System.exit(1); - } - } - }.start(); - } - - private static void sendCommand(Logger logger, int port, String command, String[] args) throws Exception { - final DatagramChannel channel = DatagramChannel.open(); - channel.configureBlocking(true); - channel.connect(new InetSocketAddress("127.0.0.1", port)); - ByteBuffer buffer = ByteBuffer.allocate(1024); - String[] param = new String[1 + (args == null ? 0 : args.length)]; - param[0] = command; - if (args != null) System.arraycopy(args, 0, param, 1, args.length); - buffer.put(JsonConvert.root().convertToBytes(param)); - buffer.flip(); - channel.write(buffer); - buffer.clear(); - channel.configureBlocking(true); - try { - channel.read(buffer); - buffer.flip(); - byte[] bytes = new byte[buffer.remaining()]; - buffer.get(bytes); - channel.close(); - if (logger != null) logger.info("Send: " + command + ", Reply: " + new String(bytes)); - Thread.sleep(1000); - } catch (Exception e) { - if (e instanceof PortUnreachableException) { - if ("APIDOC".equalsIgnoreCase(command)) { - final Application application = Application.create(true); - application.init(); - application.start(); - new ApiDocsService(application).run(args); - if (logger != null) logger.info("APIDOC OK"); - return; - } - } - throw e; - } - } - - /** - * 鍚姩 - * - * @throws Exception 寮傚父 - */ - public void start() throws Exception { - if (!singletonMode && !compileMode && this.clusterAgent != null) { - this.clusterAgent.register(this); - } - final AnyValue[] entrys = config.getAnyValues("server"); - CountDownLatch timecd = new CountDownLatch(entrys.length); - final List sncps = new ArrayList<>(); - final List others = new ArrayList<>(); - final List watchs = new ArrayList<>(); - for (final AnyValue entry : entrys) { - if (entry.getValue("protocol", "").toUpperCase().startsWith("SNCP")) { - sncps.add(entry); - } else if (entry.getValue("protocol", "").toUpperCase().startsWith("WATCH")) { - watchs.add(entry); - } else { - others.add(entry); - } - } - if (watchs.size() > 1) throw new RuntimeException("Found one more WATCH Server"); - this.watching = !watchs.isEmpty(); - - runServers(timecd, sncps); //蹇呴』纭繚SNCP鏈嶅姟閮藉惎鍔ㄥ悗鍐嶅惎鍔ㄥ叾浠栨湇鍔 - runServers(timecd, others); - runServers(timecd, watchs); //蹇呴』鍦ㄦ墍鏈夋湇鍔¢兘鍚姩鍚庡啀鍚姩WATCH鏈嶅姟 - timecd.await(); - if (this.clusterAgent != null) this.clusterAgent.start(); - if (this.messageAgents != null) { - if (logger.isLoggable(Level.FINER)) logger.log(Level.FINER, "MessageAgent starting"); - long s = System.currentTimeMillis(); - final StringBuffer sb = new StringBuffer(); - Set names = new HashSet<>(); - for (MessageAgent agent : this.messageAgents) { - names.add(agent.getName()); - Map map = agent.start().join(); - AtomicInteger maxlen = new AtomicInteger(); - map.keySet().forEach(str -> { - if (str.length() > maxlen.get()) maxlen.set(str.length()); - }); - new TreeMap<>(map).forEach((topic, ms) -> sb.append("MessageConsumer(topic=").append(alignString(topic, maxlen.get())).append(") init and start in ").append(ms).append(" ms\r\n") - ); - } - if (sb.length() > 0) logger.info(sb.toString().trim()); - logger.info("MessageAgent(names=" + JsonConvert.root().convertTo(names) + ") start in " + (System.currentTimeMillis() - s) + " ms"); - } - //if (!singletonrun) signalHandle(); - //if (!singletonrun) clearPersistData(); - logger.info(this.getClass().getSimpleName() + " started in " + (System.currentTimeMillis() - startTime) + " ms\r\n"); - for (ApplicationListener listener : this.listeners) { - listener.postStart(this); - } - if (!singletonMode && !compileMode) this.serversLatch.await(); - } - - private static String alignString(String value, int maxlen) { - StringBuilder sb = new StringBuilder(maxlen); - sb.append(value); - for (int i = 0; i < maxlen - value.length(); i++) { - sb.append(' '); - } - return sb.toString(); - } - -// private void clearPersistData() { -// File cachedir = new File(home, "cache"); -// if (!cachedir.isDirectory()) return; -// File[] lfs = cachedir.listFiles(); -// if (lfs != null) { -// for (File file : lfs) { -// if (file.getName().startsWith("persist-")) file.delete(); -// } -// } -// } -// private void signalHandle() { -// //http://www.comptechdoc.org/os/linux/programming/linux_pgsignals.html -// String[] sigs = new String[]{"HUP", "TERM", "INT", "QUIT", "KILL", "TSTP", "USR1", "USR2", "STOP"}; -// List list = new ArrayList<>(); -// for (String sig : sigs) { -// try { -// list.add(new sun.misc.Signal(sig)); -// } catch (Exception e) { -// } -// } -// sun.misc.SignalHandler handler = new sun.misc.SignalHandler() { -// -// private volatile boolean runed; -// -// @Override -// public void handle(Signal sig) { -// if (runed) return; -// runed = true; -// logger.info(Application.this.getClass().getSimpleName() + " stoped\r\n"); -// System.exit(0); -// } -// }; -// for (Signal sig : list) { -// try { -// Signal.handle(sig, handler); -// } catch (Exception e) { -// } -// } -// } - @SuppressWarnings("unchecked") - private void runServers(CountDownLatch timecd, final List serconfs) throws Exception { - this.servicecdl = new CountDownLatch(serconfs.size()); - CountDownLatch sercdl = new CountDownLatch(serconfs.size()); - final AtomicBoolean inited = new AtomicBoolean(false); - final Map> nodeClasses = new HashMap<>(); - for (final AnyValue serconf : serconfs) { - Thread thread = new Thread() { - { - setName("Redkale-" + serconf.getValue("protocol", "Server").toUpperCase().replaceFirst("\\..+", "") + ":" + serconf.getIntValue("port") + "-Thread"); - this.setDaemon(true); - } - - @Override - public void run() { - try { - //Thread ctd = Thread.currentThread(); - //ctd.setContextClassLoader(new URLClassLoader(new URL[0], ctd.getContextClassLoader())); - final String protocol = serconf.getValue("protocol", "").replaceFirst("\\..+", "").toUpperCase(); - NodeServer server = null; - if ("SNCP".equals(protocol)) { - server = NodeSncpServer.createNodeServer(Application.this, serconf); - } else if ("WATCH".equalsIgnoreCase(protocol)) { - DefaultAnyValue serconf2 = (DefaultAnyValue) serconf; - DefaultAnyValue rest = (DefaultAnyValue) serconf2.getAnyValue("rest"); - if (rest == null) { - rest = new DefaultAnyValue(); - serconf2.addValue("rest", rest); - } - rest.setValue("base", WatchServlet.class.getName()); - server = new NodeWatchServer(Application.this, serconf); - } else if ("HTTP".equalsIgnoreCase(protocol)) { - server = new NodeHttpServer(Application.this, serconf); - } else { - if (!inited.get()) { - synchronized (nodeClasses) { - if (!inited.getAndSet(true)) { //鍔犺浇鑷畾涔夌殑鍗忚锛屽锛歋OCKS - ClassFilter profilter = new ClassFilter(classLoader, NodeProtocol.class, NodeServer.class, (Class[]) null); - ClassFilter.Loader.load(home, classLoader, ((excludelibs != null ? (excludelibs + ";") : "") + serconf.getValue("excludelibs", "")).split(";"), profilter); - final Set> entrys = profilter.getFilterEntrys(); - for (FilterEntry entry : entrys) { - final Class type = entry.getType(); - NodeProtocol pros = type.getAnnotation(NodeProtocol.class); - String p = pros.value().toUpperCase(); - if ("SNCP".equals(p) || "HTTP".equals(p)) continue; - final Class old = nodeClasses.get(p); - if (old != null && old != type) { - throw new RuntimeException("Protocol(" + p + ") had NodeServer-Class(" + old.getName() + ") but repeat NodeServer-Class(" + type.getName() + ")"); - } - nodeClasses.put(p, type); - } - } - } - } - Class nodeClass = nodeClasses.get(protocol); - if (nodeClass != null) server = NodeServer.create(nodeClass, Application.this, serconf); - } - if (server == null) { - logger.log(Level.SEVERE, "Not found Server Class for protocol({0})", serconf.getValue("protocol")); - System.exit(0); - } - servers.add(server); - server.init(serconf); - if (!singletonMode && !compileMode) { - server.start(); - } else if (compileMode) { - server.getServer().getPrepareServlet().init(server.getServer().getContext(), serconf); - } - timecd.countDown(); - sercdl.countDown(); - } catch (Exception ex) { - logger.log(Level.WARNING, serconf + " runServers error", ex); - Application.this.serversLatch.countDown(); - } - } - }; - thread.start(); - } - sercdl.await(); - } - - /** - * 瀹炰緥鍖栧崟涓猄ervice - * - * @param 娉涘瀷 - * @param serviceClass 鎸囧畾鐨剆ervice绫 - * @param extServiceClasses 闇瑕佹帓闄ょ殑service绫 - * - * @return Service瀵硅薄 - * @throws Exception 寮傚父 - */ - public static T singleton(Class serviceClass, Class... extServiceClasses) throws Exception { - return singleton("", serviceClass, extServiceClasses); - } - - /** - * 瀹炰緥鍖栧崟涓猄ervice - * - * @param 娉涘瀷 - * @param name Service鐨勮祫婧愬悕 - * @param serviceClass 鎸囧畾鐨剆ervice绫 - * @param extServiceClasses 闇瑕佹帓闄ょ殑service绫 - * - * @return Service瀵硅薄 - * @throws Exception 寮傚父 - */ - public static T singleton(String name, Class serviceClass, Class... extServiceClasses) throws Exception { - if (serviceClass == null) throw new IllegalArgumentException("serviceClass is null"); - final Application application = Application.create(true); - System.setProperty("red" + "kale.singleton.serviceclass", serviceClass.getName()); - if (extServiceClasses != null && extServiceClasses.length > 0) { - StringBuilder sb = new StringBuilder(); - for (Class clazz : extServiceClasses) { - if (sb.length() > 0) sb.append(','); - sb.append(clazz.getName()); - } - System.setProperty("red" + "kale.singleton.extserviceclasses", sb.toString()); - } - application.init(); - application.start(); - for (NodeServer server : application.servers) { - T service = server.resourceFactory.find(name, serviceClass); - if (service != null) return service; - } - if (Modifier.isAbstract(serviceClass.getModifiers())) throw new IllegalArgumentException("abstract class not allowed"); - if (serviceClass.isInterface()) throw new IllegalArgumentException("interface class not allowed"); - throw new IllegalArgumentException(serviceClass.getName() + " maybe have zero not-final public method"); - } - - public static Application create(final boolean singleton) throws IOException { - return new Application(singleton, false, loadAppConfig()); - } - - /** - * 閲嶆柊鍔犺浇閰嶇疆淇℃伅 - * - * @throws IOException 寮傚父 - */ - public void reloadConfig() throws IOException { - AnyValue newconfig = loadAppConfig(); - final String confpath = this.confPath.toString(); - final String homepath = this.home.getCanonicalPath(); - final AnyValue resources = newconfig.getAnyValue("resources"); - if (resources != null) { - resourceFactory.register(RESNAME_APP_GRES, AnyValue.class, resources); - final AnyValue properties = resources.getAnyValue("properties"); - if (properties != null) { - String dfloads = properties.getValue("load"); - if (dfloads != null) { - for (String dfload : dfloads.split(";")) { - if (dfload.trim().isEmpty()) continue; - final URI df = (dfload.indexOf('/') < 0) ? URI.create(confpath + (confpath.endsWith("/") ? "" : "/") + dfload) : new File(dfload).toURI(); - if (!"file".equals(df.getScheme()) || new File(df).isFile()) { - Properties ps = new Properties(); - try { - InputStream in = df.toURL().openStream(); - ps.load(in); - in.close(); - ps.forEach((x, y) -> resourceFactory.register("property." + x, y.toString().replace("${APP_HOME}", homepath))); - } catch (Exception e) { - logger.log(Level.WARNING, "load properties(" + dfload + ") error", e); - } - } - } - } - for (AnyValue prop : properties.getAnyValues("property")) { - String name = prop.getValue("name"); - String value = prop.getValue("value"); - if (name == null || value == null) continue; - value = value.replace("${APP_HOME}", homepath); - if (name.startsWith("system.property.")) { - System.setProperty(name.substring("system.property.".length()), value); - } else if (name.startsWith("mimetype.property.")) { - MimeType.add(name.substring("mimetype.property.".length()), value); - } else if (name.startsWith("property.")) { - resourceFactory.register(name, value); - } else { - resourceFactory.register("property." + name, value); - } - } - } - } - } - - static AnyValue loadAppConfig() throws IOException { - final String home = new File(System.getProperty(RESNAME_APP_HOME, "")).getCanonicalPath().replace('\\', '/'); - System.setProperty(RESNAME_APP_HOME, home); - String confDir = System.getProperty(RESNAME_APP_CONF, "conf"); - URI appConfFile; - boolean fromcache = false; - if (confDir.contains("://")) { - appConfFile = URI.create(confDir + (confDir.endsWith("/") ? "" : "/") + "application.xml"); - } else if (confDir.charAt(0) == '/' || confDir.indexOf(':') > 0) { - File f = new File(confDir, "application.xml"); - if (f.isFile() && f.canRead()) { - appConfFile = f.toURI(); - confDir = f.getParentFile().getCanonicalPath(); - } else { - appConfFile = RedkaleClassLoader.getConfResourceAsURI(null, "application.xml"); //涓嶈兘浼燾onfDir - confDir = appConfFile.toString().replace("/application.xml", ""); - fromcache = true; - } - } else { - File f = new File(new File(home, confDir), "application.xml"); - if (f.isFile() && f.canRead()) { - appConfFile = f.toURI(); - confDir = f.getParentFile().getCanonicalPath(); - } else { - appConfFile = RedkaleClassLoader.getConfResourceAsURI(null, "application.xml"); //涓嶈兘浼燾onfDir - confDir = appConfFile.toString().replace("/application.xml", ""); - fromcache = true; - } - } - System.setProperty(RESNAME_APP_CONF, confDir); - AnyValue conf = AnyValue.loadFromXml(appConfFile.toURL().openStream(), StandardCharsets.UTF_8, (k, v) -> v.replace("${APP_HOME}", home)).getAnyValue("application"); - if (fromcache) ((DefaultAnyValue) conf).addValue("[config-from-cache]", "true"); - return conf; - } - - public static void main(String[] args) throws Exception { - Utility.midnight(); //鍏堝垵濮嬪寲涓涓婾tility - Thread.currentThread().setName("Redkale-Application-Main-Thread"); - //杩愯涓荤▼搴 - { - String cmd = System.getProperty("cmd", System.getProperty("CMD")); - String[] params = args; - if (cmd == null && args != null && args.length > 0 - && args[0] != null && !args[0].trim().isEmpty() && !"start".equalsIgnoreCase(args[0])) { - cmd = args[0]; - params = Arrays.copyOfRange(args, 1, args.length); - } - if (cmd != null) { - AnyValue config = loadAppConfig(); - Application.sendCommand(null, config.getIntValue("port"), cmd, params); - return; - } - } - //PrepareCompiler.main(args); //娴嬭瘯浠g爜 - - final Application application = Application.create(false); - application.init(); - application.startSelfServer(); - try { - for (ApplicationListener listener : application.listeners) { - listener.preStart(application); - } - application.start(); - } catch (Exception e) { - application.logger.log(Level.SEVERE, "Application start error", e); - System.exit(0); - } - System.exit(0); - } - - NodeSncpServer findNodeSncpServer(final InetSocketAddress sncpAddr) { - for (NodeServer node : servers) { - if (node.isSNCP() && sncpAddr.equals(node.getSncpAddress())) { - return (NodeSncpServer) node; - } - } - return null; - } - - public void command(String cmd) { - List localServers = new ArrayList<>(servers); //椤哄簭sncps, others, watchs - localServers.stream().forEach((server) -> { - try { - server.command(cmd); - } catch (Exception t) { - logger.log(Level.WARNING, " command server(" + server.getSocketAddress() + ") error", t); - } - }); - } - - public void shutdown() throws Exception { - for (ApplicationListener listener : this.listeners) { - try { - listener.preShutdown(this); - } catch (Exception e) { - logger.log(Level.WARNING, listener.getClass() + " preShutdown erroneous", e); - } - } - List localServers = new ArrayList<>(servers); //椤哄簭sncps, others, watchs - Collections.reverse(localServers); //鍊掑簭锛 蹇呴』璁﹚atchs鍏堝叧闂紝watch鍖呭惈鏈嶅姟鍙戠幇鍜屾敞閿閫昏緫 - if (isCompileMode() && this.messageAgents != null) { - Set names = new HashSet<>(); - if (logger.isLoggable(Level.FINER)) logger.log(Level.FINER, "MessageAgent stopping"); - long s = System.currentTimeMillis(); - for (MessageAgent agent : this.messageAgents) { - names.add(agent.getName()); - agent.stop().join(); - } - logger.info("MessageAgent(names=" + JsonConvert.root().convertTo(names) + ") stop in " + (System.currentTimeMillis() - s) + " ms"); - } - if (!isCompileMode() && clusterAgent != null) { - if (logger.isLoggable(Level.FINER)) logger.log(Level.FINER, "ClusterAgent destroying"); - long s = System.currentTimeMillis(); - clusterAgent.deregister(this); - clusterAgent.destroy(clusterAgent.getConfig()); - logger.info("ClusterAgent destroy in " + (System.currentTimeMillis() - s) + " ms"); - } - localServers.stream().forEach((server) -> { - try { - server.shutdown(); - } catch (Exception t) { - logger.log(Level.WARNING, " shutdown server(" + server.getSocketAddress() + ") error", t); - } finally { - serversLatch.countDown(); - } - }); - if (this.messageAgents != null) { - Set names = new HashSet<>(); - if (logger.isLoggable(Level.FINER)) logger.log(Level.FINER, "MessageAgent destroying"); - long s = System.currentTimeMillis(); - for (MessageAgent agent : this.messageAgents) { - names.add(agent.getName()); - agent.destroy(agent.getConfig()); - } - logger.info("MessageAgent(names=" + JsonConvert.root().convertTo(names) + ") destroy in " + (System.currentTimeMillis() - s) + " ms"); - } - for (DataSource source : dataSources) { - if (source == null) continue; - try { - if (source instanceof Service) { - ((Service) source).destroy(Sncp.isSncpDyn((Service) source) ? Sncp.getConf((Service) source) : null); -// } else { -// source.getClass().getMethod("close").invoke(source); -// RedkaleClassLoader.putReflectionMethod(source.getClass().getName(), source.getClass().getMethod("close")); - } - } catch (Exception e) { - logger.log(Level.FINER, source.getClass() + " close DataSource erroneous", e); - } - } - for (CacheSource source : cacheSources) { - if (source == null) continue; - try { - if (source instanceof Service) { - ((Service) source).destroy(Sncp.isSncpDyn((Service) source) ? Sncp.getConf((Service) source) : null); -// } else { -// source.getClass().getMethod("close").invoke(source); -// RedkaleClassLoader.putReflectionMethod(source.getClass().getName(), source.getClass().getMethod("close")); - } - } catch (Exception e) { - logger.log(Level.FINER, source.getClass() + " close CacheSource erroneous", e); - } - } - if (this.asyncGroup != null) { - ((AsyncIOGroup) this.asyncGroup).close(); - } - this.sncpTransportFactory.shutdownNow(); - } - private static int parseLenth(String value, int defValue) { if (value == null) return defValue; value = value.toUpperCase().replace("B", ""); diff --git a/src/main/java/org/redkale/boot/ClassFilter.java b/src/main/java/org/redkale/boot/ClassFilter.java index cdd1df635..9f4b73e93 100644 --- a/src/main/java/org/redkale/boot/ClassFilter.java +++ b/src/main/java/org/redkale/boot/ClassFilter.java @@ -16,6 +16,7 @@ import java.util.function.Predicate; import java.util.jar.*; import java.util.logging.*; import java.util.regex.*; +import javax.annotation.Priority; import org.redkale.util.*; import org.redkale.util.AnyValue.DefaultAnyValue; @@ -103,11 +104,12 @@ public final class ClassFilter { * @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; + List> list = new ArrayList<>(); + list.addAll(entrys); + if (ors != null) ors.forEach(f -> list.addAll(f.getFilterEntrys())); + if (ands != null) ands.forEach(f -> list.addAll(f.getFilterEntrys())); + Collections.sort(list); + return new LinkedHashSet<>(list); } /** @@ -116,11 +118,12 @@ public final class ClassFilter { * @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; + List> list = new ArrayList<>(); + list.addAll(expectEntrys); + if (ors != null) ors.forEach(f -> list.addAll(f.getFilterExpectEntrys())); + if (ands != null) ands.forEach(f -> list.addAll(f.getFilterExpectEntrys())); + Collections.sort(list); + return new LinkedHashSet<>(list); } /** @@ -129,7 +132,7 @@ public final class ClassFilter { * @return Set<FilterEntry<T>> */ public final Set> getAllFilterEntrys() { - HashSet> rs = new HashSet<>(); + HashSet> rs = new LinkedHashSet<>(); rs.addAll(getFilterEntrys()); rs.addAll(getFilterExpectEntrys()); return rs; @@ -384,7 +387,7 @@ public final class ClassFilter { * * @param 娉涘瀷 */ - public static final class FilterEntry { + public static final class FilterEntry implements Comparable> { private final HashSet groups = new LinkedHashSet<>(); @@ -416,6 +419,14 @@ public final class ClassFilter { this.name = property == null ? "" : property.getValue("name", ""); } + @Override //@Priority鍊艰秺澶э紝浼樺厛绾ц秺楂, 闇瑕佹帓鍓嶉潰 + public int compareTo(FilterEntry o) { + if (!(o instanceof FilterEntry)) return 1; + Priority p1 = this.type.getAnnotation(Priority.class); + Priority p2 = ((FilterEntry) o).type.getAnnotation(Priority.class); + return (p2 == null ? 0 : p2.value()) - (p1 == null ? 0 : p1.value()); + } + @Override public String toString() { return this.getClass().getSimpleName() + "[thread=" + Thread.currentThread().getName() @@ -465,6 +476,7 @@ public final class ClassFilter { public boolean isExpect() { return expect; } + } /** diff --git a/src/main/java/org/redkale/boot/LoggingBaseHandler.java b/src/main/java/org/redkale/boot/LoggingBaseHandler.java new file mode 100644 index 000000000..0c87b04cc --- /dev/null +++ b/src/main/java/org/redkale/boot/LoggingBaseHandler.java @@ -0,0 +1,20 @@ +/* + */ +package org.redkale.boot; + +import java.util.logging.Handler; + +/** + * Handler鍩虹被 + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @since 2.7.0 + */ +public abstract class LoggingBaseHandler extends Handler { + + protected Application currentApplication() { + return Application.currentApplication; //涓嶈兘鐩存帴鏆撮湶澶栫晫璁块棶 + } +} diff --git a/src/main/java/org/redkale/boot/LoggingFileHandler.java b/src/main/java/org/redkale/boot/LoggingFileHandler.java index 32fc1c8f0..15a981d2d 100644 --- a/src/main/java/org/redkale/boot/LoggingFileHandler.java +++ b/src/main/java/org/redkale/boot/LoggingFileHandler.java @@ -10,13 +10,13 @@ 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; +import org.redkale.util.*; /** * 鑷畾涔夌殑鏃ュ織杈撳嚭绫 @@ -26,11 +26,13 @@ import java.util.regex.Pattern; * @author zhangjx */ @SuppressWarnings("unchecked") -public class LoggingFileHandler extends Handler { +public class LoggingFileHandler extends LoggingBaseHandler { //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"; + static boolean traceflag = false; //闃叉璁剧疆system.property鍓嶈皟鐢═races绫诲鑷磂nable鎻愬墠鍒濆鍖 + /** * SNCP鐨勬棩蹇楄緭鍑篐andler */ @@ -42,6 +44,46 @@ public class LoggingFileHandler extends Handler { } } + public static class LoggingConsoleHandler extends ConsoleHandler { + + private Pattern denyreg; + + public LoggingConsoleHandler() { + super(); + configure(); + } + + private void configure() { + LogManager manager = LogManager.getLogManager(); + String denyregstr = manager.getProperty("java.util.logging.ConsoleHandler.denyreg"); + try { + if (denyregstr != null && !denyregstr.trim().isEmpty()) { + denyreg = Pattern.compile(denyregstr); + } + } catch (Exception e) { + } + } + + @Override + public void publish(LogRecord log) { + if (denyreg != null && denyreg.matcher(log.getMessage()).find()) return; + if (traceflag && Traces.enable()) { + String traceid = Traces.currTraceid(); + if (traceid == null || traceid.isEmpty()) { + traceid = "[TID:N/A] "; + } else { + traceid = "[TID:" + traceid + "] "; + } + if (log.getMessage() == null) { + log.setMessage(traceid); + } else { + log.setMessage(traceid + log.getMessage()); + } + } + super.publish(log); + } + } + /** * 榛樿鐨勬棩蹇楁椂闂存牸寮忓寲绫 * 涓嶴impleFormatter鐨勫尯鍒湪浜巐evel涓嶄娇鐢ㄦ湰鍦板寲 @@ -51,6 +93,9 @@ public class LoggingFileHandler extends Handler { @Override public String format(LogRecord log) { + if (log.getThrown() == null && log.getMessage() != null && log.getMessage().startsWith("------")) { + return formatMessage(log) + "\r\n"; + } String source; if (log.getSourceClassName() != null) { source = log.getSourceClassName(); @@ -104,9 +149,13 @@ public class LoggingFileHandler extends Handler { protected final LinkedBlockingQueue logqueue = new LinkedBlockingQueue(); - private String pattern; + protected String pattern; - private String unusual; //涓嶄负null琛ㄧず灏 WARNING銆丼EVERE 绾у埆鐨勬棩蹇楀啓鍏ュ崟鐙殑鏂囦欢涓 + protected String patternDateFormat; //闇瑕佹椂闂存牸寮忓寲 + + protected String unusual; //涓嶄负null琛ㄧず灏 WARNING銆丼EVERE 绾у埆鐨勬棩蹇楀啓鍏ュ崟鐙殑鏂囦欢涓 + + protected String unusualDateFormat; //闇瑕佹椂闂存牸寮忓寲 private int limit; //鏂囦欢澶у皬闄愬埗 @@ -118,9 +167,9 @@ public class LoggingFileHandler extends Handler { private long tomorrow; - private boolean append; + protected boolean append; - private Pattern denyreg; + protected Pattern denyreg; private final AtomicLong loglength = new AtomicLong(); @@ -198,16 +247,14 @@ public class LoggingFileHandler extends Handler { } 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 = new File(patternDateFormat == null ? pattern : Utility.formatTime(patternDateFormat, -1, System.currentTimeMillis())); 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 = new File(unusualDateFormat == null ? unusual : Utility.formatTime(unusualDateFormat, -1, System.currentTimeMillis())); logunusualfile.getParentFile().mkdirs(); logunusuallength.set(logunusualfile.length()); logunusualstream = new FileOutputStream(logunusualfile, append); @@ -241,7 +288,7 @@ public class LoggingFileHandler extends Handler { String cname = LoggingFileHandler.class.getName(); this.pattern = manager.getProperty(cname + ".pattern"); if (this.pattern == null) { - this.pattern = "logs-%m/" + getPrefix() + "log-%d.log"; + this.pattern = "logs-%tm/" + getPrefix() + "log-%td.log"; } else { int pos = this.pattern.lastIndexOf('/'); if (pos > 0) { @@ -250,6 +297,10 @@ public class LoggingFileHandler extends Handler { this.pattern = getPrefix() + this.pattern; } } + if (this.pattern != null && this.pattern.contains("%")) { //闇瑕佹椂闂存牸寮忓寲 + this.patternDateFormat = this.pattern; + Utility.formatTime(this.patternDateFormat, -1, System.currentTimeMillis()); //娴嬭瘯鏃堕棿鏍煎紡鏄惁姝g‘ + } String unusualstr = manager.getProperty(cname + ".unusual"); if (unusualstr != null) { int pos = unusualstr.lastIndexOf('/'); @@ -259,6 +310,10 @@ public class LoggingFileHandler extends Handler { this.unusual = getPrefix() + unusualstr; } } + if (this.unusual != null && this.unusual.contains("%")) { //闇瑕佹椂闂存牸寮忓寲 + this.unusualDateFormat = this.unusual; + Utility.formatTime(this.unusualDateFormat, -1, System.currentTimeMillis()); //娴嬭瘯鏃堕棿鏍煎紡鏄惁姝g‘ + } String limitstr = manager.getProperty(cname + ".limit"); try { if (limitstr != null) { @@ -333,6 +388,7 @@ public class LoggingFileHandler extends Handler { @Override public void publish(LogRecord log) { + if (!isLoggable(log)) return; final String sourceClassName = log.getSourceClassName(); if (sourceClassName == null || true) { StackTraceElement[] ses = new Throwable().getStackTrace(); @@ -346,6 +402,19 @@ public class LoggingFileHandler extends Handler { log.setSourceClassName('[' + Thread.currentThread().getName() + "] " + sourceClassName); } if (denyreg != null && denyreg.matcher(log.getMessage()).find()) return; + if (traceflag && Traces.enable()) { + String traceid = Traces.currTraceid(); + if (traceid == null || traceid.isEmpty()) { + traceid = "[TID:N/A] "; + } else { + traceid = "[TID:" + traceid + "] "; + } + if (log.getMessage() == null) { + log.setMessage(traceid); + } else { + log.setMessage(traceid + log.getMessage()); + } + } logqueue.offer(log); } diff --git a/src/main/java/org/redkale/boot/LoggingSearchHandler.java b/src/main/java/org/redkale/boot/LoggingSearchHandler.java new file mode 100644 index 000000000..98c1329f6 --- /dev/null +++ b/src/main/java/org/redkale/boot/LoggingSearchHandler.java @@ -0,0 +1,303 @@ +/* + */ +package org.redkale.boot; + +import java.io.*; +import java.util.*; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.logging.*; +import java.util.logging.Formatter; +import java.util.regex.Pattern; +import javax.persistence.*; +import org.redkale.convert.*; +import org.redkale.convert.json.JsonConvert; +import org.redkale.source.*; +import org.redkale.util.*; + +/** + * 鍩轰簬SearchSource鐨勬棩蹇楄緭鍑虹被 + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @since 2.7.0 + */ +public class LoggingSearchHandler extends LoggingBaseHandler { + + protected static final String DEFAULT_TABLE_NAME = "log-record"; + + protected final LinkedBlockingQueue logqueue = new LinkedBlockingQueue(); + + protected final AtomicInteger retryCount = new AtomicInteger(3); + + protected String tag = DEFAULT_TABLE_NAME; //鐢ㄤ簬琛ㄥ墠缂锛 榛樿鏄 + + protected String tagDateFormat; //闇瑕佹椂闂存牸寮忓寲 + + protected String pattern; + + protected Pattern denyreg; + + protected String sourceResourceName; + + protected SearchSource source; + + public LoggingSearchHandler() { + configure(); + open(); + } + + private void open() { + final String name = "Redkale-" + getClass().getSimpleName() + "-Thread"; + final int batchSize = 100; //鎵归噺鏈澶100鏉 + final List logList = new ArrayList<>(); + final SimpleFormatter formatter = new SimpleFormatter(); + final PrintStream outStream = System.out; + new Thread() { + { + setName(name); + setDaemon(true); + } + + @Override + public void run() { + while (true) { + try { + SearchLogRecord log = logqueue.take(); + while (source == null && retryCount.get() > 0) initSource(); + //----------------------鍐欐棩蹇------------------------- + if (source == null) { //source鍔犺浇澶辫触 + outStream.print(formatter.format(log.rawLog)); + } else { + logList.add(log); + int size = batchSize; + while (--size > 0) { + log = logqueue.poll(); + if (log == null) break; + logList.add(log); + } + source.insert(logList); + } + } catch (Exception e) { + ErrorManager err = getErrorManager(); + if (err != null) err.error(null, e, ErrorManager.WRITE_FAILURE); + } finally { + logList.clear(); + } + } + + } + }.start(); + } + + private synchronized void initSource() { + if (retryCount.get() < 1) return; + try { + Utility.sleep(3000); //濡傛灉SearchSource鑷韩鍦ㄦ墦鍗版棩蹇楋紝闇瑕佸仠椤夸竴鐐规椂闂磋SearchSource鍒濆鍖栧畬鎴 + Application application = currentApplication(); + this.source = (SearchSource) application.loadDataSource(sourceResourceName, false); + if (retryCount.get() == 1 && this.source == null) System.err.println("ERROR: not load logging.source(" + sourceResourceName + ")"); + } catch (Exception t) { + ErrorManager err = getErrorManager(); + if (err != null) err.error(null, t, ErrorManager.WRITE_FAILURE); + } finally { + retryCount.decrementAndGet(); + } + } + + private static boolean checkTagName(String name) { //鍙兘鏄瓧姣嶃佹暟瀛椼佺煭妯佺偣銆%銆$鍜屼笅鍒掔嚎 + if (name.isEmpty()) return false; + for (char ch : name.toCharArray()) { + if (ch >= '0' && ch <= '9') continue; + if (ch >= 'a' && ch <= 'z') continue; + if (ch >= 'A' && ch <= 'Z') continue; + if (ch == '_' || ch == '-' || ch == '%' || ch == '$' || ch == '.') continue; + return false; + } + return true; + } + + private void configure() { + LogManager manager = LogManager.getLogManager(); + String cname = getClass().getName(); + this.sourceResourceName = manager.getProperty(cname + ".source"); + if (this.sourceResourceName == null || this.sourceResourceName.isEmpty()) { + throw new RuntimeException("not found logging.property " + cname + ".source"); + } + String tagstr = manager.getProperty(cname + ".tag"); + if (tagstr != null && !tagstr.isEmpty()) { + if (!checkTagName(tagstr.replaceAll("\\$\\{.+\\}", ""))) throw new RuntimeException("found illegal logging.property " + cname + ".tag = " + tagstr); + this.tag = tagstr; + if (tagstr.contains("%")) { + this.tagDateFormat = this.tag; + Utility.formatTime(this.tagDateFormat, -1, System.currentTimeMillis()); //娴嬭瘯鏃堕棿鏍煎紡鏄惁姝g‘ + } + } + + 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) { + if (!isLoggable(log)) return; + 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(ses[i].getClassName()); + log.setSourceMethodName(ses[i].getMethodName()); + break; + } + } + if (denyreg != null && denyreg.matcher(log.getMessage()).find()) return; + String rawTag = tagDateFormat == null ? tag : Utility.formatTime(tagDateFormat, -1, log.getInstant().toEpochMilli()); + logqueue.offer(new SearchLogRecord(rawTag, log)); + } + + @Override + public void flush() { + } + + @Override + public void close() throws SecurityException { + } + + @Entity + @Table(name = DEFAULT_TABLE_NAME) + @DistributeTable(strategy = SearchLogRecord.TableStrategy.class) + public static class SearchLogRecord { + + @Id + @ConvertColumn(index = 1) + @SearchColumn(options = "false") + public String logid; + + @ConvertColumn(index = 2) + @SearchColumn(options = "false") + public String level; + + @ConvertColumn(index = 3) + @SearchColumn(date = true) + public long timestamp; + + @ConvertColumn(index = 4) + @SearchColumn(options = "false") + public String traceid; + + @ConvertColumn(index = 5) + public String threadName; + + @ConvertColumn(index = 6) + @SearchColumn(text = true, options = "offsets") + public String loggerName; + + @ConvertColumn(index = 7) + @SearchColumn(text = true, options = "offsets") + public String methodName; + + @ConvertColumn(index = 8) + @SearchColumn(text = true, options = "offsets") //, analyzer = "ik_max_word" + public String message; //log.message +"\r\n"+ log.thrown + + @Transient + @ConvertDisabled + LogRecord rawLog; + + @Transient + @ConvertDisabled + String rawTag; + + public SearchLogRecord() { + } + + protected SearchLogRecord(String tag, LogRecord log) { + this.rawLog = log; + this.rawTag = tag; + this.threadName = Thread.currentThread().getName(); + this.traceid = LoggingFileHandler.traceflag ? Traces.currTraceid() : null; + String msg = log.getMessage(); + if (log.getThrown() != null) { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + pw.println(); + log.getThrown().printStackTrace(pw); + pw.close(); + String throwable = sw.toString(); + this.message = (msg != null && !msg.isEmpty()) ? (msg + "\r\n" + throwable) : throwable; + } else { + this.message = msg; + } + this.level = log.getLevel().toString(); + this.loggerName = log.getLoggerName(); + this.methodName = log.getSourceClassName() + " " + log.getSourceMethodName(); + this.timestamp = log.getInstant().toEpochMilli(); + this.logid = Utility.format36time(timestamp) + "_" + Utility.uuid(); + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + + public static class TableStrategy implements DistributeTableStrategy { + + @Override + public String getTable(String table, SearchLogRecord bean) { + return bean.rawTag; + } + + @Override + public String getTable(String table, Serializable primary) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public String getTable(String table, FilterNode node) { + throw new UnsupportedOperationException("Not supported yet."); + } + + } + } +} diff --git a/src/main/java/org/redkale/boot/NodeHttpServer.java b/src/main/java/org/redkale/boot/NodeHttpServer.java index f7778bdae..0e2462a1d 100644 --- a/src/main/java/org/redkale/boot/NodeHttpServer.java +++ b/src/main/java/org/redkale/boot/NodeHttpServer.java @@ -90,7 +90,7 @@ public class NodeHttpServer extends NodeServer { @Override protected void loadFilter(ClassFilter filterFilter, ClassFilter otherFilter) throws Exception { - if (httpServer != null) loadHttpFilter(this.serverConf.getAnyValue("filters"), filterFilter); + if (httpServer != null) loadHttpFilter(filterFilter); } @Override @@ -102,19 +102,19 @@ public class NodeHttpServer extends NodeServer { private void initWebSocketService() { final NodeServer self = this; final ResourceFactory regFactory = application.getResourceFactory(); - resourceFactory.register((ResourceFactory rf, final Object src, final String resourceName, Field field, Object attachment) -> { //涓昏鐢ㄤ簬鍗曠偣鐨勬湇鍔 + resourceFactory.register((ResourceFactory rf, String srcResourceName, final Object srcObj, final String resourceName, Field field, Object attachment) -> { //涓昏鐢ㄤ簬鍗曠偣鐨勬湇鍔 try { if (field.getAnnotation(Resource.class) == null) return; - if (!(src instanceof WebSocketServlet)) return; - ResourceFactory.ResourceLoader loader = null; + if (!(srcObj instanceof WebSocketServlet)) return; + ResourceTypeLoader loader = null; ResourceFactory sncpResFactory = null; for (NodeServer ns : application.servers) { if (!ns.isSNCP()) continue; sncpResFactory = ns.resourceFactory; - loader = sncpResFactory.findLoader(WebSocketNode.class, field); + loader = sncpResFactory.findTypeLoader(WebSocketNode.class, field); if (loader != null) break; } - if (loader != null) loader.load(sncpResFactory, src, resourceName, field, attachment); + if (loader != null) loader.load(sncpResFactory, srcResourceName, srcObj, resourceName, field, attachment); synchronized (regFactory) { Service nodeService = (Service) rf.find(resourceName, WebSocketNode.class); if (sncpResFactory != null && resourceFactory.find(RESNAME_SNCP_ADDR, String.class) == null) { @@ -127,15 +127,15 @@ public class NodeHttpServer extends NodeServer { try { Field c = WebSocketServlet.class.getDeclaredField("messageAgent"); c.setAccessible(true); - messageAgent = (MessageAgent) c.get(src); + messageAgent = (MessageAgent) c.get(srcObj); } catch (Exception ex) { logger.log(Level.WARNING, "WebSocketServlet getMessageAgent error", ex); } nodeService = Sncp.createLocalService(serverClassLoader, resourceName, org.redkale.net.http.WebSocketNodeService.class, messageAgent, application.getResourceFactory(), application.getSncpTransportFactory(), (InetSocketAddress) null, (Set) null, (AnyValue) null); regFactory.register(resourceName, WebSocketNode.class, nodeService); } - resourceFactory.inject(nodeService, self); - field.set(src, nodeService); + resourceFactory.inject(resourceName, nodeService, self); + field.set(srcObj, nodeService); logger.fine("[" + Thread.currentThread().getName() + "] Load Service " + nodeService); } } catch (Exception e) { @@ -145,7 +145,7 @@ public class NodeHttpServer extends NodeServer { } @SuppressWarnings("unchecked") - protected void loadHttpFilter(final AnyValue filtersConf, final ClassFilter classFilter) throws Exception { + protected void loadHttpFilter(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()); diff --git a/src/main/java/org/redkale/boot/NodeServer.java b/src/main/java/org/redkale/boot/NodeServer.java index 6646f4d25..ab3230cc3 100644 --- a/src/main/java/org/redkale/boot/NodeServer.java +++ b/src/main/java/org/redkale/boot/NodeServer.java @@ -14,7 +14,6 @@ import java.lang.reflect.*; import java.net.*; import java.nio.file.*; import java.util.*; -import java.util.AbstractMap.SimpleEntry; import java.util.concurrent.*; import java.util.function.*; import java.util.logging.*; @@ -212,66 +211,13 @@ public abstract class NodeServer { final ResourceFactory appResFactory = application.getResourceFactory(); final TransportFactory appSncpTranFactory = application.getSncpTransportFactory(); final AnyValue resources = application.config.getAnyValue("resources"); - final String confURI = appResFactory.find(RESNAME_APP_CONF, String.class); - final Map> cacheResource = new HashMap<>(); - final Map> dataResources = new HashMap<>(); - if (resources != null) { - for (AnyValue sourceConf : resources.getAnyValues("source")) { - try { - String classval = sourceConf.getValue("value"); - Class type = null; - if (classval == null || classval.isEmpty()) { - RedkaleClassLoader.putServiceLoader(CacheSourceProvider.class); - List providers = new ArrayList<>(); - Iterator it = ServiceLoader.load(CacheSourceProvider.class, serverClassLoader).iterator(); - while (it.hasNext()) { - CacheSourceProvider s = it.next(); - if (s != null) RedkaleClassLoader.putReflectionPublicConstructors(s.getClass(), s.getClass().getName()); - if (s != null && s.acceptsConf(sourceConf)) { - providers.add(s); - } - } - 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 (CacheSourceProvider provider : providers) { - type = provider.sourceClass(); - if (type != null) break; - } - } else { - type = serverClassLoader.loadClass(classval); - } - if (type == DataSource.class) { - type = DataMemorySource.class; - for (AnyValue itemConf : sourceConf.getAnyValues("property")) { - if (itemConf.getValue("name", "").contains(DataSources.JDBC_URL)) { - type = DataJdbcSource.class; - break; - } - } - } - if (!Service.class.isAssignableFrom(type)) { - logger.log(Level.SEVERE, "load application source resource, but not Service error: " + sourceConf); - } else if (CacheSource.class.isAssignableFrom(type)) { - cacheResource.put(sourceConf.getValue("name", ""), new SimpleEntry(type, sourceConf)); - } else if (DataSource.class.isAssignableFrom(type)) { - dataResources.put(sourceConf.getValue("name", ""), new SimpleEntry(type, sourceConf)); - } else { - logger.log(Level.SEVERE, "load application source resource, but not CacheSource error: " + sourceConf); - } - } catch (Exception e) { - logger.log(Level.SEVERE, "load application source resource error: " + sourceConf, e); - } - } - } + final String confURI = appResFactory.find(RESNAME_APP_CONF_DIR, String.class); //------------------------------------- 娉ㄥ唽 Resource -------------------------------------------------------- - resourceFactory.register((ResourceFactory rf, final Object src, String resourceName, Field field, final Object attachment) -> { + resourceFactory.register((ResourceFactory rf, String srcResourceName, final Object srcObj, String resourceName, Field field, final Object attachment) -> { try { Resource res = field.getAnnotation(Resource.class); if (res == null || !res.name().startsWith("properties.")) return; - if ((src instanceof Service) && Sncp.isRemote((Service) src)) return; //杩滅▼妯″紡涓嶅緱娉ㄥ叆 DataSource + if ((srcObj instanceof Service) && Sncp.isRemote((Service) srcObj)) return; //杩滅▼妯″紡涓嶅緱娉ㄥ叆 DataSource Class type = field.getType(); if (type != AnyValue.class && type != AnyValue[].class) return; Object resource = null; @@ -283,18 +229,18 @@ public abstract class NodeServer { resource = properties.getAnyValues(res.name().substring("properties.".length())); appResFactory.register(resourceName, AnyValue[].class, resource); } - field.set(src, resource); + field.set(srcObj, resource); } catch (Exception e) { logger.log(Level.SEVERE, "Resource inject error", e); } }, AnyValue.class, AnyValue[].class); //------------------------------------- 娉ㄥ唽 Local AutoLoad(false) Service -------------------------------------------------------- - resourceFactory.register((ResourceFactory rf, final Object src, String resourceName, Field field, final Object attachment) -> { + resourceFactory.register((ResourceFactory rf, String srcResourceName, final Object srcObj, String resourceName, Field field, final Object attachment) -> { Class resServiceType = Service.class; try { if (field.getAnnotation(Resource.class) == null) return; - if ((src instanceof Service) && Sncp.isRemote((Service) src)) return; //杩滅▼妯″紡涓嶅緱娉ㄥ叆 AutoLoad Service + if ((srcObj instanceof Service) && Sncp.isRemote((Service) srcObj)) return; //杩滅▼妯″紡涓嶅緱娉ㄥ叆 AutoLoad Service if (!Service.class.isAssignableFrom(field.getType())) return; resServiceType = (Class) field.getType(); if (resServiceType.getAnnotation(Local.class) == null) return; @@ -302,150 +248,56 @@ public abstract class NodeServer { if (al == null || al.value()) return; //ResourceFactory resfactory = (isSNCP() ? appResFactory : resourceFactory); - SncpClient client = src instanceof Service ? Sncp.getSncpClient((Service) src) : null; + SncpClient client = srcObj instanceof Service ? Sncp.getSncpClient((Service) srcObj) : null; final InetSocketAddress sncpAddr = client == null ? null : client.getClientAddress(); final Set groups = new HashSet<>(); Service service = Modifier.isFinal(resServiceType.getModifiers()) ? (Service) resServiceType.getConstructor().newInstance() : Sncp.createLocalService(serverClassLoader, resourceName, resServiceType, null, appResFactory, appSncpTranFactory, sncpAddr, groups, null); appResFactory.register(resourceName, resServiceType, service); - field.set(src, service); - rf.inject(service, self); // 缁欏叾鍙兘鍖呭惈@Resource鐨勫瓧娈佃祴鍊; + field.set(srcObj, service); + rf.inject(resourceName, service, self); // 缁欏叾鍙兘鍖呭惈@Resource鐨勫瓧娈佃祴鍊; if (!application.isCompileMode()) service.init(null); logger.info("[" + Thread.currentThread().getName() + "] Load Service(@Local @AutoLoad service = " + resServiceType.getSimpleName() + ", resourceName = '" + resourceName + "')"); } catch (Exception e) { - logger.log(Level.SEVERE, "[" + Thread.currentThread().getName() + "] Load @Local @AutoLoad(false) Service inject " + resServiceType + " to " + src + " error", e); + logger.log(Level.SEVERE, "[" + Thread.currentThread().getName() + "] Load @Local @AutoLoad(false) Service inject " + resServiceType + " to " + srcObj + " error", e); } }, Service.class); //------------------------------------- 娉ㄥ唽 DataSource -------------------------------------------------------- - resourceFactory.register((ResourceFactory rf, final Object src, String resourceName, Field field, final Object attachment) -> { + resourceFactory.register((ResourceFactory rf, String srcResourceName, final Object srcObj, String resourceName, Field field, final Object attachment) -> { try { if (field.getAnnotation(Resource.class) == null) return; - if ((src instanceof Service) && Sncp.isRemote((Service) src)) return; //杩滅▼妯″紡涓嶅緱娉ㄥ叆 DataSource - SimpleEntry resEntry = dataResources.get(resourceName); - AnyValue sourceConf = resEntry == null ? null : resEntry.getValue(); - DataSource source = null; - if (sourceConf != null) { - final Class sourceType = resEntry.getKey(); - if (sourceType == DataJdbcSource.class) { - source = DataSources.createDataSource(resourceName, sourceConf); - } else { - boolean can = false; - RedkaleClassLoader.putReflectionPublicConstructors(sourceType, sourceType.getName()); - for (Constructor cr : sourceType.getConstructors()) { - if (cr.getParameterCount() == 0) { - can = true; - break; - } - } - if (DataSource.class.isAssignableFrom(sourceType) && can) { // 蹇呴』鏈夌┖鏋勯犲嚱鏁 - if (Modifier.isFinal(sourceType.getModifiers()) || sourceType.getAnnotation(Local.class) != null) { - source = (DataSource) sourceType.getConstructor().newInstance(); - RedkaleClassLoader.putReflectionPublicConstructors(sourceType, sourceType.getName()); - } else { - final Service srcService = (Service) src; - SncpClient client = Sncp.getSncpClient(srcService); - final InetSocketAddress sncpAddr = client == null ? null : client.getClientAddress(); - final Set groups = new HashSet<>(); - source = (DataSource) Sncp.createLocalService(serverClassLoader, resourceName, sourceType, client == null ? null : client.getMessageAgent(), appResFactory, appSncpTranFactory, sncpAddr, groups, Sncp.getConf(srcService)); - } - } - } - } - if (source == null) { - source = DataSources.createDataSource(confURI, resourceName); //浠巔ersistence.xml閰嶇疆涓垱寤 - } - - RedkaleClassLoader.putReflectionPublicConstructors(source.getClass(), source.getClass().getName()); - application.dataSources.add(source); - ResourceType rt = source.getClass().getAnnotation(ResourceType.class); - if (rt != null && rt.value() != DataSource.class) { - appResFactory.register(resourceName, rt.value(), source); - } else if (source instanceof SearchSource) { - appResFactory.register(resourceName, SearchSource.class, source); - } - appResFactory.register(resourceName, DataSource.class, source); - - field.set(src, source); - rf.inject(source, self); // 缁橝syncGroup鍜屽叾浠朄Resource鐨勫瓧娈佃祴鍊; - //NodeServer.this.watchFactory.inject(src); - if (!application.isCompileMode() && source instanceof Service) ((Service) source).init(sourceConf); - logger.info("[" + Thread.currentThread().getName() + "] Load DataSource (type = " + source.getClass().getSimpleName() + ", resourceName = '" + resourceName + "')"); + if ((srcObj instanceof Service) && Sncp.isRemote((Service) srcObj)) return; //杩滅▼妯″紡涓嶅緱娉ㄥ叆 DataSource + DataSource source = application.loadDataSource(resourceName, false); + field.set(srcObj, source); } catch (Exception e) { - logger.log(Level.SEVERE, "[" + Thread.currentThread().getName() + "] DataSource inject to " + src + " error", e); + logger.log(Level.SEVERE, "[" + Thread.currentThread().getName() + "] DataSource inject to " + srcObj + " error", e); } }, DataSource.class); //------------------------------------- 娉ㄥ唽 CacheSource -------------------------------------------------------- - resourceFactory.register(new ResourceFactory.ResourceLoader() { + resourceFactory.register(new ResourceTypeLoader() { @Override - public void load(ResourceFactory rf, final Object src, final String resourceName, Field field, final Object attachment) { + public void load(ResourceFactory rf, String srcResourceName, final Object srcObj, final String resourceName, Field field, final Object attachment) { try { if (field.getAnnotation(Resource.class) == null) return; - if (!(src instanceof Service)) throw new RuntimeException("CacheSource must be inject in Service, cannot " + src); - if ((src instanceof Service) && Sncp.isRemote((Service) src)) return; //杩滅▼妯″紡涓嶉渶瑕佹敞鍏 CacheSource - final Service srcService = (Service) src; + if (!(srcObj instanceof Service)) throw new RuntimeException("CacheSource must be inject in Service, cannot " + srcObj); + if ((srcObj instanceof Service) && Sncp.isRemote((Service) srcObj)) return; //杩滅▼妯″紡涓嶉渶瑕佹敞鍏 CacheSource + final Service srcService = (Service) srcObj; SncpClient client = Sncp.getSncpClient(srcService); final InetSocketAddress sncpAddr = client == null ? null : client.getClientAddress(); - SimpleEntry resEntry = cacheResource.get(resourceName); - AnyValue sourceConf = resEntry == null ? null : resEntry.getValue(); - if (sourceConf == null) { - SimpleEntry resEntry2 = dataResources.get(resourceName); - sourceConf = resEntry2 == null ? null : resEntry2.getValue(); - } - Class sourceType0 = CacheMemorySource.class; - if (sourceConf != null) { - String classval = sourceConf.getValue("value"); - if (classval == null || classval.isEmpty()) { - RedkaleClassLoader.putServiceLoader(CacheSourceProvider.class); - List providers = new ArrayList<>(); - Iterator it = ServiceLoader.load(CacheSourceProvider.class, serverClassLoader).iterator(); - while (it.hasNext()) { - CacheSourceProvider s = it.next(); - if (s != null) RedkaleClassLoader.putReflectionPublicConstructors(s.getClass(), s.getClass().getName()); - if (s != null && s.acceptsConf(sourceConf)) { - providers.add(s); - } - } - 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 (CacheSourceProvider provider : providers) { - sourceType0 = provider.sourceClass(); - if (sourceType0 != null) break; - } - } else { - sourceType0 = serverClassLoader.loadClass(classval); - } - } - final Class sourceType = sourceType0; - Object source = null; - if (CacheSource.class.isAssignableFrom(sourceType)) { // CacheSource - RedkaleClassLoader.putReflectionPublicConstructors(sourceType, sourceType.getName()); - source = sourceType == CacheMemorySource.class ? new CacheMemorySource(resourceName) - : (Modifier.isFinal(sourceType.getModifiers()) || sourceType.getAnnotation(Local.class) != null) ? sourceType.getConstructor().newInstance() - : (CacheSource) Sncp.createLocalService(serverClassLoader, resourceName, sourceType, client == null ? null : client.getMessageAgent(), appResFactory, appSncpTranFactory, sncpAddr, null, Sncp.getConf(srcService)); - Type genericType = field.getGenericType(); - application.cacheSources.add((CacheSource) source); - appResFactory.register(resourceName, CacheSource.class, source); - if (genericType != CacheSource.class) { - appResFactory.register(resourceName, genericType, source); - } - } - field.set(src, source); - rf.inject(source, self); // - if (!application.isCompileMode() && source instanceof Service) ((Service) source).init(sourceConf); + final boolean ws = (srcObj instanceof org.redkale.net.http.WebSocketNodeService) && sncpAddr != null; + CacheSource source = application.loadCacheSource(resourceName, ws); + field.set(srcObj, source); - if ((src instanceof org.redkale.net.http.WebSocketNodeService) && sncpAddr != null) { //鍙湁WebSocketNodeService鐨勬湇鍔℃墠闇瑕佺粰SNCP鏈嶅姟娉ㄥ叆CacheMemorySource + if (ws) { //鍙湁WebSocketNodeService鐨勬湇鍔℃墠闇瑕佺粰SNCP鏈嶅姟娉ㄥ叆CacheMemorySource NodeSncpServer sncpServer = application.findNodeSncpServer(sncpAddr); if (source != null && source.getClass().getAnnotation(Local.class) == null) { //鏈湴妯″紡鐨凷ervice涓嶇敓鎴怱ncpServlet sncpServer.getSncpServer().addSncpServlet((Service) source); } //logger.info("[" + Thread.currentThread().getName() + "] Load Service " + source); } - logger.info("[" + Thread.currentThread().getName() + "] Load CacheSource (type = " + source.getClass().getSimpleName() + ", resourceName = '" + resourceName + "')"); + logger.info("[" + Thread.currentThread().getName() + "] Load CacheSource (type = " + (source == null ? null : source.getClass().getSimpleName()) + ", resourceName = '" + resourceName + "')"); } catch (Exception e) { logger.log(Level.SEVERE, "DataSource inject error", e); } @@ -458,28 +310,28 @@ public abstract class NodeServer { }, CacheSource.class); //------------------------------------- 娉ㄥ唽 WebSocketNode -------------------------------------------------------- - resourceFactory.register(new ResourceFactory.ResourceLoader() { + resourceFactory.register(new ResourceTypeLoader() { @Override - public void load(ResourceFactory rf, final Object src, final String resourceName, Field field, final Object attachment) { + public void load(ResourceFactory rf, String srcResourceName, final Object srcObj, final String resourceName, Field field, final Object attachment) { try { if (field.getAnnotation(Resource.class) == null) return; - if ((src instanceof Service) && Sncp.isRemote((Service) src)) return; //杩滅▼妯″紡涓嶉渶瑕佹敞鍏 WebSocketNode + if ((srcObj instanceof Service) && Sncp.isRemote((Service) srcObj)) return; //杩滅▼妯″紡涓嶉渶瑕佹敞鍏 WebSocketNode Service nodeService = (Service) rf.find(resourceName, WebSocketNode.class); if (nodeService == null) { final HashSet groups = new HashSet<>(); if (groups.isEmpty() && isSNCP() && NodeServer.this.sncpGroup != null) groups.add(NodeServer.this.sncpGroup); - nodeService = Sncp.createLocalService(serverClassLoader, resourceName, org.redkale.net.http.WebSocketNodeService.class, Sncp.getMessageAgent((Service) src), application.getResourceFactory(), application.getSncpTransportFactory(), NodeServer.this.sncpAddress, groups, (AnyValue) null); + nodeService = Sncp.createLocalService(serverClassLoader, resourceName, org.redkale.net.http.WebSocketNodeService.class, Sncp.getMessageAgent((Service) srcObj), application.getResourceFactory(), application.getSncpTransportFactory(), NodeServer.this.sncpAddress, groups, (AnyValue) null); (isSNCP() ? appResFactory : resourceFactory).register(resourceName, WebSocketNode.class, nodeService); ((org.redkale.net.http.WebSocketNodeService) nodeService).setName(resourceName); } - resourceFactory.inject(nodeService, self); - MessageAgent messageAgent = Sncp.getMessageAgent((Service) src); + resourceFactory.inject(resourceName, nodeService, self); + MessageAgent messageAgent = Sncp.getMessageAgent((Service) srcObj); if (messageAgent != null && Sncp.getMessageAgent(nodeService) == null) Sncp.setMessageAgent(nodeService, messageAgent); - field.set(src, nodeService); + field.set(srcObj, nodeService); if (Sncp.isRemote(nodeService)) { remoteServices.add(nodeService); } else { - rf.inject(nodeService); //鍔ㄦ佸姞杞界殑Service涔熷瓨鍦ㄦ寜闇鍔犺浇鐨勬敞鍏ヨ祫婧 + rf.inject(resourceName, nodeService); //鍔ㄦ佸姞杞界殑Service涔熷瓨鍦ㄦ寜闇鍔犺浇鐨勬敞鍏ヨ祫婧 localServices.add(nodeService); interceptorServices.add(nodeService); if (consumer != null) consumer.accept(null, nodeService); @@ -529,7 +381,7 @@ public abstract class NodeServer { || (this.sncpGroup == null && entry.isEmptyGroups()) //绌虹殑SNCP閰嶇疆 || serviceImplClass.getAnnotation(Local.class) != null;//鏈湴妯″紡 if (localed && (serviceImplClass.isInterface() || Modifier.isAbstract(serviceImplClass.getModifiers()))) continue; //鏈湴妯″紡涓嶈兘瀹炰緥鍖栨帴鍙e拰鎶借薄绫荤殑Service绫 - final ResourceFactory.ResourceLoader resourceLoader = (ResourceFactory rf, final Object src, final String resourceName, Field field, final Object attachment) -> { + final ResourceTypeLoader resourceLoader = (ResourceFactory rf, String srcResourceName, final Object srcObj, final String resourceName, Field field, final Object attachment) -> { try { if (SncpClient.parseMethod(serviceImplClass).isEmpty() && serviceImplClass.getAnnotation(Priority.class) == null) { //class娌℃湁鍙敤鐨勬柟娉曚笖娌℃湁鏍囪鍚姩浼樺厛绾х殑锛 閫氬父涓築aseService if (!serviceImplClass.getName().startsWith("org.redkale.") && !serviceImplClass.getSimpleName().contains("Base")) { @@ -545,7 +397,7 @@ public abstract class NodeServer { } Service service; - final boolean ws = src instanceof WebSocketServlet; + final boolean ws = srcObj instanceof WebSocketServlet; if (ws || localed) { //鏈湴妯″紡 service = Sncp.createLocalService(serverClassLoader, resourceName, serviceImplClass, agent, appResourceFactory, appSncpTransFactory, NodeServer.this.sncpAddress, groups, entry.getProperty()); } else { @@ -565,7 +417,7 @@ public abstract class NodeServer { remoteServices.add(service); if (agent != null) sncpRemoteAgents.put(agent.getName(), agent); } else { - if (field != null) rf.inject(service); //鍔ㄦ佸姞杞界殑Service涔熷瓨鍦ㄦ寜闇鍔犺浇鐨勬敞鍏ヨ祫婧 + if (field != null) rf.inject(resourceName, service); //鍔ㄦ佸姞杞界殑Service涔熷瓨鍦ㄦ寜闇鍔犺浇鐨勬敞鍏ヨ祫婧 localServices.add(service); interceptorServices.add(service); if (consumer != null) consumer.accept(agent, service); @@ -577,10 +429,12 @@ public abstract class NodeServer { } }; if (entry.isExpect()) { - ResourceType rty = entry.getType().getAnnotation(ResourceType.class); - resourceFactory.register(resourceLoader, rty == null ? entry.getType() : rty.value()); + Class t = ResourceFactory.getResourceType(entry.getType()); + if (resourceFactory.findResourceTypeLoader(t) == null) { + resourceFactory.register(resourceLoader, t); + } } else { - resourceLoader.load(resourceFactory, null, entry.getName(), null, false); + resourceLoader.load(resourceFactory, null, null, entry.getName(), null, false); } } @@ -591,10 +445,10 @@ public abstract class NodeServer { final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null; //---------------- inject ---------------- new ArrayList<>(localServices).forEach(y -> { - resourceFactory.inject(y, NodeServer.this); + resourceFactory.inject(Sncp.getResourceName(y), y, NodeServer.this); }); new ArrayList<>(remoteServices).forEach(y -> { - resourceFactory.inject(y, NodeServer.this); + resourceFactory.inject(Sncp.getResourceName(y), y, NodeServer.this); calcMaxLength(y); }); @@ -852,9 +706,9 @@ public abstract class NodeServer { server.shutdown(); } - public void command(String cmd) throws IOException { + public List command(String cmd, String[] params) throws IOException { final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null; - final boolean finest = logger.isLoggable(Level.FINEST); + List results = new ArrayList<>(); localServices.forEach(y -> { Set methods = new HashSet<>(); Class loop = y.getClass(); @@ -862,10 +716,23 @@ public abstract class NodeServer { for (Method m : loop.getMethods()) { Command c = m.getAnnotation(Command.class); if (c == null) continue; - if (Modifier.isStatic(m.getModifiers())) continue; - if (m.getReturnType() != void.class) continue; - if (m.getParameterCount() != 1) continue; - if (m.getParameterTypes()[0] != String.class) continue; + if (Modifier.isStatic(m.getModifiers())) { + logger.log(Level.WARNING, m + " is static on @Command"); + continue; + } + if (m.getParameterCount() != 1 && m.getParameterCount() != 2) { + logger.log(Level.WARNING, m + " parameter count = " + m.getParameterCount() + " on @Command"); + continue; + } + if (m.getParameterTypes()[0] != String.class) { + logger.log(Level.WARNING, m + " parameters[0] type is not String.class on @Command"); + continue; + } + if (m.getParameterCount() == 2 && m.getParameterTypes()[1] != String[].class) { + logger.log(Level.WARNING, m + " parameters[1] type is not String[].class on @Command"); + continue; + } + if (!c.value().isEmpty() && !c.value().equalsIgnoreCase(cmd)) continue; methods.add(m); } //} while ((loop = loop.getSuperclass()) != Object.class); @@ -875,7 +742,8 @@ public abstract class NodeServer { try { for (Method method : methods) { one = method; - method.invoke(y, cmd); + Object r = method.getParameterCount() == 2 ? method.invoke(y, cmd, params) : method.invoke(y, cmd); + if (r != null) results.add(r); } } catch (Exception ex) { logger.log(Level.SEVERE, one + " run error, cmd = " + cmd, ex); @@ -886,6 +754,7 @@ public abstract class NodeServer { } }); if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString()); + return results; } public T getServer() { diff --git a/src/main/java/org/redkale/boot/PropertiesAgent.java b/src/main/java/org/redkale/boot/PropertiesAgent.java new file mode 100644 index 000000000..2be09f36f --- /dev/null +++ b/src/main/java/org/redkale/boot/PropertiesAgent.java @@ -0,0 +1,26 @@ +/* + */ +package org.redkale.boot; + +import java.util.Properties; +import org.redkale.util.*; + +/** + * 閰嶇疆婧怉gent, 鍦╥nit鏂规硶鍐呴渶瑕佸疄鐜拌鍙栭厤缃俊鎭紝濡傛灉鏀寔閰嶇疆鏇存敼閫氱煡锛屼篃闇瑕佸湪init閲屽疄鐜扮洃鍚 + * + * + * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.7.0 + */ +public abstract class PropertiesAgent { + + public void compile(AnyValue conf) { + } + + public abstract void init(ResourceFactory factory, Properties appProperties, AnyValue conf); + + public abstract void destroy(AnyValue conf); +} diff --git a/src/main/java/org/redkale/cluster/CacheClusterAgent.java b/src/main/java/org/redkale/cluster/CacheClusterAgent.java index 4a158f75b..2b73c067f 100644 --- a/src/main/java/org/redkale/cluster/CacheClusterAgent.java +++ b/src/main/java/org/redkale/cluster/CacheClusterAgent.java @@ -37,24 +37,26 @@ public class CacheClusterAgent extends ClusterAgent implements Resourcable { protected ScheduledThreadPoolExecutor scheduler; - //鍙兘琚獺ttpMessageClient鐢ㄥ埌鐨勬湇鍔 key: servicename + //鍙兘琚獺ttpMessageClient鐢ㄥ埌鐨勬湇鍔 key: serviceName protected final ConcurrentHashMap> httpAddressMap = new ConcurrentHashMap<>(); - //鍙兘琚玬qtp鐢ㄥ埌鐨勬湇鍔 key: servicename + //鍙兘琚玬qtp鐢ㄥ埌鐨勬湇鍔 key: serviceName protected final ConcurrentHashMap> mqtpAddressMap = new ConcurrentHashMap<>(); @Override - public void init(AnyValue config) { - super.init(config); + public void init(ResourceFactory factory, AnyValue config) { + super.init(factory, 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; - } - } + this.ttls = config.getIntValue("ttls", 10); + if (this.ttls < 5) this.ttls = 10; + } + + @Override + public void setConfig(AnyValue config) { + super.setConfig(config); + this.sourceName = getSourceName(); } @Override @@ -63,15 +65,7 @@ public class CacheClusterAgent extends ClusterAgent implements Resourcable { } 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; + return config.getValue("source"); } @Override @@ -82,13 +76,7 @@ public class CacheClusterAgent extends ClusterAgent implements Resourcable { @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; + return config.getValue("source") != null; } @Override @@ -120,22 +108,22 @@ public class CacheClusterAgent extends ClusterAgent implements Resourcable { protected void loadMqtpAddressHealth() { List keys = source.queryKeysStartsWith("cluster.mqtp:"); - keys.forEach(servicename -> { + keys.forEach(serviceName -> { try { - this.mqtpAddressMap.put(servicename, queryAddress(servicename).get(3, TimeUnit.SECONDS)); + this.mqtpAddressMap.put(serviceName, queryAddress(serviceName).get(3, TimeUnit.SECONDS)); } catch (Exception e) { - logger.log(Level.SEVERE, "loadMqtpAddressHealth check " + servicename + " error", e); + logger.log(Level.SEVERE, "loadMqtpAddressHealth check " + serviceName + " error", e); } }); } protected void checkHttpAddressHealth() { try { - this.httpAddressMap.keySet().stream().forEach(servicename -> { + this.httpAddressMap.keySet().stream().forEach(serviceName -> { try { - this.httpAddressMap.put(servicename, queryAddress(servicename).get(3, TimeUnit.SECONDS)); + this.httpAddressMap.put(serviceName, queryAddress(serviceName).get(3, TimeUnit.SECONDS)); } catch (Exception e) { - logger.log(Level.SEVERE, "checkHttpAddressHealth check " + servicename + " error", e); + logger.log(Level.SEVERE, "checkHttpAddressHealth check " + serviceName + " error", e); } }); } catch (Exception ex) { @@ -148,10 +136,10 @@ public class CacheClusterAgent extends ClusterAgent implements Resourcable { newaddr.addr = entry.address; newaddr.nodeid = this.nodeid; newaddr.time = System.currentTimeMillis(); - source.hset(entry.checkname, entry.checkid, AddressEntry.class, newaddr); + source.hset(entry.checkName, entry.checkid, AddressEntry.class, newaddr); } - @Override //鑾峰彇MQTP鐨凥TTP杩滅▼鏈嶅姟鐨勫彲鐢╥p鍒楄〃, key = servicename鐨勫悗鍗婃 + @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) + ":"; @@ -162,22 +150,22 @@ public class CacheClusterAgent extends ClusterAgent implements Resourcable { @Override //鑾峰彇HTTP杩滅▼鏈嶅姟鐨勫彲鐢╥p鍒楄〃 public CompletableFuture> queryHttpAddress(String protocol, String module, String resname) { - final String servicename = generateHttpServiceName(protocol, module, resname); - Collection rs = httpAddressMap.get(servicename); + 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 queryAddress(serviceName).thenApply(t -> { + httpAddressMap.put(serviceName, t); return t; }); } @Override protected CompletableFuture> queryAddress(final ClusterEntry entry) { - return queryAddress(entry.servicename); + return queryAddress(entry.serviceName); } - private CompletableFuture> queryAddress(final String servicename) { - final CompletableFuture> future = source.hmapAsync(servicename, AddressEntry.class, 0, 10000); + 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) -> { @@ -188,9 +176,9 @@ public class CacheClusterAgent extends ClusterAgent implements Resourcable { } protected boolean isApplicationHealth() { - String servicename = generateApplicationServiceName(); + String serviceName = generateApplicationServiceName(); String serviceid = generateApplicationServiceId(); - AddressEntry entry = (AddressEntry) source.hget(servicename, serviceid, AddressEntry.class); + AddressEntry entry = (AddressEntry) source.hget(serviceName, serviceid, AddressEntry.class); return entry != null && (System.currentTimeMillis() - entry.time) / 1000 < ttls; } @@ -210,18 +198,18 @@ public class CacheClusterAgent extends ClusterAgent implements Resourcable { deregister(application); String serviceid = generateApplicationServiceId(); - String servicename = generateApplicationServiceName(); + 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); + source.hset(serviceName, serviceid, AddressEntry.class, entry); } @Override public void deregister(Application application) { - String servicename = generateApplicationServiceName(); - source.remove(servicename); + String serviceName = generateApplicationServiceName(); + source.remove(serviceName); } @Override @@ -233,7 +221,7 @@ public class CacheClusterAgent extends ClusterAgent implements Resourcable { entry.addr = clusterEntry.address; entry.nodeid = this.nodeid; entry.time = System.currentTimeMillis(); - source.hset(clusterEntry.servicename, clusterEntry.serviceid, AddressEntry.class, entry); + source.hset(clusterEntry.serviceName, clusterEntry.serviceid, AddressEntry.class, entry); return clusterEntry; } @@ -243,24 +231,24 @@ public class CacheClusterAgent extends ClusterAgent implements Resourcable { } protected void deregister(NodeServer ns, String protocol, Service service, boolean realcanceled) { - String servicename = generateServiceName(ns, protocol, service); + 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)) { + 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)) { + if (entry.serviceName.equals(serviceName) && entry.serviceid.equals(serviceid)) { currEntry = entry; break; } } } - source.hremove(servicename, serviceid); + source.hremove(serviceName, serviceid); if (realcanceled && currEntry != null) currEntry.canceled = true; if (!"mqtp".equals(protocol) && currEntry != null && currEntry.submqtp) { deregister(ns, "mqtp", service, realcanceled); diff --git a/src/main/java/org/redkale/cluster/ClusterAgent.java b/src/main/java/org/redkale/cluster/ClusterAgent.java index d1af825d3..a201e531c 100644 --- a/src/main/java/org/redkale/cluster/ClusterAgent.java +++ b/src/main/java/org/redkale/cluster/ClusterAgent.java @@ -6,13 +6,15 @@ package org.redkale.cluster; import java.lang.ref.WeakReference; -import java.net.InetSocketAddress; +import java.net.*; +import java.nio.charset.StandardCharsets; 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.ConvertDisabled; import org.redkale.convert.json.JsonConvert; import org.redkale.mq.MessageMultiConsumer; import org.redkale.net.*; @@ -60,7 +62,7 @@ public abstract class ClusterAgent { protected final ConcurrentHashMap remoteEntrys = new ConcurrentHashMap<>(); - public void init(AnyValue config) { + public void init(ResourceFactory factory, AnyValue config) { this.config = config; this.name = config.getValue("name", ""); this.waits = config.getBoolValue("waits", false); @@ -106,7 +108,7 @@ public abstract class ClusterAgent { if (localServices.isEmpty()) return; //娉ㄥ唽鏈湴妯″紡 for (Service service : localServices) { - if (!canRegister(protocol, service)) continue; + if (!canRegister(ns, protocol, service)) continue; ClusterEntry htentry = register(ns, protocol, service); localEntrys.put(htentry.serviceid, htentry); if (protocol.toLowerCase().startsWith("http")) { @@ -132,19 +134,21 @@ public abstract class ClusterAgent { public void deregister(NodeServer ns, String protocol, Set localServices, Set remoteServices) { //娉ㄩ攢鏈湴妯″紡 杩滅▼妯″紡涓嶆敞鍐 for (Service service : localServices) { - if (!canRegister(protocol, service)) continue; + if (!canRegister(ns, protocol, service)) continue; deregister(ns, protocol, service); } afterDeregister(ns, protocol); } - protected boolean canRegister(String protocol, Service service) { + protected boolean canRegister(NodeServer ns, 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; } + ClusterEntry entry = new ClusterEntry(ns, protocol, service); + if (entry.serviceName.trim().endsWith(serviceSeparator())) return false; return true; } @@ -167,7 +171,7 @@ public abstract class ClusterAgent { return 10; } - //鑾峰彇MQTP鐨凥TTP杩滅▼鏈嶅姟鐨勫彲鐢╥p鍒楄〃, key = servicename鐨勫悗鍗婃 + //鑾峰彇MQTP鐨凥TTP杩滅▼鏈嶅姟鐨勫彲鐢╥p鍒楄〃, key = serviceName鐨勫悗鍗婃 public abstract CompletableFuture>> queryMqtpAddress(String protocol, String module, String resname); //鑾峰彇HTTP杩滅▼鏈嶅姟鐨勫彲鐢╥p鍒楄〃 @@ -184,17 +188,25 @@ public abstract class ClusterAgent { //鏍煎紡: protocol:classtype-resourcename protected void updateSncpTransport(ClusterEntry entry) { - Service service = entry.serviceref.get(); + 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); + Sncp.updateTransport(service, transportFactory, Sncp.getResourceType(service).getName() + "-" + Sncp.getResourceName(service), entry.netProtocol, entry.address, null, addrs); + } + + protected String urlEncode(String value) { + return value == null ? null : URLEncoder.encode(value, StandardCharsets.UTF_8); } protected String generateApplicationServiceName() { - return "application" + (appName == null || appName.isEmpty() ? "" : ("." + appName)) + ".node" + this.nodeid; + return "application" + (appName == null || appName.isEmpty() ? "" : ("." + appName)) + ".node." + this.nodeid; } - protected String generateApplicationServiceId() { //涓巗ervicename鐩稿悓 + protected String generateApplicationServiceType() { + return "application.nodes"; + } + + protected String generateApplicationServiceId() { //涓巗erviceName鐩稿悓 return generateApplicationServiceName(); } @@ -206,9 +218,21 @@ public abstract class ClusterAgent { return "check-" + generateApplicationServiceId(); } + protected String generateApplicationHost() { + return this.appAddress.getHostString(); + } + + protected int generateApplicationPort() { + return this.appAddress.getPort(); + } + + protected String serviceSeparator() { + return "-"; + } + //涔熶細鎻愪緵缁橦ttpMessageClusterAgent閫傜敤 public String generateHttpServiceName(String protocol, String module, String resname) { - return protocol.toLowerCase() + ":" + module + (resname == null || resname.isEmpty() ? "" : ("-" + resname)); + return protocol.toLowerCase() + serviceSeparator() + module + (resname == null || resname.isEmpty() ? "" : ("-" + resname)); } //鏍煎紡: protocol:classtype-resourcename @@ -216,21 +240,21 @@ public abstract class ClusterAgent { 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)); + return protocol.toLowerCase() + serviceSeparator() + 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; + return protocol.toLowerCase() + serviceSeparator() + mmc.module() + serviceSeparator() + selfmodule; } - if (!Sncp.isSncpDyn(service)) return protocol.toLowerCase() + ":" + service.getClass().getName(); + if (!Sncp.isSncpDyn(service)) return protocol.toLowerCase() + serviceSeparator() + service.getClass().getName(); String resname = Sncp.getResourceName(service); - return protocol.toLowerCase() + ":" + Sncp.getResourceType(service).getName() + (resname.isEmpty() ? "" : ("-" + resname)); + return protocol.toLowerCase() + serviceSeparator() + 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; + return generateServiceName(ns, protocol, service) + serviceSeparator() + this.nodeid; } protected String generateCheckName(NodeServer ns, String protocol, Service service) { @@ -249,11 +273,6 @@ public abstract class ClusterAgent { return remoteEntrys; } - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } - public TransportFactory getTransportFactory() { return transportFactory; } @@ -296,19 +315,26 @@ public abstract class ClusterAgent { public class ClusterEntry { + //serviceName+nodeid涓轰富 鏈嶅姟鐨勫崟涓疄渚 public String serviceid; - public String servicename; + //浠ュ崗璁+Rest璧勬簮鍚嶄负涓 鏈嶅姟绫诲悕 + public String serviceName; + + public String serviceType; public String checkid; - public String checkname; + public String checkName; + //http or sncp or mqtp public String protocol; - public String netprotocol; + //TCP or UDP + public String netProtocol; - public WeakReference serviceref; + @ConvertDisabled + public WeakReference serviceRef; public InetSocketAddress address; @@ -318,9 +344,10 @@ public abstract class ClusterAgent { public ClusterEntry(NodeServer ns, String protocol, Service service) { this.serviceid = generateServiceId(ns, protocol, service); - this.servicename = generateServiceName(ns, protocol, service); + this.serviceName = generateServiceName(ns, protocol, service); this.checkid = generateCheckId(ns, protocol, service); - this.checkname = generateCheckName(ns, protocol, service); + this.checkName = generateCheckName(ns, protocol, service); + this.serviceType = Sncp.getServiceType(service).getName(); this.protocol = protocol; InetSocketAddress addr = ns.getSocketAddress(); String host = addr.getHostString(); @@ -329,9 +356,9 @@ public abstract class ClusterAgent { addr = new InetSocketAddress(host, addr.getPort()); } this.address = addr; - this.serviceref = new WeakReference(service); + this.serviceRef = new WeakReference(service); Server server = ns.getServer(); - this.netprotocol = server instanceof SncpServer ? ((SncpServer) server).getNetprotocol() : Transport.DEFAULT_NETPROTOCOL; + this.netProtocol = server instanceof SncpServer ? ((SncpServer) server).getNetprotocol() : Transport.DEFAULT_NETPROTOCOL; } @Override diff --git a/src/main/java/org/redkale/convert/AnyEncoder.java b/src/main/java/org/redkale/convert/AnyEncoder.java index b241f4502..57066bfca 100644 --- a/src/main/java/org/redkale/convert/AnyEncoder.java +++ b/src/main/java/org/redkale/convert/AnyEncoder.java @@ -9,7 +9,7 @@ import java.lang.reflect.Type; /** * 瀵逛笉鏄庣被鍨嬬殑瀵硅薄杩涜搴忓垪鍖栵紱 BSON搴忓垪鍖栨椂灏嗗璞$殑绫诲悕鍐欏叆Writer锛孞SON鍒欎笉鍐欏叆銆 - * + * * 璇︽儏瑙: https://redkale.org * * @author zhangjx @@ -46,4 +46,8 @@ public final class AnyEncoder implements Encodeable { return Object.class; } + @Override + public boolean specifyable() { + return false; + } } diff --git a/src/main/java/org/redkale/convert/ArrayDecoder.java b/src/main/java/org/redkale/convert/ArrayDecoder.java index 19ed88547..de1883099 100644 --- a/src/main/java/org/redkale/convert/ArrayDecoder.java +++ b/src/main/java/org/redkale/convert/ArrayDecoder.java @@ -7,6 +7,8 @@ package org.redkale.convert; import java.lang.reflect.*; import java.util.*; +import java.util.function.IntFunction; +import org.redkale.util.Creator; /** * 鏁扮粍鐨勫弽搴忓垪鍖栨搷浣滅被
@@ -30,6 +32,8 @@ public class ArrayDecoder implements Decodeable { protected final Decodeable componentDecoder; + protected final IntFunction componentArrayFunction; + protected volatile boolean inited = false; protected final Object lock = new Object(); @@ -52,6 +56,7 @@ public class ArrayDecoder implements Decodeable { } factory.register(type, this); this.componentDecoder = factory.loadDecoder(this.componentType); + this.componentArrayFunction = Creator.arrayFunction(this.componentClass); } finally { inited = true; synchronized (lock) { @@ -102,7 +107,7 @@ public class ArrayDecoder implements Decodeable { } } in.readArrayE(); - T[] rs = (T[]) Array.newInstance((Class) this.componentClass, result.size()); + T[] rs = this.componentArrayFunction.apply(result.size()); return result.toArray(rs); } diff --git a/src/main/java/org/redkale/convert/ArrayEncoder.java b/src/main/java/org/redkale/convert/ArrayEncoder.java index 8dadd3543..018edc396 100644 --- a/src/main/java/org/redkale/convert/ArrayEncoder.java +++ b/src/main/java/org/redkale/convert/ArrayEncoder.java @@ -29,7 +29,7 @@ public class ArrayEncoder implements Encodeable { protected final Encodeable componentEncoder; - protected final boolean subtypefinal; + protected final boolean subTypeFinal; protected volatile boolean inited = false; @@ -49,7 +49,7 @@ public class ArrayEncoder implements Encodeable { 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()); + this.subTypeFinal = (this.componentType instanceof Class) && Modifier.isFinal(((Class) this.componentType).getModifiers()); } finally { inited = true; synchronized (lock) { @@ -74,7 +74,8 @@ public class ArrayEncoder implements Encodeable { out.writeArrayE(); return; } - if (this.componentEncoder == null) { + Encodeable itemEncoder = this.componentEncoder; + if (itemEncoder == null) { if (!this.inited) { synchronized (lock) { try { @@ -85,8 +86,7 @@ public class ArrayEncoder implements Encodeable { } } } - Encodeable itemEncoder = this.componentEncoder; - if (subtypefinal) { + if (subTypeFinal) { if (out.writeArrayB(value.length, this, itemEncoder, value) < 0) { for (int i = 0;; i++) { writeMemberValue(out, member, itemEncoder, value[i], i); @@ -122,6 +122,11 @@ public class ArrayEncoder implements Encodeable { return type; } + @Override + public boolean specifyable() { + return false; + } + public Type getComponentType() { return componentType; } @@ -129,5 +134,4 @@ public class ArrayEncoder implements Encodeable { public Encodeable getComponentEncoder() { return componentEncoder; } - } diff --git a/src/main/java/org/redkale/convert/CollectionEncoder.java b/src/main/java/org/redkale/convert/CollectionEncoder.java index f294fd412..02469ef2b 100644 --- a/src/main/java/org/redkale/convert/CollectionEncoder.java +++ b/src/main/java/org/redkale/convert/CollectionEncoder.java @@ -96,6 +96,11 @@ public class CollectionEncoder implements Encodeable> { return type; } + @Override + public boolean specifyable() { + return false; + } + @Override public String toString() { return this.getClass().getSimpleName() + "{componentType:" + this.type + ", encoder:" + this.componentEncoder + "}"; diff --git a/src/main/java/org/redkale/convert/ConvertCoder.java b/src/main/java/org/redkale/convert/ConvertCoder.java new file mode 100644 index 000000000..bb158fc5d --- /dev/null +++ b/src/main/java/org/redkale/convert/ConvertCoder.java @@ -0,0 +1,77 @@ +/* + */ +package org.redkale.convert; + +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +/** + * 渚濋檮鍦╯etter銆乬etter鏂规硶銆佸瓧娈佃繘琛岀畝鍗曠殑閰嶇疆
+ * 浼樺厛浣跨敤coder瀛楁 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @since 2.7.0 + */ +@Inherited +@Documented +@Target({METHOD, FIELD}) +@Retention(RUNTIME) +@Repeatable(ConvertCoder.ConvertCoders.class) +public @interface ConvertCoder { + + /** + * 闇瑕佹寚瀹氱殑瀛楁绫诲瀷锛屾寚瀹氫簡coder瀛楁鍊煎垯鍙互涓嶈缃瀛楁 + * + * @return 瀛楁绫诲悕 + */ + Class column() default Object.class; + + /** + * 瑙f瀽/搴忓垪鍖栧畾鍒跺寲鐨凷impledCoder + * + * @return SimpledCoder绫 + */ + Class coder() default SimpledCoder.class; + + /** + * 搴忓垪鍖栧畾鍒跺寲鐨 Encodeable + * + * @return Encodeable 绫 + */ + Class encoder() default Encodeable.class; + + /** + * 鍙嶅簭鍒楀寲瀹氬埗鍖栫殑 Decodeable + * + * @return Decodeable 绫 + */ + Class decoder() default Decodeable.class; + + /** + * 瑙f瀽/搴忓垪鍖栧畾鍒跺寲鐨凾YPE + * + * @return JSON or BSON or ALL + */ + ConvertType type() default ConvertType.ALL; + + /** + * ConvertCoder 鐨勫鐢ㄧ被 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ + @Inherited + @Documented + @Target({METHOD, FIELD}) + @Retention(RUNTIME) + public static @interface ConvertCoders { + + ConvertCoder[] value(); + } +} diff --git a/src/main/java/org/redkale/convert/ConvertFactory.java b/src/main/java/org/redkale/convert/ConvertFactory.java index 4152bd357..14e9a8228 100644 --- a/src/main/java/org/redkale/convert/ConvertFactory.java +++ b/src/main/java/org/redkale/convert/ConvertFactory.java @@ -12,7 +12,7 @@ import java.net.*; import java.nio.ByteBuffer; import java.nio.channels.CompletionHandler; import java.util.*; -import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.*; import java.util.concurrent.atomic.*; import java.util.regex.Pattern; import java.util.stream.*; @@ -248,7 +248,10 @@ public abstract class ConvertFactory { if (type instanceof Class) { Class clazz = (Class) type; ConvertImpl ci = clazz.getAnnotation(ConvertImpl.class); - if (ci != null) { + if (ci != null && ci.value() != Object.class) { + if (!clazz.isAssignableFrom(ci.value())) { + throw new ConvertException("@" + ConvertImpl.class.getSimpleName() + ".value(" + ci.value() + ") must be " + clazz + "'s subclass"); + } if (!Modifier.isAbstract(clazz.getModifiers()) && !Modifier.isInterface(clazz.getModifiers())) { throw new ConvertException("@" + ConvertImpl.class.getSimpleName() + " must at interface or abstract class, but " + clazz + " not"); } @@ -270,6 +273,10 @@ public abstract class ConvertFactory { return new ObjectDecoder(type); } + protected Decodeable createMultiImplDecoder(Class[] types) { + return null; + } + protected ObjectEncoder createObjectEncoder(Type type) { return new ObjectEncoder(type); } @@ -401,7 +408,9 @@ public abstract class ConvertFactory { 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鍚 + if (!(fname.startsWith("is") && fname.length() > 2) + && !(fname.startsWith("get") && fname.length() > 3) + && !(fname.startsWith("set") && fname.length() > 3)) 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); @@ -482,6 +491,175 @@ public abstract class ConvertFactory { } } + ConvertFactory columnFactory(Class type, ConvertCoder[] coders, boolean encode) { + if (coders == null || coders.length < 1) return this; + final ConvertType ct = this.getConvertType(); + List encoderList = null; + List decoderList = null; + Class readerOrWriterClass = (Class) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[encode ? 1 : 0]; + for (ConvertCoder ann : coders) { + if (!ann.type().contains(ct)) continue; + SimpledCoder coder = null; + Class clazz1 = ann.coder(); + if (clazz1 != SimpledCoder.class) { + try { + boolean skip = false; + RedkaleClassLoader.putReflectionPublicMethods(clazz1.getName()); + for (Method method : clazz1.getMethods()) { + if (method.isBridge()) continue; + if (encode) { + if ("convertTo".equals(method.getName()) && method.getParameterCount() == 2 && Writer.class.isAssignableFrom(method.getParameterTypes()[0])) { + skip = !method.getParameterTypes()[0].isAssignableFrom(readerOrWriterClass); + break; + } + } else { + if ("convertFrom".equals(method.getName()) && method.getParameterCount() == 1 && Reader.class.isAssignableFrom(method.getParameterTypes()[0])) { + skip = !method.getParameterTypes()[0].isAssignableFrom(readerOrWriterClass); + break; + } + } + } + if (skip) continue; + Field instanceField = clazz1.getField("instance"); + if (Modifier.isStatic(instanceField.getModifiers()) && instanceField.getType() == clazz1) { + RedkaleClassLoader.putReflectionField(clazz1.getName(), instanceField); + coder = (SimpledCoder) instanceField.get(null); + } + } catch (Throwable t) { + } + if (coder == null) { + try { + coder = (SimpledCoder) clazz1.getConstructor().newInstance(); + RedkaleClassLoader.putReflectionPublicConstructors(clazz1, clazz1.getName()); + } catch (Throwable t) { + t.printStackTrace(); + continue; + } + } + if (encode) { + if (encoderList == null) encoderList = new ArrayList<>(); + encoderList.add(coder); + } else { + if (decoderList == null) decoderList = new ArrayList<>(); + decoderList.add(coder); + } + } + if (coder == null) { + Class colType = type; + if (ann.column() != Object.class) colType = ann.column(); + if (encode) { + Class clazz2 = ann.encoder(); + if (clazz2 != Encodeable.class) { + try { + boolean skip = false; + RedkaleClassLoader.putReflectionPublicMethods(clazz2.getName()); + for (Method method : clazz2.getMethods()) { + if (method.isBridge()) continue; + if ("convertTo".equals(method.getName()) && method.getParameterCount() == 2 && Writer.class.isAssignableFrom(method.getParameterTypes()[0])) { + skip = !method.getParameterTypes()[0].isAssignableFrom(readerOrWriterClass); + break; + } + } + if (skip) continue; + Encodeable encoder = null; + Constructor constructor = clazz2.getConstructors()[0]; + Parameter[] params = constructor.getParameters(); + Class[] paramTypes = new Class[params.length]; + for (int i = 0; i < paramTypes.length; i++) { + paramTypes[i] = params[i].getType(); + } + if (params.length == 0) { + encoder = (Encodeable) constructor.newInstance(); + } else if (params.length == 1) { + if (paramTypes[0] != Type.class) throw new RuntimeException(clazz2 + " not found public empty-parameter Constructor"); + encoder = (Encodeable) constructor.newInstance(colType); + } else if (params.length == 2) { + if (paramTypes[0] == ConvertFactory.class && paramTypes[1] == Type.class) { + encoder = (Encodeable) constructor.newInstance(this, colType); + } else if (paramTypes[0] == Type.class && paramTypes[1] == ConvertFactory.class) { + encoder = (Encodeable) constructor.newInstance(colType, this); + } else { + throw new RuntimeException(clazz2 + " not found public empty-parameter Constructor"); + } + } else { + throw new RuntimeException(clazz2 + " not found public empty-parameter Constructor"); + } + RedkaleClassLoader.putReflectionPublicConstructors(clazz2, clazz2.getName()); + if (encoderList == null) encoderList = new ArrayList<>(); + encoderList.add(encoder); + } catch (Throwable t) { + t.printStackTrace(); + continue; + } + } + } else { + Class clazz2 = ann.decoder(); + if (clazz2 != Decodeable.class) { + try { + boolean skip = false; + RedkaleClassLoader.putReflectionPublicMethods(clazz2.getName()); + for (Method method : clazz2.getMethods()) { + if (method.isBridge()) continue; + if ("convertFrom".equals(method.getName()) && method.getParameterCount() == 1 && Reader.class.isAssignableFrom(method.getParameterTypes()[0])) { + skip = !method.getParameterTypes()[0].isAssignableFrom(readerOrWriterClass); + break; + } + } + if (skip) continue; + Decodeable decoder = null; + Constructor constructor = clazz2.getConstructors()[0]; + Parameter[] params = constructor.getParameters(); + Class[] paramTypes = new Class[params.length]; + for (int i = 0; i < paramTypes.length; i++) { + paramTypes[i] = params[i].getType(); + } + if (params.length == 0) { + decoder = (Decodeable) constructor.newInstance(); + } else if (params.length == 1) { + if (paramTypes[0] != Type.class) throw new RuntimeException(clazz2 + " not found public empty-parameter Constructor"); + decoder = (Decodeable) constructor.newInstance(colType); + } else if (params.length == 2) { + if (paramTypes[0] == ConvertFactory.class && paramTypes[1] == Type.class) { + decoder = (Decodeable) constructor.newInstance(this, colType); + } else if (paramTypes[0] == Type.class && paramTypes[1] == ConvertFactory.class) { + decoder = (Decodeable) constructor.newInstance(colType, this); + } else { + throw new RuntimeException(clazz2 + " not found public empty-parameter Constructor"); + } + } else { + throw new RuntimeException(clazz2 + " not found public empty-parameter Constructor"); + } + RedkaleClassLoader.putReflectionPublicConstructors(clazz2, clazz2.getName()); + if (decoderList == null) decoderList = new ArrayList<>(); + decoderList.add(decoder); + } catch (Throwable t) { + t.printStackTrace(); + continue; + } + } + } + } + } + if (encoderList == null && decoderList == null) return this; + ConvertFactory child = createChild(); + if (encode) { + for (Encodeable item : encoderList) { + child.register(item.getType(), item); + if (item instanceof ObjectEncoder) { + ((ObjectEncoder) item).init(child); + } + } + } else { + for (Decodeable item : decoderList) { + child.register(item.getType(), item); + if (item instanceof ObjectDecoder) { + ((ObjectDecoder) item).init(child); + } + } + } + return child; + } + private Class findEntityAlias(String name) { Class clazz = entitys.get(name); return parent == null ? clazz : parent.findEntityAlias(name); @@ -600,8 +778,8 @@ public abstract class ConvertFactory { } public final void reloadCoder(final Type type, final Class clazz) { - this.register(type, this.createDecoder(type, clazz)); - this.register(type, this.createEncoder(type, clazz)); + this.register(type, this.createDecoder(type, clazz, false)); + this.register(type, this.createEncoder(type, clazz, false)); } public final void register(final Class clazz, final Creator creator) { @@ -717,10 +895,14 @@ public abstract class ConvertFactory { throw new ConvertException("not support the type (" + type + ")"); } //姝ゅ涓嶈兘鍐峟indDecoder锛屽惁鍒檛ype涓巆lass涓嶄竴鑷, 濡: RetResult 鍜 RetResult - return createDecoder(type, clazz); + return createDecoder(type, clazz, false); } public final Decodeable createDecoder(final Type type) { + return createDecoder(type, false); + } + + public final Decodeable createDecoder(final Type type, boolean skipCustomMethod) { Class clazz; if (type instanceof ParameterizedType) { final ParameterizedType pts = (ParameterizedType) type; @@ -730,10 +912,10 @@ public abstract class ConvertFactory { } else { throw new ConvertException("not support the type (" + type + ")"); } - return createDecoder(type, clazz); + return createDecoder(type, clazz, skipCustomMethod); } - private Decodeable createDecoder(final Type type, final Class clazz) { + private Decodeable createDecoder(final Type type, final Class clazz, boolean skipCustomMethod) { Decodeable decoder = null; ObjectDecoder od = null; if (clazz.isEnum()) { @@ -756,25 +938,47 @@ public abstract class ConvertFactory { || 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 (!skipCustomMethod) { + for (Class subclazz : getSuperClasses(clazz)) { + for (final Method method : subclazz.getDeclaredMethods()) { + if (!Modifier.isStatic(method.getModifiers())) continue; + Class[] paramTypes = method.getParameterTypes(); + if (paramTypes.length != 1 && paramTypes.length != 2) continue; + if (paramTypes[0] != ConvertFactory.class && paramTypes[0] != this.getClass()) continue; + if (paramTypes.length == 2 && paramTypes[1] != Class.class && paramTypes[1] != Type.class) continue; + if (!Decodeable.class.isAssignableFrom(method.getReturnType())) continue; + if (Modifier.isPrivate(method.getModifiers()) && subclazz != clazz) continue; //澹版槑private鐨勫彧鑳借鑷韩绫讳娇鐢 + try { + method.setAccessible(true); + simpleCoder = (Decodeable) (paramTypes.length == 2 ? (paramTypes[1] == Type.class ? method.invoke(null, this, type) : method.invoke(null, this, clazz)) : method.invoke(null, this)); + RedkaleClassLoader.putReflectionDeclaredMethods(subclazz.getName()); + RedkaleClassLoader.putReflectionMethod(subclazz.getName(), method); + break; + } catch (Exception e) { + e.printStackTrace(); + } + } + if (simpleCoder != null) break; } } if (simpleCoder == null) { - Type impl = formatObjectType(type); - od = createObjectDecoder(impl); - decoder = od; + if (type instanceof Class) { + Class typeclz = (Class) type; + ConvertImpl ci = typeclz.getAnnotation(ConvertImpl.class); + if (ci != null && ci.types().length > 0) { + for (Class sub : ci.types()) { + if (!typeclz.isAssignableFrom(sub)) { + throw new ConvertException("@" + ConvertImpl.class.getSimpleName() + ".types(" + sub + ") must be " + typeclz + "'s subclass"); + } + } + decoder = createMultiImplDecoder(ci.types()); + } + } + if (decoder == null) { + Type impl = formatObjectType(type); + od = createObjectDecoder(impl); + decoder = od; + } } else { decoder = simpleCoder; } @@ -807,10 +1011,14 @@ public abstract class ConvertFactory { throw new ConvertException("not support the type (" + type + ")"); } //姝ゅ涓嶈兘鍐峟indEncoder锛屽惁鍒檛ype涓巆lass涓嶄竴鑷, 濡: RetResult 鍜 RetResult - return createEncoder(type, clazz); + return createEncoder(type, clazz, false); } public final Encodeable createEncoder(final Type type) { + return createEncoder(type, false); + } + + public final Encodeable createEncoder(final Type type, boolean skipCustomMethod) { Class clazz; if (type instanceof ParameterizedType) { final ParameterizedType pts = (ParameterizedType) type; @@ -820,10 +1028,10 @@ public abstract class ConvertFactory { } else { throw new ConvertException("not support the type (" + type + ")"); } - return createEncoder(type, clazz); + return createEncoder(type, clazz, skipCustomMethod); } - private Encodeable createEncoder(final Type type, final Class clazz) { + private Encodeable createEncoder(final Type type, final Class clazz, boolean skipCustomMethod) { Encodeable encoder = null; ObjectEncoder oe = null; if (clazz.isEnum()) { @@ -843,19 +1051,27 @@ public abstract class ConvertFactory { } 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 (!skipCustomMethod) { + for (Class subclazz : getSuperClasses(clazz)) { + for (final Method method : subclazz.getDeclaredMethods()) { + if (!Modifier.isStatic(method.getModifiers())) continue; + Class[] paramTypes = method.getParameterTypes(); + if (paramTypes.length != 1 && paramTypes.length != 2) continue; + if (paramTypes[0] != ConvertFactory.class && paramTypes[0] != this.getClass()) continue; + if (paramTypes.length == 2 && paramTypes[1] != Class.class && paramTypes[1] != Type.class) continue; + if (!Encodeable.class.isAssignableFrom(method.getReturnType())) continue; + if (Modifier.isPrivate(method.getModifiers()) && subclazz != clazz) continue; //澹版槑private鐨勫彧鑳借鑷韩绫讳娇鐢 + try { + method.setAccessible(true); + simpleCoder = (Encodeable) (paramTypes.length == 2 ? (paramTypes[1] == Type.class ? method.invoke(null, this, type) : method.invoke(null, this, clazz)) : method.invoke(null, this)); + RedkaleClassLoader.putReflectionDeclaredMethods(subclazz.getName()); + RedkaleClassLoader.putReflectionMethod(subclazz.getName(), method); + break; + } catch (Exception e) { + e.printStackTrace(); + } + } + if (simpleCoder != null) break; } } if (simpleCoder == null) { @@ -876,4 +1092,18 @@ public abstract class ConvertFactory { } + private Set getSuperClasses(final Class clazz) { + Set set = new LinkedHashSet<>(); + set.add(clazz); + Class recursClass = clazz; + while ((recursClass = recursClass.getSuperclass()) != null) { + if (recursClass == Object.class) break; + set.addAll(getSuperClasses(recursClass)); + } + for (Class sub : clazz.getInterfaces()) { + set.addAll(getSuperClasses(sub)); + } + return set; + } + } diff --git a/src/main/java/org/redkale/convert/ConvertImpl.java b/src/main/java/org/redkale/convert/ConvertImpl.java index e6a216cee..5c6e6f59c 100644 --- a/src/main/java/org/redkale/convert/ConvertImpl.java +++ b/src/main/java/org/redkale/convert/ConvertImpl.java @@ -19,18 +19,18 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME; * public String getName(); * } * - * + * * public class OneImpl implements OneEntity { * private String name; * public String getName(){return name;} * public void setName(String name){this.name=name;} * } - * + * * * String json = "{'name':'hello'}"; - * OneEntity one = JsonConvert.root.convertFrom(OneEntity.class, json); + * OneEntity one = JsonConvert.root().convertFrom(OneEntity.class, json); * //one instanceof OneImpl - * + * * *

* 璇︽儏瑙: https://redkale.org @@ -38,7 +38,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME; * @author zhangjx * @since 2.5.0 */ -@Inherited +//涓瀹氫笉鑳芥爣璁癐nherited @Documented @Target({TYPE}) @Retention(RUNTIME) @@ -49,5 +49,12 @@ public @interface ConvertImpl { * * @return String */ - Class value(); + Class value() default Object.class; + + /** + * 瀹炵幇绫荤殑闆嗗悎 + * + * @return Class[] + */ + Class[] types() default {}; } diff --git a/src/main/java/org/redkale/convert/DeMember.java b/src/main/java/org/redkale/convert/DeMember.java index 96fede608..93acef646 100644 --- a/src/main/java/org/redkale/convert/DeMember.java +++ b/src/main/java/org/redkale/convert/DeMember.java @@ -88,26 +88,26 @@ public final class DeMember { this.decoder = decoder; } - public static DeMember create(final ConvertFactory factory, final Class clazz, final String fieldname) { + public static DeMember create(final ConvertFactory factory, final Class clazz, final String fieldName) { try { - Field field = clazz.getDeclaredField(fieldname); + 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) { + 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); + 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 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) { diff --git a/src/main/java/org/redkale/convert/MapEncoder.java b/src/main/java/org/redkale/convert/MapEncoder.java index 53f5b0f40..3da1c978b 100644 --- a/src/main/java/org/redkale/convert/MapEncoder.java +++ b/src/main/java/org/redkale/convert/MapEncoder.java @@ -96,6 +96,11 @@ public class MapEncoder implements Encodeable> { return type; } + @Override + public boolean specifyable() { + return false; + } + public Type getKeyType() { return keyEncoder == null ? null : keyEncoder.getType(); } diff --git a/src/main/java/org/redkale/convert/ObjectDecoder.java b/src/main/java/org/redkale/convert/ObjectDecoder.java index 41b4f75d5..ec52e9012 100644 --- a/src/main/java/org/redkale/convert/ObjectDecoder.java +++ b/src/main/java/org/redkale/convert/ObjectDecoder.java @@ -34,6 +34,10 @@ public class ObjectDecoder implements Decodeable { protected DeMember[] members; + protected Map memberFieldMap; + + protected Map memberTagMap; + protected ConvertFactory factory; protected volatile boolean inited = false; @@ -92,6 +96,7 @@ public class ObjectDecoder implements Decodeable { final String[] cps = ObjectEncoder.findConstructorProperties(this.creator); try { ConvertColumnEntry ref; + ConvertFactory colFactory; RedkaleClassLoader.putReflectionPublicFields(clazz.getName()); for (final Field field : clazz.getFields()) { if (Modifier.isStatic(field.getModifiers())) continue; @@ -99,17 +104,18 @@ public class ObjectDecoder implements Decodeable { ref = factory.findRef(clazz, field); if (ref != null && ref.ignore()) continue; ConvertSmallString small = field.getAnnotation(ConvertSmallString.class); + colFactory = factory.columnFactory(field.getType(), field.getAnnotationsByType(ConvertCoder.class), false); Decodeable fieldCoder; if (small != null && field.getType() == String.class) { fieldCoder = StringSimpledCoder.SmallStringSimpledCoder.instance; } else { - fieldCoder = factory.findFieldCoder(clazz, field.getName()); + fieldCoder = colFactory.findFieldCoder(clazz, field.getName()); } if (fieldCoder == null) { Type t = TypeToken.createClassType(TypeToken.getGenericType(field.getGenericType(), this.type), this.type); - fieldCoder = factory.loadDecoder(t); + fieldCoder = colFactory.loadDecoder(t); } - DeMember member = new DeMember(ObjectEncoder.createAttribute(factory, type, clazz, field, null, null), fieldCoder, field, null); + DeMember member = new DeMember(ObjectEncoder.createAttribute(colFactory, type, clazz, field, null, null), fieldCoder, field, null); if (ref != null) member.index = ref.getIndex(); list.add(member); } @@ -153,17 +159,22 @@ public class ObjectDecoder implements Decodeable { if (ref != null && ref.ignore()) continue; ConvertSmallString small = method.getAnnotation(ConvertSmallString.class); + Field maybeField = ConvertFactory.readGetSetField(method); + colFactory = factory.columnFactory(method.getParameterTypes()[0], method.getAnnotationsByType(ConvertCoder.class), false); + if (maybeField != null && colFactory == factory) { + colFactory = factory.columnFactory(maybeField.getType(), maybeField.getAnnotationsByType(ConvertCoder.class), false); + } Decodeable fieldCoder; - if (small != null && method.getReturnType() == String.class) { + if (small != null && method.getParameterTypes()[0] == String.class) { fieldCoder = StringSimpledCoder.SmallStringSimpledCoder.instance; } else { - fieldCoder = factory.findFieldCoder(clazz, ConvertFactory.readGetSetFieldName(method)); + fieldCoder = colFactory.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); + fieldCoder = colFactory.loadDecoder(t); } - DeMember member = new DeMember(ObjectEncoder.createAttribute(factory, type, clazz, null, null, method), fieldCoder, ConvertFactory.readGetSetField(method), method); + DeMember member = new DeMember(ObjectEncoder.createAttribute(colFactory, type, clazz, null, null, method), fieldCoder, maybeField, method); if (ref != null) member.index = ref.getIndex(); list.add(member); } @@ -217,6 +228,12 @@ public class ObjectDecoder implements Decodeable { this.members = list.toArray(new DeMember[list.size()]); Arrays.sort(this.members, (a, b) -> a.compareTo(factory.isFieldSort(), b)); + this.memberFieldMap = new HashMap<>(this.members.length); + this.memberTagMap = new HashMap<>(this.members.length); + for (DeMember member : this.members) { + this.memberFieldMap.put(member.getAttribute().field(), member); + this.memberTagMap.put(member.getTag(), member); + } if (cps != null) { final String[] fields = cps; @@ -231,6 +248,8 @@ public class ObjectDecoder implements Decodeable { } this.creatorConstructorMembers = ms; } + + afterInitDeMember(factory); } catch (Exception ex) { throw new ConvertException(ex); } @@ -242,13 +261,6 @@ public class ObjectDecoder implements Decodeable { } } - protected void initForEachDeMember(ConvertFactory factory, DeMember member) { - } - - protected void setTag(DeMember member, int tag) { - member.tag = tag; - } - /** * 瀵硅薄鏍煎紡: [0x1][short瀛楁涓暟][瀛楁鍚峕[瀛楁鍊糫...[0x2] * @@ -276,37 +288,41 @@ public class ObjectDecoder implements Decodeable { throw new ConvertException("[" + typeClass + "] is a interface or abstract class, cannot create it's Creator."); } } + + DeMember[] memberArray = this.members; + Map fieldMap = this.memberFieldMap; + Map tagMap = this.memberTagMap; 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); + while (objin.hasNext()) { + DeMember member = objin.readFieldName(memberArray, fieldMap, tagMap); objin.readBlank(); if (member == null) { objin.skipValue(); //璺宠繃涓嶅瓨鍦ㄧ殑灞炴х殑鍊 } else { - readMemberValue(objin, member, result, first); + readDeMemberValue(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 DeMember[] constructorFields = this.creatorConstructorMembers; + final Object[] constructorParams = new Object[constructorFields.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); + while (objin.hasNext()) { + DeMember member = objin.readFieldName(memberArray, fieldMap, tagMap); objin.readBlank(); if (member == null) { objin.skipValue(); //璺宠繃涓嶅瓨鍦ㄧ殑灞炴х殑鍊 } else { - Object val = readMemberValue(objin, member, first); + Object val = readDeMemberValue(objin, member, first); boolean flag = true; - for (int i = 0; i < fields.length; i++) { - if (member == fields[i]) { + for (int i = 0; i < constructorFields.length; i++) { + if (member == constructorFields[i]) { constructorParams[i] = val; flag = false; break; @@ -327,29 +343,69 @@ public class ObjectDecoder implements Decodeable { } } - protected R objectReader(R in) { - return in; + //---------------------------------- 鍙畾鍒舵柟娉 ---------------------------------- + protected void initForEachDeMember(ConvertFactory factory, DeMember member) { + } + + protected void afterInitDeMember(ConvertFactory factory) { } protected boolean hasNext(R in, boolean first) { return in.hasNext(); } - protected Object readMemberValue(R in, DeMember member, boolean first) { + protected R objectReader(R in) { + return in; + } + + protected Object readDeMemberValue(R in, DeMember member, boolean first) { return member.read(in); } - protected void readMemberValue(R in, DeMember member, T result, boolean first) { + protected void readDeMemberValue(R in, DeMember member, T result, boolean first) { member.read(in, result); } + //--------------------------------------------------------------------------------- + protected void setTag(DeMember member, int tag) { + member.tag = tag; + } + + protected void setIndex(DeMember member, int index) { + member.index = index; + } + + protected void setPosition(DeMember member, int position) { + member.position = position; + } + @Override public Type getType() { return this.type; } public DeMember[] getMembers() { - return Arrays.copyOf(members, members.length); + return members; + } + + public DeMember getMember(String fieldName) { + return memberFieldMap.get(fieldName); + } + + public Map getMemberFieldMap() { + return memberFieldMap; + } + + public Map getMemberTagMap() { + return memberTagMap; + } + + public DeMember[] getConstructorMembers() { + return creatorConstructorMembers; + } + + public Creator getCreator() { + return creator; } @Override diff --git a/src/main/java/org/redkale/convert/ObjectEncoder.java b/src/main/java/org/redkale/convert/ObjectEncoder.java index 95fb0b317..ffa078401 100644 --- a/src/main/java/org/redkale/convert/ObjectEncoder.java +++ b/src/main/java/org/redkale/convert/ObjectEncoder.java @@ -73,7 +73,7 @@ public class ObjectEncoder implements Encodeable { final String[] cps = creator == null ? null : ObjectEncoder.findConstructorProperties(creator); try { ConvertColumnEntry ref; - + ConvertFactory colFactory; RedkaleClassLoader.putReflectionPublicFields(clazz.getName()); for (final Field field : clazz.getFields()) { if (Modifier.isStatic(field.getModifiers())) continue; @@ -81,17 +81,18 @@ public class ObjectEncoder implements Encodeable { ref = factory.findRef(clazz, field); if (ref != null && ref.ignore()) continue; ConvertSmallString small = field.getAnnotation(ConvertSmallString.class); + colFactory = factory.columnFactory(field.getType(), field.getAnnotationsByType(ConvertCoder.class), true); Encodeable fieldCoder; if (small != null && field.getType() == String.class) { fieldCoder = StringSimpledCoder.SmallStringSimpledCoder.instance; } else { - fieldCoder = factory.findFieldCoder(clazz, field.getName()); + fieldCoder = colFactory.findFieldCoder(clazz, field.getName()); } if (fieldCoder == null) { Type t = TypeToken.createClassType(TypeToken.getGenericType(field.getGenericType(), this.type), this.type); - fieldCoder = factory.loadEncoder(t); + fieldCoder = colFactory.loadEncoder(t); } - EnMember member = new EnMember(createAttribute(factory, type, clazz, field, null, null), fieldCoder, field, null); + EnMember member = new EnMember(createAttribute(colFactory, type, clazz, field, null, null), fieldCoder, field, null); if (ref != null) member.index = ref.getIndex(); list.add(member); } @@ -104,7 +105,9 @@ public class ObjectEncoder implements Encodeable { 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 (!(method.getName().startsWith("is") && method.getName().length() > 2) + && !(method.getName().startsWith("get") && method.getName().length() > 3) + && !Utility.isRecordGetter(clazz, method)) continue; if (factory.isConvertDisabled(method)) continue; String convertname = ConvertFactory.readGetSetFieldName(method); if (reversible && (cps == null || !contains(cps, convertname))) { @@ -125,17 +128,22 @@ public class ObjectEncoder implements Encodeable { } catch (Exception e) { } } + Field maybeField = ConvertFactory.readGetSetField(method); + colFactory = factory.columnFactory(method.getReturnType(), method.getAnnotationsByType(ConvertCoder.class), true); + if (maybeField != null && colFactory == factory) { + colFactory = factory.columnFactory(maybeField.getType(), maybeField.getAnnotationsByType(ConvertCoder.class), true); + } Encodeable fieldCoder; if (small != null && method.getReturnType() == String.class) { fieldCoder = StringSimpledCoder.SmallStringSimpledCoder.instance; } else { - fieldCoder = factory.findFieldCoder(clazz, ConvertFactory.readGetSetFieldName(method)); + fieldCoder = colFactory.findFieldCoder(clazz, ConvertFactory.readGetSetFieldName(method)); } if (fieldCoder == null) { Type t = TypeToken.createClassType(TypeToken.getGenericType(method.getGenericReturnType(), this.type), this.type); - fieldCoder = factory.loadEncoder(t); + fieldCoder = colFactory.loadEncoder(t); } - EnMember member = new EnMember(createAttribute(factory, type, clazz, null, method, null), fieldCoder, ConvertFactory.readGetSetField(method), method); + EnMember member = new EnMember(createAttribute(colFactory, type, clazz, null, method, null), fieldCoder, maybeField, method); if (ref != null) member.index = ref.getIndex(); list.add(member); } @@ -197,6 +205,7 @@ public class ObjectEncoder implements Encodeable { this.members = list.toArray(new EnMember[list.size()]); Arrays.sort(this.members, (a, b) -> a.compareTo(factory.isFieldSort(), b)); + afterInitEnMember(factory); } catch (Exception ex) { throw new ConvertException("ObjectEncoder init type=" + this.type + " error", ex); } @@ -208,13 +217,6 @@ public class ObjectEncoder implements Encodeable { } } - 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) { @@ -258,10 +260,30 @@ public class ObjectEncoder implements Encodeable { objout.writeObjectE(value); } + //---------------------------------- 鍙畾鍒舵柟娉 ---------------------------------- + protected void initForEachEnMember(ConvertFactory factory, EnMember member) { + } + + protected void afterInitEnMember(ConvertFactory factory) { + } + protected W objectWriter(W out, T value) { return out; } + //--------------------------------------------------------------------------------- + protected void setTag(EnMember member, int tag) { + member.tag = tag; + } + + protected void setIndex(EnMember member, int index) { + member.index = index; + } + + protected void setPosition(EnMember member, int position) { + member.position = position; + } + @Override public Type getType() { return this.type; @@ -272,7 +294,7 @@ public class ObjectEncoder implements Encodeable { } public EnMember[] getMembers() { - return Arrays.copyOf(members, members.length); + return members; } @Override @@ -280,54 +302,6 @@ public class ObjectEncoder implements Encodeable { 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; @@ -371,8 +345,12 @@ public class ObjectEncoder implements Encodeable { } fieldalias = ref == null || ref.name().isEmpty() ? mfieldname : ref.name(); } - - return Attribute.create(realType, clazz, fieldalias, null, field, getter, setter, null); + Type subclass = realType; + if ((realType instanceof Class) && field != null && getter == null && setter == null) { + //淇鐖剁被鍚玴ublic field锛宻ubclass涓嶄紶鐖剁被浼氬鑷磈ava.lang.NoSuchFieldError鐨刡ug + subclass = field.getDeclaringClass(); + } + return Attribute.create(subclass, clazz, fieldalias, null, field, getter, setter, null); } } diff --git a/src/main/java/org/redkale/convert/Reader.java b/src/main/java/org/redkale/convert/Reader.java index c9aa9a102..b6ca6fc06 100644 --- a/src/main/java/org/redkale/convert/Reader.java +++ b/src/main/java/org/redkale/convert/Reader.java @@ -5,6 +5,8 @@ */ package org.redkale.convert; +import java.util.Map; + /** * 鍙嶅簭鍒楀寲鐨勬暟鎹鍙栨祦 * @@ -141,11 +143,13 @@ public abstract class Reader { /** * 鏍规嵁瀛楁璇诲彇瀛楁瀵瑰簲鐨凞eMember * - * @param members DeMember鐨勫叏閲忛泦鍚 + * @param members DeMember鐨勫叏閲忛泦鍚 + * @param memberFieldMap DeMember鐨勫瓧娈靛悕map + * @param memberTagMap DeMember鐨則ag map * * @return 鍖归厤鐨凞eMember */ - public abstract DeMember readFieldName(final DeMember[] members); + public abstract DeMember readFieldName(final DeMember[] members, Map memberFieldMap, Map memberTagMap); /** * 璇诲彇涓涓猙oolean鍊 diff --git a/src/main/java/org/redkale/convert/StreamEncoder.java b/src/main/java/org/redkale/convert/StreamEncoder.java index e09339dbe..7a16c543b 100644 --- a/src/main/java/org/redkale/convert/StreamEncoder.java +++ b/src/main/java/org/redkale/convert/StreamEncoder.java @@ -97,6 +97,11 @@ public class StreamEncoder implements Encodeable> { return type; } + @Override + public boolean specifyable() { + return false; + } + public Encodeable getComponentEncoder() { return componentEncoder; } diff --git a/src/main/java/org/redkale/convert/TextConvert.java b/src/main/java/org/redkale/convert/TextConvert.java index c6f3b095a..57ba32bc8 100644 --- a/src/main/java/org/redkale/convert/TextConvert.java +++ b/src/main/java/org/redkale/convert/TextConvert.java @@ -28,6 +28,8 @@ public abstract class TextConvert extends Co return false; } + public abstract T convertFrom(final Type type, final String text); + 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/bson/BsonFactory.java b/src/main/java/org/redkale/convert/bson/BsonFactory.java index fcfdc8720..6b13638ae 100644 --- a/src/main/java/org/redkale/convert/bson/BsonFactory.java +++ b/src/main/java/org/redkale/convert/bson/BsonFactory.java @@ -58,6 +58,10 @@ public final class BsonFactory extends ConvertFactory { return this; } + protected boolean tiny() { + return this.tiny; + } + @Override public BsonFactory skipAllIgnore(final boolean skipIgnore) { this.registerSkipAllIgnore(skipIgnore); diff --git a/src/main/java/org/redkale/convert/bson/BsonReader.java b/src/main/java/org/redkale/convert/bson/BsonReader.java index 51c09abfd..7532217aa 100644 --- a/src/main/java/org/redkale/convert/bson/BsonReader.java +++ b/src/main/java/org/redkale/convert/bson/BsonReader.java @@ -6,6 +6,7 @@ package org.redkale.convert.bson; import java.nio.charset.StandardCharsets; +import java.util.Map; import org.redkale.convert.*; import static org.redkale.convert.Reader.SIGN_NULL; import org.redkale.convert.ext.*; @@ -219,19 +220,19 @@ public class BsonReader extends Reader { } @Override - public final DeMember readFieldName(final DeMember[] members) { - final String exceptedfield = readSmallString(); + public final DeMember readFieldName(final DeMember[] members, Map memberFieldMap, Map memberTagMap) { + 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())) { + 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())) { + if (exceptedField.equals(members[k].getAttribute().field())) { this.fieldIndex = k; return members[k]; } diff --git a/src/main/java/org/redkale/convert/bson/BsonWriter.java b/src/main/java/org/redkale/convert/bson/BsonWriter.java index 2b46c4f89..53f3c1dba 100644 --- a/src/main/java/org/redkale/convert/bson/BsonWriter.java +++ b/src/main/java/org/redkale/convert/bson/BsonWriter.java @@ -27,7 +27,7 @@ public class BsonWriter extends Writer implements ByteTuple { protected int count; - protected boolean tiny; + protected boolean tiny = BsonFactory.root().tiny(); public static ObjectPool createPool(int max) { return ObjectPool.createSafePool(max, (Object... params) -> new BsonWriter(), null, (t) -> t.recycle()); diff --git a/src/main/java/org/redkale/convert/ext/BigDecimalSimpledCoder.java b/src/main/java/org/redkale/convert/ext/BigDecimalSimpledCoder.java index 07aa95aa7..73404f32a 100644 --- a/src/main/java/org/redkale/convert/ext/BigDecimalSimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/BigDecimalSimpledCoder.java @@ -9,6 +9,7 @@ import org.redkale.convert.SimpledCoder; import org.redkale.convert.Writer; import org.redkale.convert.Reader; import java.math.BigDecimal; +import org.redkale.convert.json.*; import org.redkale.util.Utility; /** @@ -41,4 +42,30 @@ public final class BigDecimalSimpledCoder ex return new BigDecimal(Utility.charArray(value)); } + /** + * BigDecimal 鐨凧sonSimpledCoder瀹炵幇 + * + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * @param Writer杈撳嚭鐨勫瓙绫诲瀷 + */ + public static class BigDecimalJsonSimpledCoder extends SimpledCoder { + + public static final BigDecimalJsonSimpledCoder instance = new BigDecimalJsonSimpledCoder(); + + @Override + public void convertTo(final W out, final BigDecimal value) { + if (value == null) { + out.writeNull(); + } else { + out.writeSmallString(value.toString()); + } + } + + @Override + public BigDecimal convertFrom(R in) { + final String str = in.readString(); + if (str == null) return null; + return new BigDecimal(str); + } + } } diff --git a/src/main/java/org/redkale/convert/ext/BigIntegerSimpledCoder.java b/src/main/java/org/redkale/convert/ext/BigIntegerSimpledCoder.java index a6ea50d1e..404cf675a 100644 --- a/src/main/java/org/redkale/convert/ext/BigIntegerSimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/BigIntegerSimpledCoder.java @@ -9,6 +9,7 @@ import org.redkale.convert.SimpledCoder; import org.redkale.convert.Writer; import org.redkale.convert.Reader; import java.math.BigInteger; +import org.redkale.convert.json.*; /** * BigInteger 鐨凷impledCoder瀹炵幇 @@ -47,24 +48,59 @@ public final class BigIntegerSimpledCoder ex * @param Reader杈撳叆鐨勫瓙绫诲瀷 * @param Writer杈撳嚭鐨勫瓙绫诲瀷 */ - public static class BigIntegerJsonSimpledCoder extends SimpledCoder { + public static class BigIntegerJsonSimpledCoder extends SimpledCoder { public static final BigIntegerJsonSimpledCoder instance = new BigIntegerJsonSimpledCoder(); @Override - public void convertTo(final Writer out, final BigInteger value) { + public void convertTo(final W out, final BigInteger value) { if (value == null) { out.writeNull(); } else { - out.writeString(value.toString()); + out.writeSmallString(value.toString()); } } @Override - public BigInteger convertFrom(Reader in) { + public BigInteger convertFrom(R in) { final String str = in.readString(); if (str == null) return null; return new BigInteger(str); } } + + /** + * BigInteger 鐨勫崄鍏繘鍒禞sonSimpledCoder瀹炵幇 + * + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * @param Writer杈撳嚭鐨勫瓙绫诲瀷 + */ + public static class BigIntegerHexJsonSimpledCoder extends SimpledCoder { + + public static final BigIntegerHexJsonSimpledCoder instance = new BigIntegerHexJsonSimpledCoder(); + + @Override + public void convertTo(final W out, final BigInteger value) { + if (value == null) { + out.writeNull(); + } else { + String s = value.toString(16); + out.writeSmallString(s.charAt(0) == '-' ? ("-0x" + s.substring(1)) : ("0x" + s)); + } + } + + @Override + public BigInteger convertFrom(R in) { + final String str = in.readString(); + if (str == null) return null; + if (str.length() > 2) { + if (str.charAt(0) == '0' && (str.charAt(1) == 'x' || str.charAt(1) == 'X')) { + return new BigInteger(str.substring(2), 16); + } else if (str.charAt(0) == '-' && str.length() > 3 && str.charAt(1) == '0' && (str.charAt(2) == 'x' || str.charAt(2) == 'X')) { + return new BigInteger("-" + str.substring(3), 16); + } + } + return new BigInteger(str); + } + } } diff --git a/src/main/java/org/redkale/convert/ext/DLongSimpledCoder.java b/src/main/java/org/redkale/convert/ext/DLongSimpledCoder.java index cbf9a8eb3..c1d881086 100644 --- a/src/main/java/org/redkale/convert/ext/DLongSimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/DLongSimpledCoder.java @@ -8,6 +8,7 @@ package org.redkale.convert.ext; import org.redkale.convert.Reader; import org.redkale.convert.Writer; import org.redkale.convert.SimpledCoder; +import org.redkale.convert.json.*; import org.redkale.util.*; /** @@ -50,12 +51,12 @@ public final class DLongSimpledCoder extends * @param Reader杈撳叆鐨勫瓙绫诲瀷 * @param Writer杈撳嚭鐨勫瓙绫诲瀷 */ - public static class DLongJsonSimpledCoder extends SimpledCoder { + public static class DLongJsonSimpledCoder extends SimpledCoder { public static final DLongJsonSimpledCoder instance = new DLongJsonSimpledCoder(); @Override - public void convertTo(final Writer out, final DLong value) { + public void convertTo(final W out, final DLong value) { if (value == null) { out.writeNull(); } else { @@ -64,7 +65,7 @@ public final class DLongSimpledCoder extends } @Override - public DLong convertFrom(Reader in) { + public DLong convertFrom(R 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/InetAddressSimpledCoder.java b/src/main/java/org/redkale/convert/ext/InetAddressSimpledCoder.java index 3baec531a..d53b43a0c 100644 --- a/src/main/java/org/redkale/convert/ext/InetAddressSimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/InetAddressSimpledCoder.java @@ -9,6 +9,7 @@ import org.redkale.convert.SimpledCoder; import org.redkale.convert.Writer; import org.redkale.convert.Reader; import java.net.*; +import org.redkale.convert.json.*; import org.redkale.util.StringWrapper; /** @@ -87,7 +88,7 @@ public final class InetAddressSimpledCoder e * @param Reader杈撳叆鐨勫瓙绫诲瀷 * @param Writer杈撳嚭鐨勫瓙绫诲瀷 */ - public final static class InetAddressJsonSimpledCoder extends SimpledCoder { + public final static class InetAddressJsonSimpledCoder extends SimpledCoder { public static final InetAddressJsonSimpledCoder instance = new InetAddressJsonSimpledCoder(); @@ -119,7 +120,7 @@ public final class InetAddressSimpledCoder e * @param Reader杈撳叆鐨勫瓙绫诲瀷 * @param Writer杈撳嚭鐨勫瓙绫诲瀷 */ - public final static class InetSocketAddressJsonSimpledCoder extends SimpledCoder { + public final static class InetSocketAddressJsonSimpledCoder extends SimpledCoder { public static final InetSocketAddressJsonSimpledCoder instance = new InetSocketAddressJsonSimpledCoder(); diff --git a/src/main/java/org/redkale/convert/ext/InstantSimpledCoder.java b/src/main/java/org/redkale/convert/ext/InstantSimpledCoder.java index 4084c1b3d..14f072600 100644 --- a/src/main/java/org/redkale/convert/ext/InstantSimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/InstantSimpledCoder.java @@ -7,6 +7,7 @@ package org.redkale.convert.ext; import java.time.*; import org.redkale.convert.*; +import org.redkale.convert.json.*; /** * java.time.Instant 鐨凷impledCoder瀹炵幇 @@ -33,12 +34,12 @@ public class InstantSimpledCoder extends Sim return t == -1 ? null : Instant.ofEpochMilli(t); } - public final static class InstantJsonSimpledCoder extends SimpledCoder { + public final static class InstantJsonSimpledCoder extends SimpledCoder { public static final InstantJsonSimpledCoder instance = new InstantJsonSimpledCoder(); @Override - public void convertTo(final Writer out, final Instant value) { + public void convertTo(final W out, final Instant value) { if (value == null) { out.writeNull(); } else { @@ -47,7 +48,7 @@ public class InstantSimpledCoder extends Sim } @Override - public Instant convertFrom(Reader in) { + public Instant convertFrom(R in) { final String str = in.readSmallString(); if (str == null) return null; return Instant.parse(str); diff --git a/src/main/java/org/redkale/convert/ext/IntSimpledCoder.java b/src/main/java/org/redkale/convert/ext/IntSimpledCoder.java index c7889ec27..de0e8e19a 100644 --- a/src/main/java/org/redkale/convert/ext/IntSimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/IntSimpledCoder.java @@ -8,11 +8,14 @@ package org.redkale.convert.ext; import org.redkale.convert.Reader; import org.redkale.convert.SimpledCoder; import org.redkale.convert.Writer; +import org.redkale.convert.json.*; /** * int 鐨凷impledCoder瀹炵幇 * - *

璇︽儏瑙: https://redkale.org + *

+ * 璇︽儏瑙: https://redkale.org + * * @author zhangjx * @param Reader杈撳叆鐨勫瓙绫诲瀷 * @param Writer杈撳嚭鐨勫瓙绫诲瀷 @@ -31,4 +34,38 @@ public final class IntSimpledCoder extends S return in.readInt(); } + /** + * int 鐨勫崄鍏繘鍒禞sonSimpledCoder瀹炵幇 + * + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * @param Writer杈撳嚭鐨勫瓙绫诲瀷 + */ + public static class IntHexJsonSimpledCoder extends SimpledCoder { + + public static final IntHexJsonSimpledCoder instance = new IntHexJsonSimpledCoder(); + + @Override + public void convertTo(final W out, final Integer value) { + if (value == null) { + out.writeSmallString("0x0"); + } else { + if (value < 0) throw new NumberFormatException("Negative values (" + value + ") are not supported"); + out.writeSmallString("0x" + Integer.toHexString(value)); + } + } + + @Override + public Integer convertFrom(R in) { + final String str = in.readString(); + if (str == null) return 0; + try { + if (str.length() > 2 && str.charAt(0) == '0' && (str.charAt(1) == 'x' || str.charAt(1) == 'X')) { + return Integer.parseInt(str.substring(2), 16); + } + return Integer.parseInt(str); + } catch (NumberFormatException e) { + return 0; + } + } + } } diff --git a/src/main/java/org/redkale/convert/ext/LocalDateSimpledCoder.java b/src/main/java/org/redkale/convert/ext/LocalDateSimpledCoder.java index 2ab440aad..7537d5f86 100644 --- a/src/main/java/org/redkale/convert/ext/LocalDateSimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/LocalDateSimpledCoder.java @@ -7,6 +7,7 @@ package org.redkale.convert.ext; import java.time.*; import org.redkale.convert.*; +import org.redkale.convert.json.*; /** * java.time.LocalDate 鐨凷impledCoder瀹炵幇 @@ -49,12 +50,12 @@ public final class LocalDateSimpledCoder ext * @param Reader杈撳叆鐨勫瓙绫诲瀷 * @param Writer杈撳嚭鐨勫瓙绫诲瀷 */ - public final static class LocalDateJsonSimpledCoder extends SimpledCoder { + public final static class LocalDateJsonSimpledCoder extends SimpledCoder { public static final LocalDateJsonSimpledCoder instance = new LocalDateJsonSimpledCoder(); @Override - public void convertTo(final Writer out, final LocalDate value) { + public void convertTo(final W out, final LocalDate value) { if (value == null) { out.writeNull(); } else { @@ -63,7 +64,7 @@ public final class LocalDateSimpledCoder ext } @Override - public LocalDate convertFrom(Reader in) { + public LocalDate convertFrom(R in) { final String str = in.readSmallString(); if (str == null) return null; return LocalDate.parse(str); diff --git a/src/main/java/org/redkale/convert/ext/LocalDateTimeSimpledCoder.java b/src/main/java/org/redkale/convert/ext/LocalDateTimeSimpledCoder.java index bf30a23cd..12a54be2b 100644 --- a/src/main/java/org/redkale/convert/ext/LocalDateTimeSimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/LocalDateTimeSimpledCoder.java @@ -7,6 +7,7 @@ package org.redkale.convert.ext; import java.time.*; import org.redkale.convert.*; +import org.redkale.convert.json.*; /** * java.time.LocalDateTime 鐨凷impledCoder瀹炵幇 @@ -62,12 +63,12 @@ public final class LocalDateTimeSimpledCoder * @param Reader杈撳叆鐨勫瓙绫诲瀷 * @param Writer杈撳嚭鐨勫瓙绫诲瀷 */ - public final static class LocalDateTimeJsonSimpledCoder extends SimpledCoder { + public final static class LocalDateTimeJsonSimpledCoder extends SimpledCoder { public static final LocalDateTimeJsonSimpledCoder instance = new LocalDateTimeJsonSimpledCoder(); @Override - public void convertTo(final Writer out, final LocalDateTime value) { + public void convertTo(final W out, final LocalDateTime value) { if (value == null) { out.writeNull(); } else { @@ -76,7 +77,7 @@ public final class LocalDateTimeSimpledCoder } @Override - public LocalDateTime convertFrom(Reader in) { + public LocalDateTime convertFrom(R in) { final String str = in.readSmallString(); if (str == null) return null; return LocalDateTime.parse(str); diff --git a/src/main/java/org/redkale/convert/ext/LocalTimeSimpledCoder.java b/src/main/java/org/redkale/convert/ext/LocalTimeSimpledCoder.java index 49875cb00..06f72ab6f 100644 --- a/src/main/java/org/redkale/convert/ext/LocalTimeSimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/LocalTimeSimpledCoder.java @@ -7,6 +7,7 @@ package org.redkale.convert.ext; import java.time.*; import org.redkale.convert.*; +import org.redkale.convert.json.*; /** * java.time.LocalTime 鐨凷impledCoder瀹炵幇 @@ -47,12 +48,12 @@ public final class LocalTimeSimpledCoder ext * @param Reader杈撳叆鐨勫瓙绫诲瀷 * @param Writer杈撳嚭鐨勫瓙绫诲瀷 */ - public final static class LocalTimeJsonSimpledCoder extends SimpledCoder { + public final static class LocalTimeJsonSimpledCoder extends SimpledCoder { public static final LocalTimeJsonSimpledCoder instance = new LocalTimeJsonSimpledCoder(); @Override - public void convertTo(final Writer out, final LocalTime value) { + public void convertTo(final W out, final LocalTime value) { if (value == null) { out.writeNull(); } else { @@ -61,7 +62,7 @@ public final class LocalTimeSimpledCoder ext } @Override - public LocalTime convertFrom(Reader in) { + public LocalTime convertFrom(R in) { final String str = in.readSmallString(); if (str == null) return null; return LocalTime.parse(str); diff --git a/src/main/java/org/redkale/convert/ext/LongSimpledCoder.java b/src/main/java/org/redkale/convert/ext/LongSimpledCoder.java index b335564da..91da6b495 100644 --- a/src/main/java/org/redkale/convert/ext/LongSimpledCoder.java +++ b/src/main/java/org/redkale/convert/ext/LongSimpledCoder.java @@ -3,17 +3,19 @@ * 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 org.redkale.convert.json.*; /** * long 鐨凷impledCoder瀹炵幇 * - *

璇︽儏瑙: https://redkale.org + *

+ * 璇︽儏瑙: https://redkale.org + * * @author zhangjx * @param Reader杈撳叆鐨勫瓙绫诲瀷 * @param Writer杈撳嚭鐨勫瓙绫诲瀷 @@ -32,4 +34,38 @@ public final class LongSimpledCoder extends return in.readLong(); } + /** + * long 鐨勫崄鍏繘鍒禞sonSimpledCoder瀹炵幇 + * + * @param Reader杈撳叆鐨勫瓙绫诲瀷 + * @param Writer杈撳嚭鐨勫瓙绫诲瀷 + */ + public static class LongHexJsonSimpledCoder extends SimpledCoder { + + public static final LongHexJsonSimpledCoder instance = new LongHexJsonSimpledCoder(); + + @Override + public void convertTo(final W out, final Long value) { + if (value == null) { + out.writeSmallString("0x0"); + } else { + if (value < 0) throw new NumberFormatException("Negative values (" + value + ") are not supported"); + out.writeSmallString("0x" + Long.toHexString(value)); + } + } + + @Override + public Long convertFrom(R in) { + final String str = in.readString(); + if (str == null) return 0L; + try { + if (str.length() > 2 && str.charAt(0) == '0' && (str.charAt(1) == 'x' || str.charAt(1) == 'X')) { + return Long.parseLong(str.substring(2), 16); + } + return Long.parseLong(str); + } catch (NumberFormatException e) { + return 0L; + } + } + } } diff --git a/src/main/java/org/redkale/convert/json/JsonByteBufferReader.java b/src/main/java/org/redkale/convert/json/JsonByteBufferReader.java index 698e786f9..6561768fc 100644 --- a/src/main/java/org/redkale/convert/json/JsonByteBufferReader.java +++ b/src/main/java/org/redkale/convert/json/JsonByteBufferReader.java @@ -98,21 +98,6 @@ public class JsonByteBufferReader extends JsonReader { } } - /** - * 璇诲彇涓嬩竴涓湁鏁堝瓧绗 - * - * @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; - } - } - /** * 鍥為鏈鍚庤鍙栫殑瀛楃 * @@ -130,7 +115,8 @@ public class JsonByteBufferReader extends JsonReader { */ @Override public final String readObjectB(final Class clazz) { - char ch = nextGoodChar(); + this.fieldIndex = 0; //蹇呴』瑕侀噸缃负0 + char ch = nextGoodChar(true); 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; @@ -155,7 +141,7 @@ public class JsonByteBufferReader extends JsonReader { */ @Override public final int readArrayB(DeMember member, byte[] typevals, Decodeable decoder) { - char ch = nextGoodChar(); + char ch = nextGoodChar(true); 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; @@ -174,7 +160,7 @@ public class JsonByteBufferReader extends JsonReader { */ @Override public final void readBlank() { - char ch = nextGoodChar(); + char ch = nextGoodChar(true); if (ch == ':') return; StringBuilder sb = new StringBuilder(); sb.append(ch); @@ -186,23 +172,6 @@ public class JsonByteBufferReader extends JsonReader { 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; - } - /** * 璇诲彇灏忓瓧绗︿覆 * @@ -210,7 +179,7 @@ public class JsonByteBufferReader extends JsonReader { */ @Override public final String readSmallString() { - char ch = nextGoodChar(); + char ch = nextGoodChar(true); if (ch == 0) return null; final StringBuilder sb = new StringBuilder(); if (ch == '"' || ch == '\'') { @@ -300,80 +269,6 @@ public class JsonByteBufferReader extends JsonReader { } } - /** - * 璇诲彇涓涓猧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; - } - /** * 璇诲彇瀛楃涓诧紝 蹇呴』鏄"鎴栬'鍖呭洿鐨勫瓧绗︿覆鍊 * diff --git a/src/main/java/org/redkale/convert/json/JsonByteBufferWriter.java b/src/main/java/org/redkale/convert/json/JsonByteBufferWriter.java index ebc0fd06a..0e21596b8 100644 --- a/src/main/java/org/redkale/convert/json/JsonByteBufferWriter.java +++ b/src/main/java/org/redkale/convert/json/JsonByteBufferWriter.java @@ -263,7 +263,7 @@ public class JsonByteBufferWriter extends JsonWriter { } /** - * 娉ㄦ剰锛 璇tring鍊间笉鑳戒负null涓斾笉浼氳繘琛岃浆涔夛紝 鍙敤浜庝笉鍚渶瑕佽浆涔夊瓧绗︾殑瀛楃涓诧紝渚嬪enum銆乨ouble銆丅igInteger杞崲鐨凷tring + * 娉ㄦ剰锛 璇tring鍊间笉鑳戒负null涓斾笉浼氳繘琛岃浆涔夛紝 鍙敤浜庝笉鍚渶瑕佽浆涔夊瓧绗︾殑瀛楃涓诧紝渚嬪enum銆乨ouble銆丅igInteger銆丅igDecimal杞崲鐨凷tring * * @param quote 鏄惁鍐欏叆鍙屽紩鍙 * @param value String鍊 @@ -622,6 +622,11 @@ public class JsonByteBufferWriter extends JsonWriter { @Override public void writeString(String value) { + writeString(true, value); + } + + @Override + public void writeString(final boolean quote, String value) { if (value == null) { writeNull(); return; @@ -654,7 +659,7 @@ public class JsonByteBufferWriter extends JsonWriter { expandsize = expand(byteLength); if (expandsize == 0) { // 鍙渶瑕佷竴涓猙uffer final ByteBuffer buffer = this.buffers[index]; - buffer.put((byte) '"'); + if (quote) buffer.put((byte) '"'); for (int i = 0; i < chs.length; i++) { char c = chs[i]; switch (c) { @@ -689,7 +694,7 @@ public class JsonByteBufferWriter extends JsonWriter { break; } } - buffer.put((byte) '"'); + if (quote) buffer.put((byte) '"'); return; } } @@ -711,7 +716,7 @@ public class JsonByteBufferWriter extends JsonWriter { } } char[] cs = Utility.charArray(sb); - writeTo(expandsize, true, cs, 0, sb.length()); + writeTo(expandsize, quote, cs, 0, sb.length()); } @Override diff --git a/src/main/java/org/redkale/convert/json/JsonBytesWriter.java b/src/main/java/org/redkale/convert/json/JsonBytesWriter.java index 780e8f686..fd6a3ee50 100644 --- a/src/main/java/org/redkale/convert/json/JsonBytesWriter.java +++ b/src/main/java/org/redkale/convert/json/JsonBytesWriter.java @@ -137,7 +137,7 @@ public class JsonBytesWriter extends JsonWriter implements ByteTuple { } /** - * 娉ㄦ剰锛 璇tring鍊间笉鑳戒负null涓斾笉浼氳繘琛岃浆涔夛紝 鍙敤浜庝笉鍚渶瑕佽浆涔夊瓧绗︾殑瀛楃涓诧紝渚嬪enum銆乨ouble銆丅igInteger杞崲鐨凷tring + * 娉ㄦ剰锛 璇tring鍊间笉鑳戒负null涓斾笉浼氳繘琛岃浆涔夛紝 鍙敤浜庝笉鍚渶瑕佽浆涔夊瓧绗︾殑瀛楃涓诧紝渚嬪enum銆乨ouble銆丅igInteger銆丅igDecimal杞崲鐨凷tring * * @param quote 鏄惁鍔犲弻寮曞彿 * @param value 闈瀗ull涓斾笉鍚渶瑕佽浆涔夌殑瀛楃鐨凷tring鍊 @@ -363,10 +363,10 @@ public class JsonBytesWriter extends JsonWriter implements ByteTuple { return this.count; } - private void writeEscapeLatinString(byte[] value) { + private void writeEscapeLatinString(final boolean quote, byte[] value) { byte[] bytes = expand(value.length * 2 + 2); int curr = count; - bytes[curr++] = '"'; + if (quote) bytes[curr++] = '"'; for (byte b : value) { if (b == '"') { bytes[curr++] = '\\'; @@ -391,23 +391,28 @@ public class JsonBytesWriter extends JsonWriter implements ByteTuple { bytes[curr++] = b; } } - bytes[curr++] = '"'; + if (quote) bytes[curr++] = '"'; count = curr; } @Override public void writeString(String value) { + writeString(true, value); + } + + @Override + public void writeString(final boolean quote, String value) { if (value == null) { writeNull(); return; } if (Utility.isLatin1(value)) { - writeEscapeLatinString(Utility.latin1ByteArray(value)); + writeEscapeLatinString(quote, Utility.latin1ByteArray(value)); return; } byte[] bytes = expand(value.length() * 4 + 2); int curr = count; - bytes[curr++] = '"'; + if (quote) bytes[curr++] = '"'; int len = value.length(); for (int i = 0; i < len; i++) { char ch = value.charAt(i); @@ -452,7 +457,7 @@ public class JsonBytesWriter extends JsonWriter implements ByteTuple { break; } } - bytes[curr++] = '"'; + if (quote) bytes[curr++] = '"'; count = curr; } diff --git a/src/main/java/org/redkale/convert/json/JsonCharsWriter.java b/src/main/java/org/redkale/convert/json/JsonCharsWriter.java index cb481cbeb..800f140ed 100644 --- a/src/main/java/org/redkale/convert/json/JsonCharsWriter.java +++ b/src/main/java/org/redkale/convert/json/JsonCharsWriter.java @@ -95,7 +95,7 @@ public class JsonCharsWriter extends JsonWriter { } /** - * 娉ㄦ剰锛 璇tring鍊间笉鑳戒负null涓斾笉浼氳繘琛岃浆涔夛紝 鍙敤浜庝笉鍚渶瑕佽浆涔夊瓧绗︾殑瀛楃涓诧紝渚嬪enum銆乨ouble銆丅igInteger杞崲鐨凷tring + * 娉ㄦ剰锛 璇tring鍊间笉鑳戒负null涓斾笉浼氳繘琛岃浆涔夛紝 鍙敤浜庝笉鍚渶瑕佽浆涔夊瓧绗︾殑瀛楃涓诧紝渚嬪enum銆乨ouble銆丅igInteger銆丅igDecimal杞崲鐨凷tring * * @param quote 鏄惁鍔犲弻寮曞彿 * @param value 闈瀗ull涓斾笉鍚渶瑕佽浆涔夌殑瀛楃鐨凷tring鍊 @@ -308,12 +308,17 @@ public class JsonCharsWriter extends JsonWriter { @Override public void writeString(String value) { + writeString(true, value); + } + + @Override + public void writeString(final boolean quote, String value) { if (value == null) { writeNull(); return; } expand(value.length() * 2 + 2); - content[count++] = '"'; + if (quote) content[count++] = '"'; for (char ch : Utility.charArray(value)) { switch (ch) { case '\n': @@ -341,7 +346,7 @@ public class JsonCharsWriter extends JsonWriter { break; } } - content[count++] = '"'; + if (quote) content[count++] = '"'; } @Override diff --git a/src/main/java/org/redkale/convert/json/JsonConvert.java b/src/main/java/org/redkale/convert/json/JsonConvert.java index e4365f641..3a09676a7 100644 --- a/src/main/java/org/redkale/convert/json/JsonConvert.java +++ b/src/main/java/org/redkale/convert/json/JsonConvert.java @@ -27,6 +27,9 @@ public class JsonConvert extends TextConvert { public static final Type TYPE_MAP_STRING_STRING = new TypeToken>() { }.getType(); + public static final Type TYPE_LIST_STRING = new TypeToken>() { + }.getType(); + public static final Type TYPE_RETRESULT_STRING = new TypeToken>() { }.getType(); @@ -100,6 +103,7 @@ public class JsonConvert extends TextConvert { return convertFrom(type, new String(bytes, offset, length, StandardCharsets.UTF_8)); } + @Override public T convertFrom(final Type type, final String text) { if (text == null) return null; return convertFrom(type, Utility.charArray(text)); @@ -211,6 +215,24 @@ public class JsonConvert extends TextConvert { return (V) new AnyDecoder(factory).convertFrom(reader); } + //json鏁版嵁鐨勬暟缁勯暱搴﹀繀椤诲拰types涓暟鐩稿悓 + public Object[] convertFrom(final Type[] types, final String text) { + if (text == null) return null; + return new JsonMultiArrayDecoder(getFactory(), types).convertFrom(new JsonReader(text)); + } + + //json鏁版嵁鐨勬暟缁勯暱搴﹀繀椤诲拰types涓暟鐩稿悓 + public Object[] convertFrom(final Type[] types, final byte[] bytes) { + if (bytes == null) return null; + return convertFrom(types, new String(bytes, StandardCharsets.UTF_8)); + } + + //json鏁版嵁鐨勬暟缁勯暱搴﹀繀椤诲拰types涓暟鐩稿悓 + public Object[] convertFrom(final Type[] types, final byte[] bytes, final int offset, final int length) { + if (bytes == null) return null; + return convertFrom(types, new String(bytes, offset, length, StandardCharsets.UTF_8)); + } + //------------------------------ convertTo ----------------------------------------------------------- @Override public String convertTo(final Object value) { diff --git a/src/main/java/org/redkale/convert/json/JsonDynEncoder.java b/src/main/java/org/redkale/convert/json/JsonDynEncoder.java index 9b1ce17d6..fcdc0cdcd 100644 --- a/src/main/java/org/redkale/convert/json/JsonDynEncoder.java +++ b/src/main/java/org/redkale/convert/json/JsonDynEncoder.java @@ -129,7 +129,8 @@ public abstract class JsonDynEncoder implements Encodeable { 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 (!(method.getName().startsWith("is") && method.getName().length() > 2) + && !(method.getName().startsWith("get") && method.getName().length() > 3)) continue; if (factory.isConvertDisabled(method)) continue; if (method.getParameterTypes().length != 0) continue; if (method.getReturnType() == void.class) continue; @@ -195,7 +196,9 @@ public abstract class JsonDynEncoder implements Encodeable { 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; + if (!(fname.startsWith("is") && fname.length() > 2) + && !(fname.startsWith("get") && fname.length() > 3) + && !(fname.startsWith("set") && fname.length() > 3)) 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); @@ -206,6 +209,10 @@ public abstract class JsonDynEncoder implements Encodeable { } protected static JsonDynEncoder generateDyncEncoder(final JsonFactory factory, final Class clazz, final List members) { + final ObjectEncoder selfObjEncoder = factory.createObjectEncoder(clazz); + selfObjEncoder.init(factory); + if (selfObjEncoder.getMembers().length != members.size()) return null; //瀛樺湪ignore绛夊畾鍒堕厤缃 + final String supDynName = JsonDynEncoder.class.getName().replace('.', '/'); final String valtypeName = clazz.getName().replace('.', '/'); final String writerName = JsonWriter.class.getName().replace('.', '/'); @@ -220,9 +227,11 @@ public abstract class JsonDynEncoder implements Encodeable { final String valtypeDesc = org.redkale.asm.Type.getDescriptor(clazz); Map mixedNames0 = null; + StringBuilder memberb = new StringBuilder(); for (AccessibleObject element : members) { ConvertColumnEntry ref1 = factory.findRef(clazz, element); final String fieldname = ref1 == null || ref1.name().isEmpty() ? readGetSetFieldName(element) : ref1.name(); + memberb.append(fieldname).append(','); final Class fieldtype = readGetSetFieldType(element); if (fieldtype != String.class && !fieldtype.isPrimitive()) { if (mixedNames0 == null) mixedNames0 = new HashMap<>(); @@ -231,9 +240,8 @@ public abstract class JsonDynEncoder implements Encodeable { } 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); + final String newDynName = "org/redkaledyn/json/_Dyn" + JsonDynEncoder.class.getSimpleName() + + "__" + clazz.getName().replace('.', '_').replace('$', '_') + "_" + factory.tiny() + "_" + Utility.md5Hex(memberb.toString()); //tiny蹇呴』瑕佸姞涓, 鍚屼竴涓被浼氭湁澶氫釜瀛楁瀹氬埗Convert try { Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.')); Class newClazz = clz == null ? loader.loadClass(newDynName.replace('/', '.')) : clz; diff --git a/src/main/java/org/redkale/convert/json/JsonFactory.java b/src/main/java/org/redkale/convert/json/JsonFactory.java index fcbd1aab2..6b2ac8023 100644 --- a/src/main/java/org/redkale/convert/json/JsonFactory.java +++ b/src/main/java/org/redkale/convert/json/JsonFactory.java @@ -7,7 +7,7 @@ package org.redkale.convert.json; import java.io.Serializable; import java.lang.reflect.*; -import java.math.BigInteger; +import java.math.*; import java.net.*; import org.redkale.convert.*; import org.redkale.convert.ext.*; @@ -24,7 +24,7 @@ import org.redkale.util.*; @SuppressWarnings("unchecked") public final class JsonFactory extends ConvertFactory { - private static final JsonFactory instance = new JsonFactory(null, getSystemPropertyBoolean("redkaleconvert.json.tiny", "redkale.convert.tiny", true)); + private static final JsonFactory instance = new JsonFactory(null, getSystemPropertyBoolean("redkale.convert.json.tiny", "redkale.convert.tiny", true)); static { instance.register(Serializable.class, instance.loadEncoder(Object.class)); @@ -40,6 +40,7 @@ public final class JsonFactory extends ConvertFactory { this.register(InetSocketAddress.class, InetAddressSimpledCoder.InetSocketAddressJsonSimpledCoder.instance); this.register(DLong.class, DLongSimpledCoder.DLongJsonSimpledCoder.instance); this.register(BigInteger.class, BigIntegerSimpledCoder.BigIntegerJsonSimpledCoder.instance); + this.register(BigDecimal.class, BigDecimalSimpledCoder.BigDecimalJsonSimpledCoder.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); @@ -64,7 +65,7 @@ public final class JsonFactory extends ConvertFactory { } public static JsonFactory create() { - return new JsonFactory(null, getSystemPropertyBoolean("redkale.convert.json.tiny", "convert.tiny", true)); + return new JsonFactory(null, getSystemPropertyBoolean("redkale.convert.json.tiny", "redkale.convert.tiny", true)); } @Override @@ -77,6 +78,11 @@ public final class JsonFactory extends ConvertFactory { return super.createObjectEncoder(type); } + @Override + protected Decodeable createMultiImplDecoder(Class[] types) { + return new JsonMultiImplDecoder(this, types); + } + protected boolean tiny() { return this.tiny; } diff --git a/src/main/java/org/redkale/convert/json/JsonMultiArrayDecoder.java b/src/main/java/org/redkale/convert/json/JsonMultiArrayDecoder.java new file mode 100644 index 000000000..ce03aa798 --- /dev/null +++ b/src/main/java/org/redkale/convert/json/JsonMultiArrayDecoder.java @@ -0,0 +1,62 @@ +/* + */ +package org.redkale.convert.json; + +import java.lang.reflect.Type; +import java.util.*; +import org.redkale.convert.*; + +/** + * 鏁扮粍鏁版嵁涓寘鍚笉鍚孴ype鐨勫弽搴忓垪鍖栬В鏋愬櫒
+ * 濡: ['aaa',{'name':'hahah'}], 闇瑕佷袱涓猅ype鏉ュ弽搴忓垪鍖(String, Map<String, String>)
+ * 娉ㄦ剰: type鐨勪釜鏁板繀椤诲ぇ浜庢垨绛変簬缁撴灉鏁扮粍鍏冪礌涓暟锛 姝よВ鏋愬櫒瀵硅薄涓嶄細琚紦瀛橈紝姣忔閮戒細鍒涘缓鏂板疄渚 + * + * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.7.0 + */ +public class JsonMultiArrayDecoder implements Decodeable { + + protected final JsonFactory factory; + + protected final Type[] types; + + protected final Decodeable[] decoders; + + public JsonMultiArrayDecoder(final JsonFactory factory, final Type[] types) { + this.factory = factory; + this.types = types; + this.decoders = new Decodeable[types.length]; + for (int i = 0; i < types.length; i++) { + this.decoders[i] = factory.loadDecoder(types[i]); + } + } + + @Override + public Object[] convertFrom(JsonReader in) { + return convertFrom(in, null); + } + + public Object[] convertFrom(JsonReader in, DeMember member) { + int len = in.readArrayB(member, null, null); + if (len == Reader.SIGN_NULL) return null; + //len must be Reader.SIGN_NOLENGTH + final List result = new ArrayList(); + int startPosition = in.position(); + int index = -1; + final Decodeable[] coders = this.decoders; + while (in.hasNext(startPosition, -1)) { + result.add(coders[++index % coders.length].convertFrom(in)); + } + in.readArrayE(); + return result.toArray(new Object[result.size()]); + } + + @Override + public Type getType() { + return Object[].class; + } + +} diff --git a/src/main/java/org/redkale/convert/json/JsonMultiImplDecoder.java b/src/main/java/org/redkale/convert/json/JsonMultiImplDecoder.java new file mode 100644 index 000000000..4f58e5253 --- /dev/null +++ b/src/main/java/org/redkale/convert/json/JsonMultiImplDecoder.java @@ -0,0 +1,181 @@ +/* + */ +package org.redkale.convert.json; + +import java.lang.reflect.Type; +import java.util.*; +import org.redkale.convert.*; +import org.redkale.util.*; + +/** + * 鎶借薄鎴栨帴鍙g被瀛樺湪澶氱瀹炵幇绫荤殑鍙嶅簭鍒楀寲瑙f瀽鍣
+ * + * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param 娉涘瀷 + * + * @since 2.7.0 + */ +public class JsonMultiImplDecoder implements Decodeable { + + protected final JsonFactory factory; + + protected final Class[] types; + + protected final ObjectDecoder[] decoders; + + protected final int maxMemberCount; + + protected final ObjectDecoder firstDecoder; + + protected final Map repeatFieldToDecoders = new HashMap<>(); + + protected final Map uniqueFieldToDecoders = new HashMap<>(); + + public JsonMultiImplDecoder(final JsonFactory factory, final Class[] types) { + this.factory = factory; + this.types = types; + this.decoders = new ObjectDecoder[types.length]; + int max = 0; + Set[] fields = new Set[types.length]; + Set[] movsets = new Set[types.length]; + Map fieldTypes = new HashMap<>(); + for (int i = 0; i < types.length; i++) { + movsets[i] = new HashSet(); + fields[i] = new HashSet<>(); + ObjectDecoder decoder = (ObjectDecoder) factory.loadDecoder(types[i]); + if (decoder.getMembers().length > max) { + max = decoder.getMembers().length; + } + for (DeMember member : decoder.getMembers()) { + String name = member.getAttribute().field(); + this.repeatFieldToDecoders.put(name, decoder); + fields[i].add(name); + Attribute t = fieldTypes.get(name); + if (t == null) { + fieldTypes.put(name, member.getAttribute()); + } else if (!member.getAttribute().genericType().equals(t.genericType())) { + throw new RuntimeException("Field(" + name + ")'s Type is not same in " + member.getAttribute().declaringClass() + " and " + t.declaringClass()); + } + } + this.decoders[i] = decoder; + } + this.maxMemberCount = max; + + for (int i = 0; i < fields.length; i++) { + Set removes = movsets[i]; + for (String s : fields[i]) { + boolean repeat = false; + for (int j = 0; j < fields.length; j++) { + if (j == i) continue; + if (fields[j].contains(s)) { + repeat = true; + break; + } + } + if (repeat) removes.add(s); + } + } + + int min = max + 1; + ObjectDecoder first = null; //瀛楁鏈灏戠殑绫讳綔涓洪粯璁ゅ弽瑙f瀽鍣 + for (int i = 0; i < fields.length; i++) { + Set fieldSet = fields[i]; + for (String s : movsets[i]) { + fieldSet.remove(s); //绉婚櫎閲嶅鐨勫瓧娈 + } + if (fieldSet.size() < min) { + first = this.decoders[i]; + min = fieldSet.size(); + } + for (String s : fieldSet) { + this.uniqueFieldToDecoders.put(s, this.decoders[i]); + this.repeatFieldToDecoders.remove(s); + } + } + this.firstDecoder = first; + } + + @Override + public T convertFrom(JsonReader in) { + final String clazz = in.readObjectB(null); + if (clazz == null) return null; + ObjectDecoder decoder = this.firstDecoder; + Map uniques = this.uniqueFieldToDecoders; + Map repeats = this.repeatFieldToDecoders; + int index = -1; + boolean finaled = false; + final Object[][] params = new Object[this.maxMemberCount][2]; + while (in.hasNext()) { + String fieldName = in.readFieldName(); + DeMember member = decoder.getMember(fieldName); + //new Set[]{Utility.ofSet("1", "2", "3"), Utility.ofSet("2", "3"), Utility.ofSet("4", "2", "3"), Utility.ofSet("6", "7", "8"), Utility.ofSet("6", "9")}; + if (member == null && !finaled) { + ObjectDecoder de = uniques.get(fieldName); + if (de == null) { + de = repeats.get(fieldName); + if (de != null) { + decoder = de; + member = de.getMember(fieldName); + for (int i = 0; i <= index; i++) { //杩佺Щparams涓殑DeMember.Attribute + if (params[i] != null) { + DeMember dm = de.getMember(((Attribute) params[i][0]).field()); + params[i][0] = dm == null ? null : dm.getAttribute(); + } + } + } + } else { + finaled = true; + decoder = de; + member = de.getMember(fieldName); + for (int i = 0; i <= index; i++) { //杩佺Щparams涓殑DeMember.Attribute + if (params[i] != null) { + DeMember dm = de.getMember(((Attribute) params[i][0]).field()); + params[i][0] = dm == null ? null : dm.getAttribute(); + } + } + } + } + in.readBlank(); + if (member == null) { + in.skipValue(); //璺宠繃涓嶅瓨鍦ㄧ殑灞炴х殑鍊 + } else { + params[++index] = new Object[]{member.getAttribute(), member.read(in)}; + } + } + in.readObjectE(null); + if (decoder.getConstructorMembers() == null) { //绌烘瀯閫犲嚱鏁 + T result = (T) decoder.getCreator().create(); + for (int i = 0; i <= index; i++) { + ((Attribute) params[i][0]).set(result, params[i][1]); + } + return result; + } else { + final DeMember[] constructorFields = decoder.getConstructorMembers(); + final Object[] constructorParams = new Object[constructorFields.length]; + for (int i = 0; i < constructorFields.length; i++) { + for (int j = 0; j < params.length; j++) { + if (params[j] != null && params[j][0] != null + && constructorFields[i].getAttribute().field().equals(((Attribute) params[j][0]).field())) { + constructorParams[i] = params[j][1]; + params[j] = null; + break; + } + } + } + final T result = (T) decoder.getCreator().create(constructorParams); + for (int i = 0; i < params.length; i++) { + if (params[i] != null && params[i][0] != null) { + ((Attribute) params[i][0]).set(result, params[i][1]); + } + } + return result; + } + } + + @Override + public Type getType() { + return Object.class; + } +} diff --git a/src/main/java/org/redkale/convert/json/JsonReader.java b/src/main/java/org/redkale/convert/json/JsonReader.java index 17c4683b7..71cfdd1f0 100644 --- a/src/main/java/org/redkale/convert/json/JsonReader.java +++ b/src/main/java/org/redkale/convert/json/JsonReader.java @@ -5,6 +5,7 @@ */ package org.redkale.convert.json; +import java.util.Map; import org.redkale.convert.*; import static org.redkale.convert.Reader.*; import org.redkale.util.*; @@ -76,7 +77,7 @@ public class JsonReader extends Reader { public final void seek(String key) { if (key == null || key.length() < 1) return; final String[] keys = key.split("\\."); - nextGoodChar(); //璇绘帀 { [ + nextGoodChar(true); //璇绘帀 { [ for (String key1 : keys) { while (this.hasNext()) { String field = this.readSmallString(); @@ -93,7 +94,7 @@ public class JsonReader extends Reader { */ @Override public final void skipValue() { - final char ch = nextGoodChar(); + final char ch = nextGoodChar(true); switch (ch) { case '"': case '\'': @@ -131,20 +132,46 @@ public class JsonReader extends Reader { * @return 绌虹櫧瀛楃鎴栨湁鏁堝瓧绗 */ protected char nextChar() { - return this.text[++this.position]; + int p = ++this.position; + if (p >= text.length) return 0; + return this.text[p]; } /** - * 璺宠繃绌虹櫧瀛楃锛 杩斿洖涓涓潪绌虹櫧瀛楃 + * 璺宠繃绌虹櫧瀛楃銆佸崟琛屾垨澶氳娉ㄩ噴锛 杩斿洖涓涓潪绌虹櫧瀛楃 + * + * @param allowComment 鏄惁瀹硅鍚敞閲 * * @return 鏈夋晥瀛楃 */ - protected char nextGoodChar() { - char c = nextChar(); - if (c > ' ') return c; + protected char nextGoodChar(boolean allowComment) { + char c; for (;;) { c = nextChar(); - if (c > ' ') return c; + if (c == 0) return c;// 0 琛ㄧずbuffer缁撳熬浜 + if (c > ' ') { + if (allowComment && c == '/') { //鏀寔鍗曡鍜屽琛屾敞閲 + char n = nextChar(); + if (n == '/') { + for (;;) { + if (nextChar() == '\n') break; + } + return nextGoodChar(allowComment); + } else if (n == '*') { + char nc; + char lc = 0; + for (;;) { + nc = nextChar(); + if (nc == '/' && lc == '*') break; + lc = nc; + } + return nextGoodChar(allowComment); + } else { + throw new ConvertException("illegal escape(" + n + ") (position = " + this.position + ") in '" + new String(text) + "'"); + } + } + return c; + } } } @@ -157,9 +184,31 @@ public class JsonReader extends Reader { this.position--; } + /** + * 鏄惁{寮澶寸殑瀵硅薄瀛楃 + * + * @return 鏄惁瀵硅薄瀛楃 + */ + public boolean isNextObject() { + char ch = nextGoodChar(true); + backChar(ch); + return ch == '{'; + } + + /** + * 鏄惁[寮澶寸殑鏁扮粍瀛楃 + * + * @return 鏄惁鏁扮粍瀛楃 + */ + public boolean isNextArray() { + char ch = nextGoodChar(true); + backChar(ch); + return ch == '['; + } + @Override public final ValueType readType() { - char ch = nextGoodChar(); + char ch = nextGoodChar(true); if (ch == '{') { backChar(ch); return ValueType.MAP; @@ -183,15 +232,8 @@ public class JsonReader extends Reader { public String readObjectB(final Class clazz) { this.fieldIndex = 0; //蹇呴』瑕侀噸缃负0 if (this.text.length == 0) return null; - char ch = this.text[++this.position]; + char ch = nextGoodChar(true); 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) + ")"); @@ -232,17 +274,9 @@ public class JsonReader extends Reader { @Override public int readArrayB(DeMember member, byte[] typevals, Decodeable componentDecoder) { if (this.text.length == 0) return SIGN_NULL; - char ch = this.text[++this.position]; + char ch = nextGoodChar(true); 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) + ")"); @@ -257,15 +291,8 @@ public class JsonReader extends Reader { */ @Override public void readBlank() { - char ch = this.text[++this.position]; + char ch = nextGoodChar(true); 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) + ")"); } @@ -289,17 +316,14 @@ public class JsonReader extends Reader { */ @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; + char ch = nextGoodChar(true); + if (ch == ',') { + char nt = nextGoodChar(true); + if (nt == '}' || nt == ']') return false; + this.position--; + return true; } + if (ch == '}' || ch == ']') return false; this.position--; // { [ 浜ょ敱 readObjectB 鎴 readMapB 鎴 readArrayB 璇诲彇 return true; } @@ -313,15 +337,9 @@ public class JsonReader extends Reader { public String readSmallString() { final int eof = this.limit; if (this.position == eof) return null; + char ch = nextGoodChar(true); //闇瑕佽烦杩囨敞閲 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; @@ -363,55 +381,84 @@ public class JsonReader extends Reader { */ @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; - } - } + char firstchar = nextGoodChar(true); 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; - } + firstchar = nextGoodChar(false); + 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 = " + currpos + ") in (" + new String(this.text) + ")"); + if (firstchar == '+') firstchar = nextChar(); //鍏煎+寮澶寸殑 + if (firstchar < '0' || firstchar > '9') throw new ConvertException("illegal escape(" + firstchar + ") (position = " + position + ")"); value = firstchar - '0'; } + if (firstchar == 'N') { + if (negative) throw new ConvertException("illegal escape(" + firstchar + ") (position = " + position + ")"); + char c = nextChar(); + if (c != 'a') throw new ConvertException("illegal escape(" + c + ") (position = " + position + ")"); + c = nextChar(); + if (c != 'N') throw new ConvertException("illegal escape(" + c + ") (position = " + position + ")"); + if (quote) { + c = nextChar(); + if (c != '"' && c != '\'') throw new ConvertException("illegal escape(" + c + ") (position = " + position + ")"); + } + return 0; //NaN 杩斿洖0; + } else if (firstchar == 'I') { //Infinity + char c = nextChar(); + if (c != 'n') throw new ConvertException("illegal escape(" + c + ") (position = " + position + ")"); + c = nextChar(); + if (c != 'f') throw new ConvertException("illegal escape(" + c + ") (position = " + position + ")"); + c = nextChar(); + if (c != 'i') throw new ConvertException("illegal escape(" + c + ") (position = " + position + ")"); + c = nextChar(); + if (c != 'n') throw new ConvertException("illegal escape(" + c + ") (position = " + position + ")"); + c = nextChar(); + if (c != 'i') throw new ConvertException("illegal escape(" + c + ") (position = " + position + ")"); + c = nextChar(); + if (c != 't') throw new ConvertException("illegal escape(" + c + ") (position = " + position + ")"); + c = nextChar(); + if (c != 'y') throw new ConvertException("illegal escape(" + c + ") (position = " + position + ")"); + if (quote) { + c = nextChar(); + if (c != '"' && c != '\'') throw new ConvertException("illegal escape(" + c + ") (position = " + position + ")"); + } + return negative ? Integer.MIN_VALUE : Integer.MAX_VALUE; + } + boolean hex = false; 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) + ")"); + char ch = nextChar(); + if (ch == 0) break; + if (ch >= '0' && ch <= '9') { + if (dot) continue; + value = (hex ? (value << 4) : ((value << 3) + (value << 1))) + digits[ch]; + } else if (ch == '"' || ch == '\'') { + if (quote) break; + throw new ConvertException("illegal escape(" + ch + ") (position = " + position + ")"); + } else if (ch == 'x' || ch == 'X') { + if (value != 0) throw new ConvertException("illegal escape(" + ch + ") (position = " + position + ")"); + hex = true; + } else if (ch >= 'a' && ch <= 'f') { + if (!hex) throw new ConvertException("illegal escape(" + ch + ") (position = " + position + ")"); + if (dot) continue; + value = (value << 4) + digits[ch]; + } else if (ch >= 'A' && ch <= 'F') { + if (!hex) throw new ConvertException("illegal escape(" + ch + ") (position = " + position + ")"); + if (dot) continue; + value = (value << 4) + digits[ch]; + } else if (quote && ch <= ' ') { + } else if (ch == '.') { + dot = true; + } else if (ch == ',' || ch == '}' || ch == ']' || ch <= ' ' || ch == ':') { + backChar(ch); + break; + } else { + throw new ConvertException("illegal escape(" + ch + ") (position = " + position + ")"); } - if (val != -2) value = value * 10 + val; } - this.position = currpos - 1; return negative ? -value : value; } @@ -422,72 +469,105 @@ public class JsonReader extends Reader { */ @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; - } - } + char firstchar = nextGoodChar(true); 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; - } + firstchar = nextGoodChar(false); + 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 = " + currpos + ") in (" + new String(this.text) + ")"); + if (firstchar == '+') firstchar = nextChar(); //鍏煎+寮澶寸殑 + if (firstchar < '0' || firstchar > '9') throw new ConvertException("illegal escape(" + firstchar + ") (position = " + position + ")"); value = firstchar - '0'; } + if (firstchar == 'N') { + if (negative) throw new ConvertException("illegal escape(" + firstchar + ") (position = " + position + ")"); + char c = nextChar(); + if (c != 'a') throw new ConvertException("illegal escape(" + c + ") (position = " + position + ")"); + c = nextChar(); + if (c != 'N') throw new ConvertException("illegal escape(" + c + ") (position = " + position + ")"); + if (quote) { + c = nextChar(); + if (c != '"' && c != '\'') throw new ConvertException("illegal escape(" + c + ") (position = " + position + ")"); + } + return 0L; //NaN 杩斿洖0; + } else if (firstchar == 'I') { //Infinity + char c = nextChar(); + if (c != 'n') throw new ConvertException("illegal escape(" + c + ") (position = " + position + ")"); + c = nextChar(); + if (c != 'f') throw new ConvertException("illegal escape(" + c + ") (position = " + position + ")"); + c = nextChar(); + if (c != 'i') throw new ConvertException("illegal escape(" + c + ") (position = " + position + ")"); + c = nextChar(); + if (c != 'n') throw new ConvertException("illegal escape(" + c + ") (position = " + position + ")"); + c = nextChar(); + if (c != 'i') throw new ConvertException("illegal escape(" + c + ") (position = " + position + ")"); + c = nextChar(); + if (c != 't') throw new ConvertException("illegal escape(" + c + ") (position = " + position + ")"); + c = nextChar(); + if (c != 'y') throw new ConvertException("illegal escape(" + c + ") (position = " + position + ")"); + if (quote) { + c = nextChar(); + if (c != '"' && c != '\'') throw new ConvertException("illegal escape(" + c + ") (position = " + position + ")"); + } + return negative ? Long.MIN_VALUE : Long.MAX_VALUE; + } + boolean hex = false; 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) + ")"); + char ch = nextChar(); + if (ch == 0) break; + if (ch >= '0' && ch <= '9') { + if (dot) continue; + value = (hex ? (value << 4) : ((value << 3) + (value << 1))) + digits[ch]; + } else if (ch == '"' || ch == '\'') { + if (quote) break; + throw new ConvertException("illegal escape(" + ch + ") (position = " + position + ")"); + } else if (ch == 'x' || ch == 'X') { + if (value != 0) throw new ConvertException("illegal escape(" + ch + ") (position = " + position + ")"); + hex = true; + } else if (ch >= 'a' && ch <= 'f') { + if (!hex) throw new ConvertException("illegal escape(" + ch + ") (position = " + position + ")"); + if (dot) continue; + value = (value << 4) + digits[ch]; + } else if (ch >= 'A' && ch <= 'F') { + if (!hex) throw new ConvertException("illegal escape(" + ch + ") (position = " + position + ")"); + if (dot) continue; + value = (value << 4) + digits[ch]; + } else if (quote && ch <= ' ') { + } else if (ch == '.') { + dot = true; + } else if (ch == ',' || ch == '}' || ch == ']' || ch <= ' ' || ch == ':') { + backChar(ch); + break; + } else { + throw new ConvertException("illegal escape(" + ch + ") (position = " + position + ")"); } - if (val != -2) value = value * 10 + val; } - this.position = currpos - 1; return negative ? -value : value; } + public final String readFieldName() { + return this.readSmallString(); + } + @Override - public final DeMember readFieldName(final DeMember[] members) { - final String exceptedfield = this.readSmallString(); - if (exceptedfield == null) return null; + public final DeMember readFieldName(final DeMember[] members, Map memberFieldMap, Map memberTagMap) { + 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())) { + 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())) { + if (exceptedField.equals(members[k].getAttribute().field())) { this.fieldIndex = k; return members[k]; } @@ -557,7 +637,11 @@ public class JsonReader extends Reader { String chars = readSmallString(); if (chars != null) chars = chars.trim(); if (chars == null || chars.isEmpty()) return 0.f; - return Float.parseFloat(chars); + switch (chars) { + case "Infinity": return (float) Double.POSITIVE_INFINITY; + case "-Infinity": return (float) Double.NEGATIVE_INFINITY; + default: return Float.parseFloat(chars); //Float.parseFloat鑳借瘑鍒玁aN + } } @Override @@ -565,7 +649,11 @@ public class JsonReader extends Reader { String chars = readSmallString(); if (chars != null) chars = chars.trim(); if (chars == null || chars.isEmpty()) return 0.0; - return Double.parseDouble(chars); + switch (chars) { + case "Infinity": return Double.POSITIVE_INFINITY; + case "-Infinity": return Double.NEGATIVE_INFINITY; + default: return Double.parseDouble(chars); //Double.parseDouble鑳借瘑鍒玁aN + } } /** @@ -576,14 +664,8 @@ public class JsonReader extends Reader { @Override public String readString() { final char[] text0 = this.text; + char expected = nextGoodChar(true); 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') { diff --git a/src/main/java/org/redkale/convert/json/JsonStreamWriter.java b/src/main/java/org/redkale/convert/json/JsonStreamWriter.java index ad989ebc5..40010235e 100644 --- a/src/main/java/org/redkale/convert/json/JsonStreamWriter.java +++ b/src/main/java/org/redkale/convert/json/JsonStreamWriter.java @@ -88,7 +88,7 @@ class JsonStreamWriter extends JsonByteBufferWriter { } /** - * 娉ㄦ剰锛 璇tring鍊间笉鑳戒负null涓斾笉浼氳繘琛岃浆涔夛紝 鍙敤浜庝笉鍚渶瑕佽浆涔夊瓧绗︾殑瀛楃涓诧紝渚嬪enum銆乨ouble銆丅igInteger杞崲鐨凷tring + * 娉ㄦ剰锛 璇tring鍊间笉鑳戒负null涓斾笉浼氳繘琛岃浆涔夛紝 鍙敤浜庝笉鍚渶瑕佽浆涔夊瓧绗︾殑瀛楃涓诧紝渚嬪enum銆乨ouble銆丅igInteger銆丅igDecimal杞崲鐨凷tring * * @param quote 鏄惁鍐欏叆鍙屽紩鍙 * @param value String鍊 diff --git a/src/main/java/org/redkale/convert/json/JsonWriter.java b/src/main/java/org/redkale/convert/json/JsonWriter.java index 96c150e97..fd84788ab 100644 --- a/src/main/java/org/redkale/convert/json/JsonWriter.java +++ b/src/main/java/org/redkale/convert/json/JsonWriter.java @@ -21,7 +21,7 @@ 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; + protected boolean tiny = JsonFactory.root().tiny(); @Override public boolean tiny() { @@ -47,7 +47,7 @@ public abstract class JsonWriter extends Writer { public abstract void writeTo(final byte[] chs, final int start, final int len); //鍙兘鏄 0 - 127 鐨勫瓧绗 /** - * 娉ㄦ剰锛 璇tring鍊间笉鑳戒负null涓斾笉浼氳繘琛岃浆涔夛紝 鍙敤浜庝笉鍚渶瑕佽浆涔夊瓧绗︾殑瀛楃涓诧紝渚嬪enum銆乨ouble銆丅igInteger杞崲鐨凷tring + * 娉ㄦ剰锛 璇tring鍊间笉鑳戒负null涓斾笉浼氳繘琛岃浆涔夛紝 鍙敤浜庝笉鍚渶瑕佽浆涔夊瓧绗︾殑瀛楃涓诧紝渚嬪enum銆乨ouble銆丅igInteger銆丅igDecimal杞崲鐨凷tring * * @param quote 鏄惁鍔犲弻寮曞彿 * @param value 闈瀗ull涓斾笉鍚渶瑕佽浆涔夌殑瀛楃鐨凷tring鍊 @@ -85,6 +85,8 @@ public abstract class JsonWriter extends Writer { @Override public abstract void writeLong(long value); + public abstract void writeString(final boolean quote, String value); + @Override public abstract void writeString(String value); @@ -156,7 +158,7 @@ public abstract class JsonWriter extends Writer { @Override public final void writeWrapper(StringWrapper value) { - writeLatin1To(false, String.valueOf(value)); + writeString(false, String.valueOf(value)); } @Override diff --git a/src/main/java/org/redkale/mq/HttpMessageClusterClient.java b/src/main/java/org/redkale/mq/HttpMessageClusterClient.java index bd03e57bc..342e22ff9 100644 --- a/src/main/java/org/redkale/mq/HttpMessageClusterClient.java +++ b/src/main/java/org/redkale/mq/HttpMessageClusterClient.java @@ -94,7 +94,7 @@ public class HttpMessageClusterClient extends HttpMessageClient { } final Map clientHeaders = new LinkedHashMap<>(); byte[] clientBody = null; - if (req.isRpc()) clientHeaders.put(Rest.REST_HEADER_RPC_NAME, "true"); + if (req.isRpc()) clientHeaders.put(Rest.REST_HEADER_RPC, "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()); @@ -148,7 +148,7 @@ public class HttpMessageClusterClient extends HttpMessageClient { } final Map clientHeaders = new LinkedHashMap<>(); byte[] clientBody = null; - if (req.isRpc()) clientHeaders.put(Rest.REST_HEADER_RPC_NAME, "true"); + if (req.isRpc()) clientHeaders.put(Rest.REST_HEADER_RPC, "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()); diff --git a/src/main/java/org/redkale/mq/HttpMessageLocalClient.java b/src/main/java/org/redkale/mq/HttpMessageLocalClient.java index bb2fab6c4..76b51fa30 100644 --- a/src/main/java/org/redkale/mq/HttpMessageLocalClient.java +++ b/src/main/java/org/redkale/mq/HttpMessageLocalClient.java @@ -16,6 +16,7 @@ import org.redkale.boot.*; import org.redkale.convert.*; import org.redkale.convert.json.JsonConvert; import org.redkale.net.http.*; +import org.redkale.util.Traces; /** * 娌℃湁閰嶇疆MQ涓斾篃娌℃湁ClusterAgent鐨勬儏鍐典笅瀹炵幇鐨勯粯璁ttpMessageClient瀹炰緥 @@ -100,8 +101,9 @@ public class HttpMessageLocalClient extends HttpMessageClient { future.completeExceptionally(new RuntimeException("404 Not Found " + topic)); return future; } - HttpRequest req = new HttpMessageLocalRequest(context(), request); + HttpRequest req = new HttpMessageLocalRequest(context(), request, userid); HttpResponse resp = new HttpMessageLocalResponse(req, future); + Traces.createTraceid(); try { servlet.execute(req, resp); } catch (Exception e) { @@ -117,9 +119,10 @@ public class HttpMessageLocalClient extends HttpMessageClient { if (fine) logger.log(Level.FINE, "sendMessage: request=" + request + ", not found servlet"); return CompletableFuture.completedFuture(new HttpResult().status(404)); } - HttpRequest req = new HttpMessageLocalRequest(context(), request); + HttpRequest req = new HttpMessageLocalRequest(context(), request, userid); CompletableFuture future = new CompletableFuture(); HttpResponse resp = new HttpMessageLocalResponse(req, future); + Traces.createTraceid(); try { servlet.execute(req, resp); } catch (Exception e) { @@ -144,8 +147,9 @@ public class HttpMessageLocalClient extends HttpMessageClient { if (fine) logger.log(Level.FINE, "produceMessage: request=" + request + ", not found servlet"); return; } - HttpRequest req = new HttpMessageLocalRequest(context(), request); + HttpRequest req = new HttpMessageLocalRequest(context(), request, userid); HttpResponse resp = new HttpMessageLocalResponse(req, null); + Traces.createTraceid(); try { servlet.execute(req, resp); } catch (Exception e) { @@ -156,8 +160,9 @@ public class HttpMessageLocalClient extends HttpMessageClient { @Override public void broadcastMessage(String topic, Serializable userid, String groupid, HttpSimpleRequest request, AtomicLong counter) { HttpPrepareServlet ps = prepareServlet(); - HttpRequest req = new HttpMessageLocalRequest(context(), request); + HttpRequest req = new HttpMessageLocalRequest(context(), request, userid); HttpResponse resp = new HttpMessageLocalResponse(req, null); + Traces.createTraceid(); ps.filterServletsByMmcTopic(topic).forEach(s -> { try { s.execute(req, resp); @@ -169,8 +174,9 @@ public class HttpMessageLocalClient extends HttpMessageClient { public static class HttpMessageLocalRequest extends HttpRequest { - public HttpMessageLocalRequest(HttpContext context, HttpSimpleRequest req) { + public HttpMessageLocalRequest(HttpContext context, HttpSimpleRequest req, Serializable userid) { super(context, req); + if (userid != null) this.currentUserid = userid; } } @@ -218,7 +224,17 @@ public class HttpMessageLocalClient extends HttpMessageClient { @Override public void finish(final Convert convert, final Type type, Object obj) { if (future == null) return; - future.complete(obj); + if (obj instanceof CompletableFuture) { + ((CompletableFuture) obj).whenComplete((r, t) -> { + if (t == null) { + future.complete(r); + } else { + future.completeExceptionally((Throwable) t); + } + }); + } else { + future.complete(obj); + } } @Override diff --git a/src/main/java/org/redkale/mq/HttpMessageProcessor.java b/src/main/java/org/redkale/mq/HttpMessageProcessor.java index 27abd4c7f..2456d13d4 100644 --- a/src/main/java/org/redkale/mq/HttpMessageProcessor.java +++ b/src/main/java/org/redkale/mq/HttpMessageProcessor.java @@ -43,11 +43,11 @@ public class HttpMessageProcessor implements MessageProcessor { protected final HttpServlet servlet; - protected final boolean multiconsumer; + protected final boolean multiConsumer; - protected final String restmodule; // 鍓嶅悗鏈/, 渚嬪: /user/ + protected final String restModule; // 鍓嶅悗鏈/, 渚嬪: /user/ - protected final String multimodule; // 鍓嶅悗鏈/, 渚嬪: /userstat/ + protected final String multiModule; // 鍓嶅悗鏈/, 渚嬪: /userstat/ protected ThreadLocal> respPoolThreadLocal; @@ -57,7 +57,7 @@ public class HttpMessageProcessor implements MessageProcessor { protected CountDownLatch cdl; - protected long starttime; + protected long startTime; protected final Runnable innerCallback = () -> { if (cdl != null) cdl.countDown(); @@ -74,9 +74,9 @@ public class HttpMessageProcessor implements MessageProcessor { 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.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(), @@ -85,7 +85,7 @@ public class HttpMessageProcessor implements MessageProcessor { @Override public void begin(final int size, long starttime) { - this.starttime = starttime; + this.startTime = starttime; this.cdl = size > 1 ? new CountDownLatch(size) : null; } @@ -97,15 +97,16 @@ public class HttpMessageProcessor implements MessageProcessor { private void execute(final MessageRecord message, final Runnable callback) { HttpMessageRequest request = null; try { + Traces.currTraceid(message.getTraceid()); long now = System.currentTimeMillis(); - long cha = now - message.createtime; - long e = now - starttime; - if (multiconsumer) message.setResptopic(null); //涓嶅璁告湁鍝嶅簲 + 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)); + if (multiConsumer) request.setRequestURI(request.getRequestURI().replaceFirst(this.multiModule, this.restModule)); server.getHttpServer().getContext().execute(servlet, request, response); long o = System.currentTimeMillis() - now; @@ -117,9 +118,9 @@ public class HttpMessageProcessor implements MessageProcessor { 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()) { + 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)); + 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); } @@ -131,7 +132,7 @@ public class HttpMessageProcessor implements MessageProcessor { try { this.cdl.await(30, TimeUnit.SECONDS); } catch (Exception ex) { - logger.log(Level.SEVERE, HttpMessageProcessor.class.getSimpleName() + " commit error, restmodule=" + this.restmodule, ex); + logger.log(Level.SEVERE, HttpMessageProcessor.class.getSimpleName() + " commit error, restmodule=" + this.restModule, ex); } this.cdl = null; } diff --git a/src/main/java/org/redkale/mq/HttpMessageRequest.java b/src/main/java/org/redkale/mq/HttpMessageRequest.java index 1c42942bd..87fbaffe6 100644 --- a/src/main/java/org/redkale/mq/HttpMessageRequest.java +++ b/src/main/java/org/redkale/mq/HttpMessageRequest.java @@ -30,7 +30,7 @@ public class HttpMessageRequest extends HttpRequest { this.message = message; this.hashid = this.message.hash(); this.currentUserid = message.getUserid(); - this.createtime = System.currentTimeMillis(); + this.createTime = System.currentTimeMillis(); return this; } diff --git a/src/main/java/org/redkale/mq/HttpMessageResponse.java b/src/main/java/org/redkale/mq/HttpMessageResponse.java index 422302248..3d0ef390a 100644 --- a/src/main/java/org/redkale/mq/HttpMessageResponse.java +++ b/src/main/java/org/redkale/mq/HttpMessageResponse.java @@ -69,11 +69,11 @@ public class HttpMessageResponse extends HttpResponse { } 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); + finishHttpResult(this.finest, ((HttpMessageRequest) this.request).getRespConvert(), type, this.message, this.callback, this.messageClient, this.producer, message.getRespTopic(), result); } public void finishHttpResult(Type type, Convert respConvert, HttpResult result) { - finishHttpResult(this.finest, respConvert == null ? ((HttpMessageRequest) this.request).getRespConvert() : respConvert, type, this.message, this.callback, this.messageClient, this.producer, message.getResptopic(), result); + finishHttpResult(this.finest, respConvert == null ? ((HttpMessageRequest) this.request).getRespConvert() : respConvert, 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) { @@ -120,7 +120,7 @@ public class HttpMessageResponse extends HttpResponse { @Override public void finishJson(final JsonConvert convert, final Object obj) { - if (message.isEmptyResptopic()) { + if (message.isEmptyRespTopic()) { if (callback != null) callback.run(); return; } @@ -130,7 +130,7 @@ public class HttpMessageResponse extends HttpResponse { @Override public void finishJson(final Type type, final Object obj) { - if (message.isEmptyResptopic()) { + if (message.isEmptyRespTopic()) { if (callback != null) callback.run(); return; } @@ -139,7 +139,7 @@ public class HttpMessageResponse extends HttpResponse { @Override public void finishJson(final JsonConvert convert, final Type type, final Object obj) { - if (message.isEmptyResptopic()) { + if (message.isEmptyRespTopic()) { if (callback != null) callback.run(); return; } @@ -148,7 +148,7 @@ public class HttpMessageResponse extends HttpResponse { @Override public void finish(Type type, org.redkale.service.RetResult ret) { - if (message.isEmptyResptopic()) { + if (message.isEmptyRespTopic()) { if (callback != null) callback.run(); return; } @@ -158,7 +158,7 @@ public class HttpMessageResponse extends HttpResponse { @Override public void finish(final Convert convert, Type type, org.redkale.service.RetResult ret) { - if (message.isEmptyResptopic()) { + if (message.isEmptyRespTopic()) { if (callback != null) callback.run(); return; } @@ -167,7 +167,7 @@ public class HttpMessageResponse extends HttpResponse { @Override public void finish(final Convert convert, final Type type, Object obj) { - if (message.isEmptyResptopic()) { + if (message.isEmptyRespTopic()) { if (callback != null) callback.run(); return; } @@ -176,7 +176,7 @@ public class HttpMessageResponse extends HttpResponse { @Override public void finish(String obj) { - if (message.isEmptyResptopic()) { + if (message.isEmptyRespTopic()) { if (callback != null) callback.run(); return; } @@ -210,7 +210,7 @@ public class HttpMessageResponse extends HttpResponse { } else if (finest) { producer.logger.log(Level.FINEST, "HttpMessageResponse.finish status: " + status); } - if (this.message.isEmptyResptopic()) { + if (this.message.isEmptyRespTopic()) { if (callback != null) callback.run(); return; } @@ -219,7 +219,7 @@ public class HttpMessageResponse extends HttpResponse { @Override public void finish(final Convert convert, Type type, HttpResult result) { - if (message.isEmptyResptopic()) { + if (message.isEmptyRespTopic()) { if (callback != null) callback.run(); return; } @@ -229,7 +229,7 @@ public class HttpMessageResponse extends HttpResponse { @Override public void finish(boolean kill, final byte[] bs, int offset, int length) { - if (message.isEmptyResptopic()) { + if (message.isEmptyRespTopic()) { if (callback != null) callback.run(); return; } @@ -242,7 +242,7 @@ public class HttpMessageResponse extends HttpResponse { @Override public void finish(boolean kill, final String contentType, final byte[] bs, int offset, int length) { - if (message.isEmptyResptopic()) { + if (message.isEmptyRespTopic()) { if (callback != null) callback.run(); return; } @@ -252,7 +252,7 @@ public class HttpMessageResponse extends HttpResponse { @Override protected void finish(boolean kill, final String contentType, final byte[] bs, int offset, int length, Consumer consumer, A attachment) { - if (message.isEmptyResptopic()) { + if (message.isEmptyRespTopic()) { if (callback != null) callback.run(); return; } @@ -262,7 +262,7 @@ public class HttpMessageResponse extends HttpResponse { @Override public void finish(boolean kill, ByteBuffer buffer) { - if (message.isEmptyResptopic()) { + if (message.isEmptyRespTopic()) { if (callback != null) callback.run(); return; } @@ -273,7 +273,7 @@ public class HttpMessageResponse extends HttpResponse { @Override public void finish(boolean kill, ByteBuffer... buffers) { - if (message.isEmptyResptopic()) { + if (message.isEmptyRespTopic()) { if (callback != null) callback.run(); return; } diff --git a/src/main/java/org/redkale/mq/MessageAgent.java b/src/main/java/org/redkale/mq/MessageAgent.java index e1f7c953a..7d9af20f9 100644 --- a/src/main/java/org/redkale/mq/MessageAgent.java +++ b/src/main/java/org/redkale/mq/MessageAgent.java @@ -58,14 +58,31 @@ public abstract class MessageAgent { protected int producerCount = 1; + protected MessageCoder messageCoder = MessageRecordCoder.getInstance(); + //鏈湴Service娑堟伅鎺ユ敹澶勭悊鍣紝 key:consumer protected HashMap messageNodes = new LinkedHashMap<>(); - public void init(AnyValue config) { + public void init(ResourceFactory factory, 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()); + String coderType = config.getValue("coder", ""); + if (!coderType.trim().isEmpty()) { + try { + Class> coderClass = (Class) Thread.currentThread().getContextClassLoader().loadClass(coderType); + RedkaleClassLoader.putReflectionPublicConstructors(coderClass, coderClass.getName()); + MessageCoder coder = coderClass.getConstructor().newInstance(); + if (factory != null) factory.inject(coder); + if (coder instanceof Service) ((Service) coder).init(config); + this.messageCoder = coder; + } catch (RuntimeException ex) { + throw ex; + } catch (Exception e) { + throw new RuntimeException(e); + } + } // application (it doesn't execute completion handlers). this.timeoutExecutor = (ScheduledThreadPoolExecutor) Executors.newScheduledThreadPool(1, (Runnable r) -> { Thread t = new Thread(r); @@ -102,6 +119,7 @@ public abstract class MessageAgent { if (this.timeoutExecutor != null) this.timeoutExecutor.shutdown(); if (this.sncpProducer != null) this.sncpProducer.shutdown().join(); if (this.httpProducer != null) this.httpProducer.shutdown().join(); + if (this.messageCoder instanceof Service) ((Service) this.messageCoder).destroy(config); } protected List getAllMessageConsumer() { @@ -125,6 +143,10 @@ public abstract class MessageAgent { return producers; } + public MessageCoder getMessageCoder() { + return this.messageCoder; + } + public Logger getLogger() { return logger; } diff --git a/src/main/java/org/redkale/mq/MessageClient.java b/src/main/java/org/redkale/mq/MessageClient.java index 05a31985f..e1eaabcf2 100644 --- a/src/main/java/org/redkale/mq/MessageClient.java +++ b/src/main/java/org/redkale/mq/MessageClient.java @@ -13,6 +13,7 @@ import org.redkale.convert.Convert; import org.redkale.convert.json.JsonConvert; import static org.redkale.mq.MessageRecord.*; import org.redkale.net.http.*; +import org.redkale.util.*; /** * @@ -76,7 +77,7 @@ public abstract class MessageClient { if (node.scheduledFuture != null) node.scheduledFuture.cancel(true); AtomicLong ncer = node.getCounter(); if (ncer != null) ncer.decrementAndGet(); - final long cha = now - msg.createtime; + final long cha = now - msg.createTime; if (finest) messageAgent.logger.log(Level.FINEST, clazzName + ".MessageRespFutureNode.receive (mq.delay = " + cha + "ms, mq.seqid = " + msg.getSeqid() + ")"); node.future.complete(msg); long cha2 = System.currentTimeMillis() - now; @@ -97,8 +98,8 @@ public abstract class MessageClient { } } } - if (needresp && (message.getResptopic() == null || message.getResptopic().isEmpty())) { - message.setResptopic(respTopic); + if (needresp && (message.getRespTopic() == null || message.getRespTopic().isEmpty())) { + message.setRespTopic(respTopic); } if (counter != null) counter.incrementAndGet(); getProducer().apply(message); @@ -126,47 +127,59 @@ public abstract class MessageClient { 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)); + return new MessageRecord(msgSeqno.incrementAndGet(), CTYPE_STRING, 1, 0, System.currentTimeMillis(), 0, null, null, resptopic, Traces.createTraceid(), 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)); + return new MessageRecord(msgSeqno.incrementAndGet(), CTYPE_STRING, 1, 0, System.currentTimeMillis(), 0, null, topic, resptopic, Traces.createTraceid(), content == null ? null : content.getBytes(StandardCharsets.UTF_8)); + } + + public MessageRecord createMessageRecord(String topic, String resptopic, String traceid, String content) { + return new MessageRecord(msgSeqno.incrementAndGet(), CTYPE_STRING, 1, 0, System.currentTimeMillis(), 0, null, topic, resptopic, traceid, 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)); + return new MessageRecord(msgSeqno.incrementAndGet(), CTYPE_STRING, 1, 0, System.currentTimeMillis(), userid, null, topic, resptopic, Traces.createTraceid(), content == null ? null : content.getBytes(StandardCharsets.UTF_8)); + } + + public MessageRecord createMessageRecord(int userid, String topic, String resptopic, String traceid, String content) { + return new MessageRecord(msgSeqno.incrementAndGet(), CTYPE_STRING, 1, 0, System.currentTimeMillis(), userid, null, topic, resptopic, traceid, 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)); + return new MessageRecord(msgSeqno.incrementAndGet(), ctype(convert, bean), 1, 0, System.currentTimeMillis(), 0, null, topic, resptopic, Traces.createTraceid(), convert.convertToBytes(bean)); + } + + public MessageRecord createMessageRecord(String topic, String resptopic, String traceid, Convert convert, Object bean) { + return new MessageRecord(msgSeqno.incrementAndGet(), ctype(convert, bean), 1, 0, System.currentTimeMillis(), 0, null, topic, resptopic, traceid, 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)); + return new MessageRecord(msgSeqno.incrementAndGet(), ctype(convert, bean), 1, 0, System.currentTimeMillis(), userid, null, topic, resptopic, Traces.createTraceid(), 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)); + return new MessageRecord(msgSeqno.incrementAndGet(), ctype(convert, bean), 1, 0, System.currentTimeMillis(), userid, groupid, topic, resptopic, Traces.createTraceid(), 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)); + return new MessageRecord(msgSeqno.incrementAndGet(), ctype(convert, bean), 1, flag, System.currentTimeMillis(), userid, groupid, topic, resptopic, Traces.createTraceid(), convert.convertToBytes(bean)); } public MessageRecord createMessageRecord(String topic, String resptopic, byte[] content) { - return new MessageRecord(msgSeqno.incrementAndGet(), (byte) 0, topic, resptopic, content); + return new MessageRecord(msgSeqno.incrementAndGet(), (byte) 0, topic, resptopic, Traces.createTraceid(), content); } public MessageRecord createMessageRecord(long seqid, String topic, String resptopic, byte[] content) { - return new MessageRecord(seqid, (byte) 0, topic, resptopic, content); + return new MessageRecord(seqid, (byte) 0, topic, resptopic, Traces.createTraceid(), content); } protected MessageRecord createMessageRecord(byte ctype, String topic, String resptopic, byte[] content) { - return new MessageRecord(msgSeqno.incrementAndGet(), ctype, topic, resptopic, content); + return new MessageRecord(msgSeqno.incrementAndGet(), ctype, topic, resptopic, Traces.createTraceid(), content); } protected MessageRecord createMessageRecord(long seqid, byte ctype, String topic, String resptopic, byte[] content) { - return new MessageRecord(seqid, ctype, topic, resptopic, content); + return new MessageRecord(seqid, ctype, topic, resptopic, Traces.createTraceid(), content); } private byte ctype(Convert convert, Object bean) { diff --git a/src/main/java/org/redkale/mq/MessageRecord.java b/src/main/java/org/redkale/mq/MessageRecord.java index 2d78af8f7..a885ccd31 100644 --- a/src/main/java/org/redkale/mq/MessageRecord.java +++ b/src/main/java/org/redkale/mq/MessageRecord.java @@ -52,7 +52,7 @@ public class MessageRecord implements Serializable { @ConvertColumn(index = 4) @Comment("鍒涘缓鏃堕棿") - protected long createtime; + protected long createTime; @ConvertColumn(index = 5) @Comment("鐢ㄦ埛ID锛屾棤鐢ㄦ埛淇℃伅瑙嗕负null鎴0, 鍏蜂綋鏁版嵁绫诲瀷鍙兘鏄痠nt銆乴ong銆丼tring") //@since 2.5.0 鐢眎nt鏀规垚Serializable @@ -68,40 +68,45 @@ public class MessageRecord implements Serializable { @ConvertColumn(index = 8) @Comment("鐩爣topic, 涓虹┖琛ㄧず鏃犵洰鏍噒opic") - protected String resptopic; + protected String respTopic; @ConvertColumn(index = 9) + @Comment("閾捐矾ID") + protected String traceid; + + @ConvertColumn(index = 10) @Comment("娑堟伅鍐呭") protected byte[] content; - @ConvertColumn(index = 10) + @ConvertColumn(index = 11) @Comment("娑堟伅鍐呭鐨勭被鍨") protected byte ctype; @Comment("鏈湴闄勫姞瀵硅薄锛屼笉浼氳搴忓垪鍖") - protected Object localattach; + 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, String topic, String resptopic, String traceid, byte[] content) { + this(seqid, ctype, 1, 0, System.currentTimeMillis(), 0, null, topic, resptopic, traceid, 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 flag, Serializable userid, String groupid, String topic, String resptopic, String traceid, byte[] content) { + this(seqid, ctype, 1, flag, System.currentTimeMillis(), userid, groupid, topic, resptopic, traceid, content); } - protected MessageRecord(long seqid, byte ctype, int version, int flag, long createtime, Serializable userid, String groupid, String topic, String resptopic, byte[] content) { + protected MessageRecord(long seqid, byte ctype, int version, int flag, long createTime, Serializable userid, String groupid, String topic, String resptopic, String traceid, byte[] content) { this.seqid = seqid; this.ctype = ctype; this.version = version; this.flag = flag; - this.createtime = createtime; + this.createTime = createTime; this.userid = userid; this.groupid = groupid; this.topic = topic; - this.resptopic = resptopic; + this.respTopic = resptopic; + this.traceid = traceid; this.content = content; } @@ -110,7 +115,7 @@ public class MessageRecord implements Serializable { } public MessageRecord attach(Object attach) { - this.localattach = attach; + this.localAttach = attach; return this; } @@ -120,8 +125,13 @@ public class MessageRecord implements Serializable { } @ConvertDisabled - public boolean isEmptyResptopic() { - return this.resptopic == null || this.resptopic.isEmpty(); + public boolean isEmptyRespTopic() { + return this.respTopic == null || this.respTopic.isEmpty(); + } + + @ConvertDisabled + public boolean isEmptyTraceid() { + return this.traceid == null || this.traceid.isEmpty(); } public T convertFromContent(Convert convert, java.lang.reflect.Type type) { @@ -159,8 +169,8 @@ public class MessageRecord implements Serializable { return this; } - public MessageRecord createtime(long createtime) { - this.createtime = createtime; + public MessageRecord createTime(long createtime) { + this.createTime = createtime; return this; } @@ -179,8 +189,8 @@ public class MessageRecord implements Serializable { return this; } - public MessageRecord resptopic(String resptopic) { - this.resptopic = resptopic; + public MessageRecord respTopic(String resptopic) { + this.respTopic = resptopic; return this; } @@ -189,6 +199,11 @@ public class MessageRecord implements Serializable { return this; } + public MessageRecord traceid(String traceid) { + this.traceid = traceid; + return this; + } + public MessageRecord contentString(String content) { this.content = content == null ? null : content.getBytes(StandardCharsets.UTF_8); return this; @@ -218,12 +233,12 @@ public class MessageRecord implements Serializable { this.flag = flag; } - public long getCreatetime() { - return createtime; + public long getCreateTime() { + return createTime; } - public void setCreatetime(long createtime) { - this.createtime = createtime; + public void setCreateTime(long createTime) { + this.createTime = createTime; } public Serializable getUserid() { @@ -234,6 +249,14 @@ public class MessageRecord implements Serializable { this.userid = userid; } + public String getTraceid() { + return traceid; + } + + public void setTraceid(String traceid) { + this.traceid = traceid; + } + public String getGroupid() { return groupid; } @@ -250,12 +273,12 @@ public class MessageRecord implements Serializable { this.topic = topic; } - public String getResptopic() { - return resptopic; + public String getRespTopic() { + return respTopic; } - public void setResptopic(String resptopic) { - this.resptopic = resptopic; + public void setRespTopic(String respTopic) { + this.respTopic = respTopic; } public byte[] getContent() { @@ -273,11 +296,11 @@ public class MessageRecord implements Serializable { 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.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.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; //寰幆鍗犱綅绗 @@ -292,8 +315,8 @@ public class MessageRecord implements Serializable { 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 if (localAttach != null) { + sb.append(",\"attach\":").append(JsonConvert.root().convertTo(localAttach)); } else { sb.append(",\"content\":\"").append(new String(this.content, StandardCharsets.UTF_8)).append("\""); } diff --git a/src/main/java/org/redkale/mq/MessageRecordCoder.java b/src/main/java/org/redkale/mq/MessageRecordCoder.java index 34f0bd239..d95e97d32 100644 --- a/src/main/java/org/redkale/mq/MessageRecordCoder.java +++ b/src/main/java/org/redkale/mq/MessageRecordCoder.java @@ -29,10 +29,11 @@ public class MessageRecordCoder implements MessageCoder { @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()); + byte[] groupid = MessageCoder.getBytes(data.getGroupid()); + byte[] topic = MessageCoder.getBytes(data.getTopic()); + byte[] resptopic = MessageCoder.getBytes(data.getRespTopic()); + byte[] traceid = MessageCoder.getBytes(data.getTraceid()); int count = 8 //seqid + 1 //ctype + 4 //version @@ -40,8 +41,9 @@ public class MessageRecordCoder implements MessageCoder { + 8 //createtime + 2 + userid.length + 2 + groupid.length - + 2 + stopics.length - + 2 + dtopics.length + + 2 + topic.length + + 2 + resptopic.length + + 2 + traceid.length + 4 + (data.getContent() == null ? 0 : data.getContent().length); final byte[] bs = new byte[count]; ByteBuffer buffer = ByteBuffer.wrap(bs); @@ -49,15 +51,23 @@ public class MessageRecordCoder implements MessageCoder { buffer.put(data.ctype); buffer.putInt(data.getVersion()); buffer.putInt(data.getFlag()); - buffer.putLong(data.getCreatetime()); + 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); + + buffer.putChar((char) topic.length); + if (topic.length > 0) buffer.put(topic); + + buffer.putChar((char) resptopic.length); + if (resptopic.length > 0) buffer.put(resptopic); + + buffer.putChar((char) traceid.length); + if (traceid.length > 0) buffer.put(traceid); + if (data.getContent() == null) { buffer.putInt(0); } else { @@ -81,6 +91,7 @@ public class MessageRecordCoder implements MessageCoder { String groupid = MessageCoder.getShortString(buffer); String topic = MessageCoder.getShortString(buffer); String resptopic = MessageCoder.getShortString(buffer); + String traceid = MessageCoder.getShortString(buffer); byte[] content = null; int contentlen = buffer.getInt(); @@ -88,7 +99,7 @@ public class MessageRecordCoder implements MessageCoder { content = new byte[contentlen]; buffer.get(content); } - return new MessageRecord(seqid, ctype, version, flag, createtime, userid, groupid, topic, resptopic, content); + return new MessageRecord(seqid, ctype, version, flag, createtime, userid, groupid, topic, resptopic, traceid, content); } } diff --git a/src/main/java/org/redkale/mq/MessageRespFutureNode.java b/src/main/java/org/redkale/mq/MessageRespFutureNode.java index a25946c08..e4f8202c0 100644 --- a/src/main/java/org/redkale/mq/MessageRespFutureNode.java +++ b/src/main/java/org/redkale/mq/MessageRespFutureNode.java @@ -23,7 +23,7 @@ public class MessageRespFutureNode implements Runnable { protected final long seqid; - protected final long createtime; + protected final long createTime; protected final AtomicLong counter; @@ -44,14 +44,14 @@ public class MessageRespFutureNode implements Runnable { this.respNodes = respNodes; this.counter = counter; this.future = future; - this.createtime = System.currentTimeMillis(); + 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" + 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)) : "")); } @@ -59,8 +59,8 @@ public class MessageRespFutureNode implements Runnable { return seqid; } - public long getCreatetime() { - return createtime; + public long getCreateTime() { + return createTime; } public AtomicLong getCounter() { diff --git a/src/main/java/org/redkale/mq/SncpMessageProcessor.java b/src/main/java/org/redkale/mq/SncpMessageProcessor.java index f0b18a5fe..52c8e207d 100644 --- a/src/main/java/org/redkale/mq/SncpMessageProcessor.java +++ b/src/main/java/org/redkale/mq/SncpMessageProcessor.java @@ -10,6 +10,7 @@ import java.util.logging.*; import org.redkale.boot.NodeSncpServer; import org.redkale.net.sncp.*; import org.redkale.service.Service; +import org.redkale.util.Traces; /** * 涓涓猄ervice瀵瑰簲涓涓狹essageProcessor @@ -75,8 +76,9 @@ public class SncpMessageProcessor implements MessageProcessor { private void execute(final MessageRecord message, final Runnable callback) { SncpMessageResponse response = null; try { + Traces.currTraceid(message.getTraceid()); long now = System.currentTimeMillis(); - long cha = now - message.createtime; + long cha = now - message.createTime; long e = now - starttime; SncpContext context = server.getSncpServer().getContext(); SncpMessageRequest request = new SncpMessageRequest(context, message); diff --git a/src/main/java/org/redkale/mq/SncpMessageRequest.java b/src/main/java/org/redkale/mq/SncpMessageRequest.java index 75b6639a6..ffb07c16e 100644 --- a/src/main/java/org/redkale/mq/SncpMessageRequest.java +++ b/src/main/java/org/redkale/mq/SncpMessageRequest.java @@ -29,13 +29,13 @@ public class SncpMessageRequest extends SncpRequest { super(context); this.message = message; this.hashid = this.message.hash(); - this.createtime = System.currentTimeMillis(); + 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 (message.localAttach != null) return; if (logger.isLoggable(Level.FINER)) { message.attach(Utility.append(new Object[]{action.actionName()}, params)); } else { diff --git a/src/main/java/org/redkale/mq/SncpMessageResponse.java b/src/main/java/org/redkale/mq/SncpMessageResponse.java index 78d935754..59e275841 100644 --- a/src/main/java/org/redkale/mq/SncpMessageResponse.java +++ b/src/main/java/org/redkale/mq/SncpMessageResponse.java @@ -51,12 +51,12 @@ public class SncpMessageResponse extends SncpResponse { 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)); + 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())); + 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 ec06a7df4..9d8ed7439 100644 --- a/src/main/java/org/redkale/net/AsyncConnection.java +++ b/src/main/java/org/redkale/net/AsyncConnection.java @@ -138,6 +138,14 @@ public abstract class AsyncConnection implements ChannelContext, Channel, AutoCl ioThread.execute(command); } + public final void execute(Runnable... commands) { + ioThread.execute(commands); + } + + public final void execute(Collection commands) { + ioThread.execute(commands); + } + public final boolean inCurrThread() { return ioThread.inCurrThread(); } diff --git a/src/main/java/org/redkale/net/AsyncIOThread.java b/src/main/java/org/redkale/net/AsyncIOThread.java index 973930b51..ca53574bf 100644 --- a/src/main/java/org/redkale/net/AsyncIOThread.java +++ b/src/main/java/org/redkale/net/AsyncIOThread.java @@ -67,6 +67,15 @@ public class AsyncIOThread extends AsyncThread { selector.wakeup(); } + @Override + public void execute(Collection commands) { + if (commands == null) return; + for (Runnable command : commands) { + commandQueue.offer(command); + } + selector.wakeup(); + } + public void register(Consumer consumer) { registerQueue.offer(consumer); selector.wakeup(); diff --git a/src/main/java/org/redkale/net/PrepareServlet.java b/src/main/java/org/redkale/net/PrepareServlet.java index 84201c0e8..cf713aa28 100644 --- a/src/main/java/org/redkale/net/PrepareServlet.java +++ b/src/main/java/org/redkale/net/PrepareServlet.java @@ -215,6 +215,7 @@ public abstract class PrepareServlet { protected final JsonConvert jsonConvert; - protected long createtime; + protected long createTime; protected boolean keepAlive; @@ -80,7 +81,7 @@ public abstract class Request { protected void recycle() { hashid = 0; - createtime = 0; + createTime = 0; pipelineIndex = 0; pipelineCount = 0; pipelineOver = false; @@ -139,8 +140,14 @@ public abstract class Request { return this.context; } + @Deprecated //since 2.7.0 replace by getCreateTime() + @ConvertDisabled public long getCreatetime() { - return createtime; + return createTime; + } + + public long getCreateTime() { + return createTime; } public int getHashid() { diff --git a/src/main/java/org/redkale/net/Response.java b/src/main/java/org/redkale/net/Response.java index fb096ca44..44e4d05d1 100644 --- a/src/main/java/org/redkale/net/Response.java +++ b/src/main/java/org/redkale/net/Response.java @@ -143,7 +143,7 @@ public abstract class Response> { protected void init(AsyncConnection channel) { this.channel = channel; this.request.channel = channel; - this.request.createtime = System.currentTimeMillis(); + this.request.createTime = System.currentTimeMillis(); } protected void setFilter(Filter> filter) { diff --git a/src/main/java/org/redkale/net/Server.java b/src/main/java/org/redkale/net/Server.java index b74710247..fac05caed 100644 --- a/src/main/java/org/redkale/net/Server.java +++ b/src/main/java/org/redkale/net/Server.java @@ -269,8 +269,9 @@ public abstract class Server commands) { + if (commands == null) return; + 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); diff --git a/src/main/java/org/redkale/net/client/Client.java b/src/main/java/org/redkale/net/client/Client.java index 81fe6ea00..6b73a9873 100644 --- a/src/main/java/org/redkale/net/client/Client.java +++ b/src/main/java/org/redkale/net/client/Client.java @@ -5,7 +5,6 @@ */ package org.redkale.net.client; -import java.net.SocketAddress; import java.util.Queue; import java.util.concurrent.*; import java.util.concurrent.atomic.*; @@ -27,6 +26,8 @@ import org.redkale.util.*; */ public abstract class Client { + public static final int DEFAULT_MAX_PIPELINES = 256; + protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); protected final boolean finest = logger.isLoggable(Level.FINEST); @@ -35,15 +36,13 @@ public abstract class Client { protected final boolean tcp; //鏄惁TCP鍗忚 - protected final SocketAddress address; //杩炴帴鐨勫湴鍧 - - protected final Creator> codecCreator; + protected final ClientAddress address; //杩炴帴鐨勫湴鍧 protected final ScheduledThreadPoolExecutor timeoutScheduler; - protected final LongAdder writeReqCounter = new LongAdder(); + protected final LongAdder reqWritedCounter = new LongAdder(); - protected final LongAdder pollRespCounter = new LongAdder(); + protected final LongAdder respDoneCounter = new LongAdder(); private final AtomicInteger connSeqno = new AtomicInteger(); @@ -53,15 +52,15 @@ public abstract class Client { protected ClientConnection[] connArray; //杩炴帴姹 - protected LongAdder[] connResps; //杩炴帴褰撳墠澶勭悊鏁 + protected LongAdder[] connRespWaitings; //杩炴帴褰撳墠澶勭悊鏁 - protected AtomicBoolean[] connOpens; //conns鐨勬爣璁扮粍锛屽綋conn涓嶅瓨鍦ㄦ垨closed鐘舵侊紝鏍囪涓篺alse + protected AtomicBoolean[] connOpenStates; //conns鐨勬爣璁扮粍锛屽綋conn涓嶅瓨鍦ㄦ垨closed鐘舵侊紝鏍囪涓篺alse - protected final Queue>[] connWaits; //杩炴帴绛夊緟姹 + protected final Queue>[] connAcquireWaitings; //杩炴帴绛夊緟姹 protected int connLimit = Utility.cpus(); //鏈澶ц繛鎺ユ暟 - protected int maxPipelines = 16; //鍗曚釜杩炴帴鏈澶у苟琛屽鐞嗘暟 + protected int maxPipelines = DEFAULT_MAX_PIPELINES; //鍗曚釜杩炴帴鏈澶у苟琛屽鐞嗘暟 protected int readTimeoutSeconds; @@ -79,36 +78,35 @@ public abstract class Client { //鍒涘缓杩炴帴鍚庤繘琛岀殑鐧诲綍閴存潈鎿嶄綔 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, ClientAddress address) { + this(group, true, address, Utility.cpus(), 16, 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, ClientAddress address) { + this(group, tcp, address, Utility.cpus(), 16, 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, ClientAddress address, int maxconns) { + this(group, tcp, address, maxconns, 16, 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, ClientAddress address, int maxconns, int maxPipelines) { + this(group, tcp, address, maxconns, maxPipelines, null, null, null); } - protected Client(AsyncGroup group, boolean tcp, SocketAddress address, int maxconns, Creator> codecCreator, + protected Client(AsyncGroup group, boolean tcp, ClientAddress address, int maxconns, Function, CompletableFuture> authenticate) { - this(group, tcp, address, maxconns, 16, codecCreator, null, null, authenticate); + this(group, tcp, address, maxconns, 16, null, null, authenticate); } - protected Client(AsyncGroup group, boolean tcp, SocketAddress address, int maxconns, Creator> codecCreator, + protected Client(AsyncGroup group, boolean tcp, ClientAddress address, int maxconns, R closeRequest, Function, CompletableFuture> authenticate) { - this(group, tcp, address, maxconns, 16, codecCreator, null, closeRequest, authenticate); + this(group, tcp, address, maxconns, 16, 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) { + protected Client(AsyncGroup group, boolean tcp, ClientAddress address, int maxconns, + int maxPipelines, R pingRequest, R closeRequest, Function, CompletableFuture> authenticate) { if (maxPipelines < 1) throw new IllegalArgumentException("maxPipelines must bigger 0"); this.group = group; this.tcp = tcp; @@ -117,16 +115,15 @@ public abstract class Client { 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(); + this.connOpenStates = new AtomicBoolean[connLimit]; + this.connRespWaitings = new LongAdder[connLimit]; + this.connAcquireWaitings = new Queue[connLimit]; + for (int i = 0; i < connOpenStates.length; i++) { + this.connOpenStates[i] = new AtomicBoolean(); + this.connRespWaitings[i] = new LongAdder(); + this.connAcquireWaitings[i] = Utility.unsafe() != null ? new MpscGrowableArrayQueue<>(16, 1 << 10) : new ConcurrentLinkedDeque(); } //timeoutScheduler 涓嶄粎浠呯粰瓒呮椂鐢紝 杩樼粰write鐢 this.timeoutScheduler = new ScheduledThreadPoolExecutor(1, (Runnable r) -> { @@ -151,11 +148,13 @@ public abstract class Client { } } catch (Throwable t) { } - }, pingInterval(), pingInterval(), TimeUnit.SECONDS); + }, pingIntervalSeconds(), pingIntervalSeconds(), TimeUnit.SECONDS); } } - protected int pingInterval() { + protected abstract ClientConnection createClientConnection(final int index, AsyncConnection channel); + + protected int pingIntervalSeconds() { return 30; } @@ -205,80 +204,84 @@ public abstract class Client { if (cflag) { ClientConnection cc = context.getAttribute(connectionContextName); if (cc != null && cc.isOpen()) return CompletableFuture.completedFuture(cc); - } - int connIndex = -1; + int connIndex; final int size = this.connArray.length; WorkThread workThread = WorkThread.currWorkThread(); if (workThread != null && workThread.threads() == size) { connIndex = workThread.index(); + } else { + connIndex = (int) Math.abs(Thread.currentThread().getId() % size); } - 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; - } +// if (connIndex >= 0) { + ClientConnection cc = this.connArray[connIndex]; + if (cc != null && cc.isOpen()) { + if (cflag) context.setAttribute(connectionContextName, cc); + return CompletableFuture.completedFuture(cc); } - 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); - }); + final int index = connIndex; + final Queue> waitQueue = this.connAcquireWaitings[index]; + if (this.connOpenStates[index].compareAndSet(false, true)) { + CompletableFuture future = address.createClient(tcp, group, 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); } - } else if (conn.runningCount() < 1) { - return CompletableFuture.completedFuture(conn); - } else if (minRunningConn == null || minRunningConn.runningCount() > conn.runningCount()) { - minRunningConn = conn; - } + return c; + }).whenComplete((r, t) -> { + if (t != null) this.connOpenStates[index].set(false); + }); + } else { + CompletableFuture rs = Utility.orTimeout(new CompletableFuture(), 6, TimeUnit.SECONDS); + waitQueue.offer(rs); + return rs; } - if (minRunningConn != null && minRunningConn.runningCount() < maxPipelines) { - ClientConnection minConn = minRunningConn; - return CompletableFuture.completedFuture(minConn); - } - return waitClientConnection(); +// } +// 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.connOpenStates[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.connOpenStates[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 +// return CompletableFuture.completedFuture(minRunningConn); +// } +// return waitClientConnection(); } protected CompletableFuture waitClientConnection() { CompletableFuture rs = Utility.orTimeout(new CompletableFuture(), 6, TimeUnit.SECONDS); - connWaits[connSeqno.getAndIncrement() % this.connLimit].offer(rs); + connAcquireWaitings[connSeqno.getAndIncrement() % this.connLimit].offer(rs); return rs; } - protected ClientConnection createClientConnection(final int index, AsyncConnection channel) { - return new ClientConnection(this, index, channel); + protected long getRespWaitingCount() { + long s = 0; + for (LongAdder a : connRespWaitings) { + s += a.longValue(); + } + return s; } public int getReadTimeoutSeconds() { diff --git a/src/main/java/org/redkale/net/client/ClientAddress.java b/src/main/java/org/redkale/net/client/ClientAddress.java new file mode 100644 index 000000000..91fa91804 --- /dev/null +++ b/src/main/java/org/redkale/net/client/ClientAddress.java @@ -0,0 +1,48 @@ +/* + */ +package org.redkale.net.client; + +import java.net.SocketAddress; +import java.util.concurrent.CompletableFuture; +import org.redkale.convert.json.JsonConvert; +import org.redkale.net.*; + +/** + * Client杩炴帴鍦板潃 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @since 2.7.0 + */ +public class ClientAddress implements java.io.Serializable { + + protected SocketAddress address; + + public ClientAddress() { + } + + + public ClientAddress(SocketAddress address) { + this.address = address; + } + + public CompletableFuture createClient(final boolean tcp, final AsyncGroup group, int readTimeoutSeconds, int writeTimeoutSeconds) { + return group.createClient(tcp, address, readTimeoutSeconds, writeTimeoutSeconds); + } + + public SocketAddress getAddress() { + return address; + } + + public void setAddress(SocketAddress address) { + this.address = address; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + +} diff --git a/src/main/java/org/redkale/net/client/ClientCodec.java b/src/main/java/org/redkale/net/client/ClientCodec.java index edf35b71b..a0c017a42 100644 --- a/src/main/java/org/redkale/net/client/ClientCodec.java +++ b/src/main/java/org/redkale/net/client/ClientCodec.java @@ -25,14 +25,17 @@ public abstract class ClientCodec { protected final List> results = new ArrayList<>(); - public ClientCodec() { + protected final ClientConnection connection; + + public ClientCodec(ClientConnection connection) { + this.connection = connection; } //杩斿洖true: array浼歝lear, 杩斿洖false: buffer浼歝lear - public abstract boolean codecResult(ClientConnection conn, ByteBuffer buffer, ByteArray array); + public abstract boolean codecResult(ByteBuffer buffer, ByteArray array); - protected Queue responseQueue(ClientConnection conn) { - return conn.responseQueue; + protected Queue responseQueue() { + return connection.responseQueue; } public List> removeResults() { @@ -42,6 +45,10 @@ public abstract class ClientCodec { return rs; } + public ClientConnection getConnection() { + return connection; + } + public void addResult(P result) { this.results.add(new ClientResult<>(result)); } diff --git a/src/main/java/org/redkale/net/client/ClientConnection.java b/src/main/java/org/redkale/net/client/ClientConnection.java index a397de09e..157013e23 100644 --- a/src/main/java/org/redkale/net/client/ClientConnection.java +++ b/src/main/java/org/redkale/net/client/ClientConnection.java @@ -27,13 +27,15 @@ import org.redkale.util.*; * @param 璇锋眰瀵硅薄 * @param

鍝嶅簲瀵硅薄 */ -public class ClientConnection implements Consumer { +public abstract class ClientConnection implements Consumer { protected final int index; //浠0寮濮嬶紝 connArray鐨勪笅鍧愭爣 protected final Client client; - protected final LongAdder respCounter; + protected final ClientCodec codec; + + protected final LongAdder respWaitingCounter; protected final AsyncConnection channel; @@ -49,7 +51,7 @@ public class ClientConnection implements Consumer requestQueue = new ArrayDeque<>(); - protected final Queue responseQueue = new ArrayDeque<>(); + protected final ArrayDeque responseQueue = new ArrayDeque<>(); protected final CompletionHandler writeHandler = new CompletionHandler() { @@ -73,6 +75,8 @@ public class ClientConnection implements Consumer implements Consumer 1 ? (maxPipelines - responseQueue.size()) : 1; if (must && pipelines < 1) pipelines = 1; int c = 0; - AtomicBoolean pw = this.pauseWriting; + AtomicBoolean pw = conn.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); + R req; + if (lastHalfRequest == null) { + req = requestQueue.poll(); + } else { + req = lastHalfRequest; + lastHalfRequest = null; + } + if (req == null) break; + writeLastRequest = req; + if (req.canMerge(conn)) { + R r; + while ((r = requestQueue.poll()) != null) { + i++; + if (!req.merge(conn, r)) break; + req.respFuture.mergeCount++; + } + req.accept(conn, rw); + if (r != null) { + r.accept(conn, rw); + req = r; + } + } else { + req.accept(conn, rw); + } c++; + if (!req.isCompleted()) { + lastHalfRequest = req; + this.pauseWriting.set(true); + break; + } } - if (c > 0) { //褰揅lient杩炴帴Server鏃跺厛浠嶴erver璇诲彇鏁版嵁鏃,浼氬厛鍙戦佷竴涓狤MPTY鐨剅equest锛岃繖鏍穡riteArray.count灏变細涓0 - channel.write(writeArray, writeHandler); + if (c > 0) { //褰揅lient杩炴帴Server鍚庡厛浠嶴erver璇诲彇鏁版嵁鏃,浼氬厛鍙戦佷竴涓狤MPTY鐨剅equest锛岃繖鏍穡riteArray.count灏变細涓0 + channel.write(rw, writeHandler); return true; } + if (pw.get()) writePending.compareAndSet(true, false); return false; } @@ -113,8 +145,6 @@ public class ClientConnection implements Consumer readHandler = new CompletionHandler() { - ClientCodec codec; - @Override public void completed(Integer count, ByteBuffer attachment) { if (count < 1) { @@ -123,7 +153,6 @@ public class ClientConnection implements Consumer implements Consumer rs, ClientFuture respFuture) { + if (respFuture != null) { + if (!respFuture.request.isCompleted()) { + if (rs.exc == null) { + responseQueue.offerFirst(respFuture); + pauseWriting.set(false); + return; + } else { //寮傚父浜嗛渶瑕佹竻鎺夊崐鍖 + lastHalfRequest = null; + pauseWriting.set(false); + } + } + respWaitingCounter.decrement(); + if (isAuthenticated() && client.respDoneCounter != null) client.respDoneCounter.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.inIO() + || workThread.getState() != Thread.State.RUNNABLE) { + respFuture.completeExceptionally(rs.exc); + } else { + workThread.execute(() -> respFuture.completeExceptionally(rs.exc)); + } + } else { + if (workThread == null || workThread == Thread.currentThread() || workThread.inIO() + || workThread.getState() != Thread.State.RUNNABLE) { + 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); + } + } + } + public void codecResponse(ByteBuffer buffer) { - if (codec.codecResult(ClientConnection.this, buffer, readArray)) { //鎴愬姛浜 + if (codec.codecResult(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; + int mergeCount = respFuture.mergeCount; + completeResponse(rs, respFuture); + if (mergeCount > 0) { + for (int i = 0; i < mergeCount; i++) { + respFuture = responseQueue.poll(); + if (respFuture != null) completeResponse(rs, respFuture); } - if (rs.exc != null) { - if (workThread == null || workThread == Thread.currentThread() || workThread.inIO() - || workThread.getState() != Thread.State.RUNNABLE) { - respFuture.completeExceptionally(rs.exc); - } else { - workThread.execute(() -> respFuture.completeExceptionally(rs.exc)); - } - } else { - if (workThread == null || workThread == Thread.currentThread() || workThread.inIO() - || workThread.getState() != Thread.State.RUNNABLE) { - 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); } } } @@ -185,7 +237,7 @@ public class ClientConnection implements Consumer implements Consumer writeChannel(R request) { ClientFuture respFuture = createClientFuture(request); if (request == client.closeRequest) { @@ -230,10 +285,11 @@ public class ClientConnection implements Consumer 0 && respFuture.request != null) { - respFuture.responseQueue = responseQueue; + respFuture.conn = this; respFuture.timeout = client.timeoutScheduler.schedule(respFuture, rts, TimeUnit.SECONDS); } } + respWaitingCounter.increment(); //鏀惧湪writeChannelInThread璁℃暟浼氬欢杩燂紝瀵艰嚧涓嶅噯纭 if (channel.inCurrThread()) { writeChannelInThread(request, respFuture); } else { @@ -244,12 +300,16 @@ public class ClientConnection implements Consumer implements Consumer getCodec() { + return codec; + } + @Override //AsyncConnection.beforeCloseListener public void accept(AsyncConnection t) { - respCounter.reset(); - client.connOpens[index].set(false); + respWaitingCounter.reset(); + client.connOpenStates[index].set(false); client.connArray[index] = null; //蹇呴』connflags涔嬪悗 } @@ -284,7 +348,7 @@ public class ClientConnection implements Consumer implements Consumer extends CompletableFuture implements Runnable { ScheduledFuture timeout; - Queue responseQueue; + int mergeCount; //鍚堝苟鐨勪釜鏁帮紝涓嶇畻鑷韩 + + ClientConnection conn; public ClientFuture() { super(); @@ -43,6 +45,10 @@ public class ClientFuture extends CompletableFuture implements Runnable { this.request = request; } + public int getMergeCount() { + return mergeCount; + } + @Override //JDK9+ public ClientFuture newIncompleteFuture() { return new ClientFuture<>(); @@ -54,6 +60,17 @@ public class ClientFuture extends CompletableFuture implements Runnable { @Override public void run() { + if (conn == null) return; + AsyncConnection channel = conn.getChannel(); + if (channel.inCurrThread()) { + this.runTimeout(); + } else { + channel.execute(this::runTimeout); + } + } + + private void runTimeout() { + Queue responseQueue = conn.responseQueue; if (responseQueue != null) responseQueue.remove(this); TimeoutException ex = new TimeoutException(); WorkThread workThread = null; diff --git a/src/main/java/org/redkale/net/client/ClientRequest.java b/src/main/java/org/redkale/net/client/ClientRequest.java index 2256dd797..2ac8508cb 100644 --- a/src/main/java/org/redkale/net/client/ClientRequest.java +++ b/src/main/java/org/redkale/net/client/ClientRequest.java @@ -22,7 +22,9 @@ public abstract class ClientRequest implements BiConsumer result */ public class ClientResult

{ diff --git a/src/main/java/org/redkale/net/http/HttpContext.java b/src/main/java/org/redkale/net/http/HttpContext.java index d2fedfe19..1900594a8 100644 --- a/src/main/java/org/redkale/net/http/HttpContext.java +++ b/src/main/java/org/redkale/net/http/HttpContext.java @@ -30,12 +30,18 @@ public class HttpContext extends Context { protected final String remoteAddrHeader; + protected final HttpRpcAuthenticator rpcAuthenticator; + + protected final AnyValue rpcAuthenticatorConfig; + protected boolean lazyHeaders; //瀛樺湪鍔ㄦ佹敼鍊 // protected RequestURINode[] uriCacheNodes; public HttpContext(HttpContextConfig config) { super(config); this.remoteAddrHeader = config.remoteAddrHeader; + this.rpcAuthenticator = config.rpcAuthenticator; + this.rpcAuthenticatorConfig = config.rpcAuthenticatorConfig; random.setSeed(Math.abs(System.nanoTime())); } @@ -184,6 +190,10 @@ public class HttpContext extends Context { public String remoteAddrHeader; + public HttpRpcAuthenticator rpcAuthenticator; + + public AnyValue rpcAuthenticatorConfig; + } protected static class RequestURINode { diff --git a/src/main/java/org/redkale/net/http/HttpRequest.java b/src/main/java/org/redkale/net/http/HttpRequest.java index d6577785d..5f3396231 100644 --- a/src/main/java/org/redkale/net/http/HttpRequest.java +++ b/src/main/java/org/redkale/net/http/HttpRequest.java @@ -146,6 +146,8 @@ public class HttpRequest extends Request { private final String remoteAddrHeader; + final HttpRpcAuthenticator rpcAuthenticator; + HttpServlet.ActionEntry actionEntry; //浠呬緵HttpServlet浼犻扙ntry浣跨敤 public HttpRequest(HttpContext context) { @@ -156,6 +158,7 @@ public class HttpRequest extends Request { super(context); this.array = array; this.remoteAddrHeader = context.remoteAddrHeader; + this.rpcAuthenticator = context.rpcAuthenticator; } @SuppressWarnings("OverridableMethodCallInConstructor") @@ -163,6 +166,7 @@ public class HttpRequest extends Request { super(context); this.array = new ByteArray(); this.remoteAddrHeader = null; + this.rpcAuthenticator = null; if (req != null) initSimpleRequest(req, true); } @@ -198,10 +202,10 @@ public class HttpRequest extends Request { HttpSimpleRequest req = new HttpSimpleRequest(); req.setBody(array.length() == 0 ? null : array.getBytes()); if (!getHeaders().isEmpty()) { - if (headers.containsKey(Rest.REST_HEADER_RPC_NAME) + if (headers.containsKey(Rest.REST_HEADER_RPC) || 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_RPC); req.removeHeader(Rest.REST_HEADER_CURRUSERID_NAME); } else { req.setHeaders(headers); @@ -655,7 +659,7 @@ public class HttpRequest extends Request { value = bytes.toString(charset); headers.put("User-Agent", value); break; - case Rest.REST_HEADER_RPC_NAME: + case Rest.REST_HEADER_RPC: value = bytes.toString(charset); this.rpc = "true".equalsIgnoreCase(value); headers.put(name, value); @@ -827,7 +831,7 @@ public class HttpRequest extends Request { return; } String name = toDecodeString(array, offset, keypos - offset, charset); - if (name.charAt(0) == '<') return; //鍐呭鍙兘鏄痻ml鏍煎紡; 濡: { return uid.isEmpty() ? 0 : Integer.parseInt(uid); } + /** + * 鑾峰彇褰撳墠鐢ㄦ埛ID鐨刲ong鍊
+ * + * @return 鐢ㄦ埛ID + * + * @since 2.7.0 + */ + @SuppressWarnings("unchecked") + public long currentLongUserid() { + if (currentUserid == CURRUSERID_NIL || currentUserid == null) return 0L; + if (this.currentUserid instanceof Number) return ((Number) this.currentUserid).longValue(); + String uid = this.currentUserid.toString(); + return uid.isEmpty() ? 0L : Long.parseLong(uid); + } + /** * 鑾峰彇褰撳墠鐢ㄦ埛ID
* @@ -939,16 +958,16 @@ public class HttpRequest extends Request { @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; + if (type == int.class || type == Integer.class) return (T) (Integer) (int) 0; + if (type == long.class || type == Long.class) return (T) (Long) (long) 0; return null; } - if (type == int.class) { + if (type == int.class || type == Integer.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 (type == long.class || 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)); @@ -1182,9 +1201,7 @@ public class HttpRequest extends Request { } private static CharSequence toMapString(Map map, int indent) { - char[] chars = new char[indent]; - Arrays.fill(chars, ' '); - final String space = new String(chars); + final String space = " ".repeat(indent); StringBuilder sb = new StringBuilder(); sb.append("{\r\n"); for (Map.Entry en : map.entrySet()) { diff --git a/src/main/java/org/redkale/net/http/HttpResponse.java b/src/main/java/org/redkale/net/http/HttpResponse.java index 82619f5bb..a1c527090 100644 --- a/src/main/java/org/redkale/net/http/HttpResponse.java +++ b/src/main/java/org/redkale/net/http/HttpResponse.java @@ -36,6 +36,8 @@ import static org.redkale.util.Utility.append; */ public class HttpResponse extends Response { + protected static final byte[] EMPTY_BTYES = new byte[0]; + 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(); @@ -451,7 +453,6 @@ public class HttpResponse extends Response { // convert.convertToBytes(type, ret, convertHandler); // } // } - /** * 灏哛etResult瀵硅薄浠SON鏍煎紡杈撳嚭 * @@ -478,7 +479,6 @@ public class HttpResponse extends Response { // convert.convertToBytes(type, ret, convertHandler); // } // } - /** * 灏咰ompletableFuture鐨勭粨鏋滃璞′互JSON鏍煎紡杈撳嚭 * @@ -491,7 +491,6 @@ public class HttpResponse extends Response { // public void finishJson(final JsonConvert convert, final Type valueType, final CompletableFuture future) { // finish(convert, valueType, future); // } - /** * 灏哛etResult瀵硅薄杈撳嚭 * @@ -580,9 +579,9 @@ public class HttpResponse extends Response { addHeader(result.getHeaders()).addCookie(result.getCookies()).setStatus(result.getStatus() < 1 ? 200 : result.getStatus()); Object val = result.getResult(); if (val == null) { - finish(""); + finish((String) null, EMPTY_BTYES); } else if (val instanceof CharSequence) { - finish(val.toString()); + finish(getStatus(), val.toString()); } else { Convert cc = result.convert(); if (cc == null) cc = convert; @@ -666,6 +665,36 @@ public class HttpResponse extends Response { finish(convert, valueType, (CompletionStage) Flows.maybePublisherToFuture(publisher)); } + /** + * 灏咹ttpScope瀵硅薄杈撳嚭 + * + * @param future HttpScope杈撳嚭寮傛瀵硅薄 + */ + public void finishScope(CompletionStage future) { + finish(request.getRespConvert(), future); + } + + /** + * 灏咹ttpScope瀵硅薄杈撳嚭 + * + * @param convert 鎸囧畾鐨凜onvert + * @param future HttpScope杈撳嚭寮傛瀵硅薄 + */ + public void finishScope(final Convert convert, 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, v); + }); + } + /** * 灏咹ttpScope瀵硅薄杈撳嚭 * @@ -932,12 +961,12 @@ public class HttpResponse extends Response { // } // } } - + @Override protected void error() { finish500(); } - + /** * 浠304鐘舵佺爜杈撳嚭 */ @@ -1297,6 +1326,17 @@ public class HttpResponse extends Response { return this.header.duplicate(); } + /** + * 鍒ゆ柇鏄惁瀛樺湪Header鍊 + * + * @param name + * + * @return 鏄惁瀛樺湪 + */ + public boolean existsHeader(String name) { + return this.header.getValue(name) != null; + } + /** * 璁剧疆Header鍊 * @@ -1549,6 +1589,8 @@ public class HttpResponse extends Response { public HttpRender httpRender; + public AnyValue renderConfig; + public final byte[][] plainLiveContentLengthArray = new byte[cacheMaxContentLength][]; public final byte[][] jsonLiveContentLengthArray = new byte[cacheMaxContentLength][]; diff --git a/src/main/java/org/redkale/net/http/HttpRpcAuthenticator.java b/src/main/java/org/redkale/net/http/HttpRpcAuthenticator.java new file mode 100644 index 000000000..cdcc3b855 --- /dev/null +++ b/src/main/java/org/redkale/net/http/HttpRpcAuthenticator.java @@ -0,0 +1,44 @@ +/* + */ +package org.redkale.net.http; + +import org.redkale.util.AnyValue; + +/** + * rpc閴存潈楠岃瘉鍣
+ * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @since 2.7.0 + * + */ +public interface HttpRpcAuthenticator { + + /** + * 鍒濆鍖栨柟娉 + * + * @param config 閰嶇疆鍙傛暟 + */ + default void init(AnyValue config) { + } + + /** + * 鎴愬姛杩斿洖true锛 涓嶆垚鍔熻繑鍥瀎alse锛屼笖闇瑕乺esponse.finish()杈撳嚭澶辫触鐨勪俊鎭紝 姣斿404 + * + * @param request HttpRequest + * @param response HttpResponse + * + * @return 鏄惁楠岃瘉鎴愬姛 + */ + public boolean auth(HttpRequest request, HttpResponse response); + + /** + * 閿姣佹柟娉 + * + * @param config 閰嶇疆鍙傛暟 + */ + default void destroy(AnyValue config) { + } +} diff --git a/src/main/java/org/redkale/net/http/HttpRpcSecretAuthenticator.java b/src/main/java/org/redkale/net/http/HttpRpcSecretAuthenticator.java new file mode 100644 index 000000000..117bad875 --- /dev/null +++ b/src/main/java/org/redkale/net/http/HttpRpcSecretAuthenticator.java @@ -0,0 +1,40 @@ +/* + */ +package org.redkale.net.http; + +import org.redkale.util.AnyValue; + +/** + * rpc閴存潈楠岃瘉鍣⊿ecret key鐨勫疄鐜扮被
+ * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @since 2.7.0 + * + */ +public class HttpRpcSecretAuthenticator implements HttpRpcAuthenticator { + + protected String secretKey = ""; + + @Override + public void init(AnyValue config) { + this.secretKey = config.getValue("secret").trim(); + } + + @Override + public boolean auth(HttpRequest request, HttpResponse response) { + String key = request.getHeader("rest-rpc-secret"); + if (key == null) { + response.finish(404, null); + return false; + } + if (!secretKey.equals(key)) { + response.finish(404, null); + return false; + } + return true; + } + +} diff --git a/src/main/java/org/redkale/net/http/HttpScope.java b/src/main/java/org/redkale/net/http/HttpScope.java index 3c177beb8..1203cbdda 100644 --- a/src/main/java/org/redkale/net/http/HttpScope.java +++ b/src/main/java/org/redkale/net/http/HttpScope.java @@ -6,12 +6,15 @@ package org.redkale.net.http; import java.io.Serializable; +import java.lang.reflect.Type; import java.net.HttpCookie; import java.util.*; +import java.util.concurrent.CompletableFuture; import java.util.function.*; import javax.persistence.Transient; import org.redkale.convert.*; import org.redkale.convert.json.JsonConvert; +import org.redkale.util.TypeToken; /** * HTTP杈撳嚭寮曟搸鐨勫璞″煙
@@ -41,10 +44,17 @@ public class HttpScope { public static final Object NIL = new Object(); + static final Type FUTRU_TYPE = new TypeToken>() { + }.getType(); + @ConvertColumn(index = 1) protected String referid; + //@since 2.7.0 @ConvertColumn(index = 2) + protected Object referObj; + + @ConvertColumn(index = 3) protected Map attributes; //@since 2.4.0 @@ -52,11 +62,11 @@ public class HttpScope { protected Function attrFunction; //@since 2.4.0 - @ConvertColumn(index = 3) + @ConvertColumn(index = 4) protected Map headers; //@since 2.4.0 - @ConvertColumn(index = 4) + @ConvertColumn(index = 5) protected List cookies; public static HttpScope refer(String template) { @@ -107,6 +117,11 @@ public class HttpScope { return rs; } + public HttpScope referObj(Object value) { + this.referObj = value; + return this; + } + public HttpScope attrFunc(Function attrFunction) { this.attrFunction = attrFunction; return this; @@ -131,7 +146,7 @@ public class HttpScope { return this; } - public HttpScope attr(Map map) { + public HttpScope attr(Map map) { if (map == null) return this; if (this.attributes == null) this.attributes = new LinkedHashMap<>(); this.attributes.putAll(map); @@ -216,6 +231,14 @@ public class HttpScope { this.referid = referid; } + public Object getReferObj() { + return referObj; + } + + public void setReferObj(Object referObj) { + this.referObj = referObj; + } + public Map getAttributes() { final Function attrFunc = this.attrFunction; if (attrFunc != null) { diff --git a/src/main/java/org/redkale/net/http/HttpServer.java b/src/main/java/org/redkale/net/http/HttpServer.java index b75e6e58d..ae13de7ae 100644 --- a/src/main/java/org/redkale/net/http/HttpServer.java +++ b/src/main/java/org/redkale/net/http/HttpServer.java @@ -56,6 +56,9 @@ public class HttpServer extends Server getHttpServlets() { @@ -328,10 +334,12 @@ public class HttpServer extends Server @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.rpconly) { + if (!request.rpc) { + response.finish(404, null); + return; + } else if (request.rpcAuthenticator != null) { + if (!request.rpcAuthenticator.auth(request, response)) { + return; + } + } } if (entry.cacheseconds > 0) {//鏈夌紦瀛樿缃 CacheEntry ce = entry.modeOneCache ? entry.oneCache : entry.cache.get(request.getRequestURI()); diff --git a/src/main/java/org/redkale/net/http/HttpSimpleClient.java b/src/main/java/org/redkale/net/http/HttpSimpleClient.java index 3a91531ba..00e1af406 100644 --- a/src/main/java/org/redkale/net/http/HttpSimpleClient.java +++ b/src/main/java/org/redkale/net/http/HttpSimpleClient.java @@ -31,6 +31,8 @@ import org.redkale.util.*; */ public class HttpSimpleClient { + public static final String USER_AGENT = "Redkale-http-client/" + Redkale.getDotedVersion(); + protected final AsyncGroup asyncGroup; protected int readTimeoutSeconds = 6; @@ -103,7 +105,7 @@ public class HttpSimpleClient { + "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-http-client/" + Redkale.getDotedVersion() + "\r\n").getBytes(StandardCharsets.UTF_8)); + array.put(("User-Agent: " + USER_AGENT + "\r\n").getBytes(StandardCharsets.UTF_8)); } if (headers == null || !headers.containsKey("Connection")) { array.put(("Connection: close\r\n").getBytes(StandardCharsets.UTF_8)); diff --git a/src/main/java/org/redkale/net/http/Rest.java b/src/main/java/org/redkale/net/http/Rest.java index 9c5dc9ec9..8cf868e8b 100644 --- a/src/main/java/org/redkale/net/http/Rest.java +++ b/src/main/java/org/redkale/net/http/Rest.java @@ -40,7 +40,7 @@ public final class Rest { public static final String REST_HEADER_RESOURCE_NAME = "rest-resource-name"; - public static final String REST_HEADER_RPC_NAME = "rest-rpc-name"; + public static final String REST_HEADER_RPC = "rest-rpc"; public static final String REST_HEADER_CURRUSERID_NAME = "rest-curruserid-name"; @@ -155,9 +155,13 @@ public final class Rest { } } - static JsonConvert createJsonConvert(RestConvert[] converts, RestConvertCoder[] coders) { - if ((converts == null || converts.length < 1) && (coders == null || coders.length < 1)) return JsonConvert.root(); - final JsonFactory childFactory = JsonFactory.create(); + public static JsonFactory createJsonFactory(RestConvert[] converts, RestConvertCoder[] coders) { + return createJsonFactory(true, converts, coders); + } + + public static JsonFactory createJsonFactory(boolean tiny, RestConvert[] converts, RestConvertCoder[] coders) { + if ((converts == null || converts.length < 1) && (coders == null || coders.length < 1)) return JsonFactory.root(); + final JsonFactory childFactory = JsonFactory.create().tiny(tiny); List types = new ArrayList<>(); Set reloadTypes = new HashSet<>(); if (coders != null) { @@ -169,25 +173,28 @@ public final class Rest { if (converts != null) { for (RestConvert rc : converts) { if (rc.type() == void.class || rc.type() == Void.class) { - return JsonFactory.create().skipAllIgnore(true).getConvert(); + return JsonFactory.create().skipAllIgnore(true); } if (types.contains(rc.type())) throw new RuntimeException("@RestConvert type(" + rc.type() + ") repeat"); if (rc.skipIgnore()) { childFactory.registerSkipIgnore(rc.type()); childFactory.reloadCoder(rc.type()); + } else if (rc.onlyColumns().length > 0) { + childFactory.registerIgnoreAll(rc.type(), rc.onlyColumns()); + childFactory.reloadCoder(rc.type()); } else { childFactory.register(rc.type(), false, rc.convertColumns()); childFactory.register(rc.type(), true, rc.ignoreColumns()); childFactory.reloadCoder(rc.type()); } types.add(rc.type()); - childFactory.tiny(rc.tiny()); + if (tiny) childFactory.tiny(rc.tiny()); } } for (Class type : reloadTypes) { childFactory.reloadCoder(type); } - return childFactory.getConvert(); + return childFactory; } static String getWebModuleNameLowerCase(Class serviceType) { @@ -916,6 +923,10 @@ public final class Rest { final String multiContextDesc = Type.getDescriptor(MultiContext.class); final String multiContextName = MultiContext.class.getName().replace('.', '/'); final String mappingDesc = Type.getDescriptor(HttpMapping.class); + final String restConvertDesc = Type.getDescriptor(RestConvert.class); + final String restConvertsDesc = Type.getDescriptor(RestConvert.RestConverts.class); + final String restConvertCoderDesc = Type.getDescriptor(RestConvertCoder.class); + final String restConvertCodersDesc = Type.getDescriptor(RestConvertCoder.RestConvertCoders.class); final String httpParamDesc = Type.getDescriptor(HttpParam.class); final String httpParamsDesc = Type.getDescriptor(HttpParam.HttpParams.class); final String sourcetypeDesc = Type.getDescriptor(HttpParam.HttpParameterStyle.class); @@ -1277,7 +1288,7 @@ public final class Rest { genField.setAccessible(true); Object[] rc = restConverts.get(i); - genField.set(obj, createJsonConvert((RestConvert[]) rc[0], (RestConvertCoder[]) rc[1])); + genField.set(obj, createJsonFactory((RestConvert[]) rc[0], (RestConvertCoder[]) rc[1]).getConvert()); } Field typesfield = newClazz.getDeclaredField(REST_PARAMTYPES_FIELD_NAME); typesfield.setAccessible(true); @@ -1574,6 +1585,7 @@ public final class Rest { n = annhead.name(); radix = annhead.radix(); comment = annhead.comment(); + required = false; if (n.isEmpty()) throw new RuntimeException("@RestHeader.value is illegal in " + method); } RestCookie anncookie = param.getAnnotation(RestCookie.class); @@ -1583,6 +1595,7 @@ public final class Rest { n = anncookie.name(); radix = anncookie.radix(); comment = anncookie.comment(); + required = false; if (n.isEmpty()) throw new RuntimeException("@RestCookie.value is illegal in " + method); } RestSessionid annsid = param.getAnnotation(RestSessionid.class); @@ -1590,6 +1603,7 @@ public final class Rest { if (annhead != null) throw new RuntimeException("@RestSessionid and @RestHeader cannot on the same Parameter in " + method); if (anncookie != null) throw new RuntimeException("@RestSessionid and @RestCookie cannot on the same Parameter in " + method); if (ptype != String.class) throw new RuntimeException("@RestSessionid must on String Parameter in " + method); + required = false; } RestAddress annaddr = param.getAnnotation(RestAddress.class); if (annaddr != null) { @@ -1598,6 +1612,7 @@ public final class Rest { if (annsid != null) throw new RuntimeException("@RestAddress and @RestSessionid cannot on the same Parameter in " + method); if (ptype != String.class) throw new RuntimeException("@RestAddress must on String Parameter in " + method); comment = annaddr.comment(); + required = false; } RestBody annbody = param.getAnnotation(RestBody.class); if (annbody != null) { @@ -1644,6 +1659,7 @@ public final class Rest { if (annfile != null) throw new RuntimeException("@RestUserid and @RestUploadFile cannot on the same Parameter in " + method); if (!ptype.isPrimitive() && !java.io.Serializable.class.isAssignableFrom(ptype)) throw new RuntimeException("@RestUserid must on java.io.Serializable Parameter in " + method); comment = ""; + required = false; } RestHeaders annheaders = param.getAnnotation(RestHeaders.class); @@ -1657,6 +1673,7 @@ public final class Rest { if (userid != null) throw new RuntimeException("@RestHeaders and @RestUserid cannot on the same Parameter in " + method); if (!TYPE_MAP_STRING_STRING.equals(param.getParameterizedType())) throw new RuntimeException("@RestHeaders must on Map Parameter in " + method); comment = ""; + required = false; } RestParams annparams = param.getAnnotation(RestParams.class); if (annparams != null) { @@ -1710,6 +1727,7 @@ public final class Rest { } Map mappingMap = new LinkedHashMap<>(); + java.lang.reflect.Type returnGenericNoFutureType = TypeToken.getGenericType(method.getGenericReturnType(), serviceType); { // 璁剧疆 Annotation //璁剧疆 HttpMapping boolean reqpath = false; @@ -1741,23 +1759,22 @@ public final class Rest { } av1.visitEnd(); - java.lang.reflect.Type grt = TypeToken.getGenericType(method.getGenericReturnType(), serviceType); Class rtc = returnType; if (rtc == void.class) { rtc = RetResult.class; - grt = TYPE_RETRESULT_STRING; + returnGenericNoFutureType = TYPE_RETRESULT_STRING; } else if (CompletionStage.class.isAssignableFrom(returnType)) { - ParameterizedType ptgrt = (ParameterizedType) grt; - grt = ptgrt.getActualTypeArguments()[0]; - rtc = TypeToken.typeToClass(grt); + ParameterizedType ptgrt = (ParameterizedType) returnGenericNoFutureType; + returnGenericNoFutureType = ptgrt.getActualTypeArguments()[0]; + rtc = TypeToken.typeToClass(returnGenericNoFutureType); if (rtc == null) rtc = Object.class; //搴旇涓嶄細鍙戠敓鍚? } av0.visit("result", Type.getType(Type.getDescriptor(rtc))); - if (grt != rtc) { - String refid = typeRefs.get(grt); + if (returnGenericNoFutureType != rtc) { + String refid = typeRefs.get(returnGenericNoFutureType); if (refid == null) { refid = "_typeref_" + typeRefs.size(); - typeRefs.put(grt, refid); + typeRefs.put(returnGenericNoFutureType, refid); } av0.visit("resultref", refid); } @@ -1770,10 +1787,52 @@ public final class Rest { mappingMap.put("actionid", entry.actionid); mappingMap.put("comment", entry.comment); mappingMap.put("methods", entry.methods); - mappingMap.put("result", grt == returnType ? returnType.getName() : String.valueOf(grt)); + mappingMap.put("result", returnGenericNoFutureType == returnType ? returnType.getName() : String.valueOf(returnGenericNoFutureType)); entry.mappingurl = url; } - + if (rcs != null && rcs.length > 0) { // 璁剧疆 Annotation + av0 = mv.visitAnnotation(restConvertsDesc, true); + AnnotationVisitor av1 = av0.visitArray("value"); + //璁剧疆 RestConvert + for (RestConvert rc : rcs) { + AnnotationVisitor av2 = av1.visitAnnotation(null, restConvertDesc); + av2.visit("tiny", rc.tiny()); + av2.visit("skipIgnore", rc.skipIgnore()); + av2.visit("type", Type.getType(Type.getDescriptor(rc.type()))); + AnnotationVisitor av3 = av2.visitArray("onlyColumns"); + for (String s : rc.onlyColumns()) { + av3.visit(null, s); + } + av3.visitEnd(); + av3 = av2.visitArray("ignoreColumns"); + for (String s : rc.ignoreColumns()) { + av3.visit(null, s); + } + av3.visitEnd(); + av3 = av2.visitArray("convertColumns"); + for (String s : rc.convertColumns()) { + av3.visit(null, s); + } + av3.visitEnd(); + av2.visitEnd(); + } + av1.visitEnd(); + av0.visitEnd(); + } + if (rcc != null && rcc.length > 0) { // 璁剧疆 Annotation + av0 = mv.visitAnnotation(restConvertCodersDesc, true); + AnnotationVisitor av1 = av0.visitArray("value"); + //璁剧疆 RestConvertCoder + for (RestConvertCoder rc : rcc) { + AnnotationVisitor av2 = av1.visitAnnotation(null, restConvertCoderDesc); + av2.visit("type", Type.getType(Type.getDescriptor(rc.type()))); + av2.visit("field", rc.field()); + av2.visit("coder", Type.getType(Type.getDescriptor(rc.coder()))); + av2.visitEnd(); + } + av1.visitEnd(); + av0.visitEnd(); + } { // 璁剧疆 Annotation av0 = mv.visitAnnotation(httpParamsDesc, true); AnnotationVisitor av1 = av0.visitArray("value"); @@ -2251,7 +2310,7 @@ public final class Rest { mv.visitTypeInsn(CHECKCAST, ptype.getName().replace('.', '/')); mv.visitVarInsn(ASTORE, maxLocals); varInsns.add(new int[]{ALOAD, maxLocals}); - JsonFactory.root().loadDecoder(param.getParameterizedType()); + JsonFactory.root().loadDecoder(pgentype); //鏋勫缓 RestHeader銆丷estCookie銆丷estAddress 绛夎祴鍊兼搷浣 Class loop = ptype; @@ -2572,22 +2631,34 @@ public final class Rest { } else if (CompletionStage.class.isAssignableFrom(returnType)) { mv.visitVarInsn(ASTORE, maxLocals); mv.visitVarInsn(ALOAD, 2); //response - if (rcs != null && rcs.length > 0) { - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, REST_CONVERT_FIELD_PREFIX + restConverts.size(), convertDesc); - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;"); - MethodDebugVisitor.pushInt(mv, entry.methodidx);//鏂规硶涓嬫爣 - mv.visitInsn(AALOAD); - mv.visitVarInsn(ALOAD, maxLocals); - mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(" + convertDesc + typeDesc + stageDesc + ")V", false); + if (returnGenericNoFutureType == HttpScope.class) { + if (rcs != null && rcs.length > 0) { + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, REST_CONVERT_FIELD_PREFIX + restConverts.size(), convertDesc); + mv.visitVarInsn(ALOAD, maxLocals); + mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishScope", "(" + convertDesc + stageDesc + ")V", false); + } else { + mv.visitVarInsn(ALOAD, maxLocals); + mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishScope", "(" + stageDesc + ")V", false); + } } else { - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, newDynName, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;"); - MethodDebugVisitor.pushInt(mv, entry.methodidx);//鏂规硶涓嬫爣 - mv.visitInsn(AALOAD); - mv.visitVarInsn(ALOAD, maxLocals); - mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(" + typeDesc + stageDesc + ")V", false); + if (rcs != null && rcs.length > 0) { + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, REST_CONVERT_FIELD_PREFIX + restConverts.size(), convertDesc); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;"); + MethodDebugVisitor.pushInt(mv, entry.methodidx);//鏂规硶涓嬫爣 + mv.visitInsn(AALOAD); + mv.visitVarInsn(ALOAD, maxLocals); + mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(" + convertDesc + typeDesc + stageDesc + ")V", false); + } else { + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, REST_RETURNTYPES_FIELD_NAME, "[Ljava/lang/reflect/Type;"); + MethodDebugVisitor.pushInt(mv, entry.methodidx);//鏂规硶涓嬫爣 + mv.visitInsn(AALOAD); + mv.visitVarInsn(ALOAD, maxLocals); + mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(" + typeDesc + stageDesc + ")V", false); + } } mv.visitInsn(RETURN); maxLocals++; @@ -2872,7 +2943,7 @@ public final class Rest { Field genField = newClazz.getDeclaredField(REST_CONVERT_FIELD_PREFIX + (i + 1)); genField.setAccessible(true); Object[] rc = restConverts.get(i); - genField.set(obj, createJsonConvert((RestConvert[]) rc[0], (RestConvertCoder[]) rc[1])); + genField.set(obj, createJsonFactory((RestConvert[]) rc[0], (RestConvertCoder[]) rc[1]).getConvert()); RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), genField); } Field typesfield = newClazz.getDeclaredField(REST_PARAMTYPES_FIELD_NAME); diff --git a/src/main/java/org/redkale/net/http/RestConvert.java b/src/main/java/org/redkale/net/http/RestConvert.java index 9ed108616..4e259c0ad 100644 --- a/src/main/java/org/redkale/net/http/RestConvert.java +++ b/src/main/java/org/redkale/net/http/RestConvert.java @@ -25,14 +25,47 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME; @Repeatable(RestConvert.RestConverts.class) public @interface RestConvert { + /** + * 鏄惁杈撳嚭绌哄瓧绗︿覆锛0鏁板 + * + * @return boolean + */ boolean tiny() default true; + /** + * 鏄惁蹇界暐ConvertColumn.ignore=true鐨勮缃紝 浼樺厛绾ф渶楂 + * + * @return boolean + */ boolean skipIgnore() default false; + /** + * 绫诲瀷 + * + * @return Class + */ Class type(); + /** + * 浠呮樉绀虹殑瀛楁锛 浼樺厛绾у叾娆,鏈夊煎氨浼氬拷鐣gnoreColumns銆乧onvertColumns鍊 + * + * @since 2.7.0 + * @return String[] + */ + String[] onlyColumns() default {}; + + /** + * 灞忚斀鐨勫瓧娈 + * + * @return String[] + */ String[] ignoreColumns() default {}; + /** + * 鍏佽杈撳嚭鐨勫瓧娈 + * + * @return String[] + */ String[] convertColumns() default {}; @Inherited diff --git a/src/main/java/org/redkale/net/http/WebSocket.java b/src/main/java/org/redkale/net/http/WebSocket.java index d927bd595..3e7b454bd 100644 --- a/src/main/java/org/redkale/net/http/WebSocket.java +++ b/src/main/java/org/redkale/net/http/WebSocket.java @@ -645,6 +645,18 @@ public abstract class WebSocket { return _sendConvert; } + protected void setTextConvert(Convert convert) { + this._textConvert = convert; + } + + protected void setBinaryConvert(Convert convert) { + this._binaryConvert = convert; + } + + protected void setSendConvert(Convert convert) { + this._sendConvert = convert; + } + //------------------------------------------------------------------- /** * 鑾峰彇鎸囧畾userid鐨刉ebSocket鏁扮粍, 娌℃湁杩斿洖null
diff --git a/src/main/java/org/redkale/net/http/WebSocketReadHandler.java b/src/main/java/org/redkale/net/http/WebSocketReadHandler.java index 48a1e5695..e0c0da654 100644 --- a/src/main/java/org/redkale/net/http/WebSocketReadHandler.java +++ b/src/main/java/org/redkale/net/http/WebSocketReadHandler.java @@ -296,7 +296,7 @@ public class WebSocketReadHandler implements CompletionHandler methodens = new ArrayList<>(); //------------------------------------------------------------------------------ diff --git a/src/main/java/org/redkale/service/Persist.java b/src/main/java/org/redkale/service/Persist.java deleted file mode 100644 index bd1e11d0b..000000000 --- a/src/main/java/org/redkale/service/Persist.java +++ /dev/null @@ -1,32 +0,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.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 4ab271b9a..5ae14f68a 100644 --- a/src/main/java/org/redkale/service/RetLabel.java +++ b/src/main/java/org/redkale/service/RetLabel.java @@ -79,7 +79,7 @@ public @interface RetLabel { } } try { - File propPath = new File(System.getProperty(RESNAME_APP_CONF, new File(System.getProperty(RESNAME_APP_HOME, ""), "conf").getPath())); + File propPath = new File(System.getProperty(RESNAME_APP_CONF_DIR, 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"))) { diff --git a/src/main/java/org/redkale/service/RetResult.java b/src/main/java/org/redkale/service/RetResult.java index 7382cc47f..4ba1a8044 100644 --- a/src/main/java/org/redkale/service/RetResult.java +++ b/src/main/java/org/redkale/service/RetResult.java @@ -123,6 +123,22 @@ public class RetResult implements Serializable { return CompletableFuture.completedFuture(new RetResult(result)); } + //@since 2.7.0 + public static RetResult fail(int retcode, String retinfo) { + return new RetResult(retcode, retinfo); + } + + //@since 2.7.0 + public static CompletableFuture> failFuture(int retcode, String retinfo) { + return CompletableFuture.completedFuture(new RetResult(retcode, retinfo)); + } + + //@since 2.7.0 + public T join() { + if (isSuccess()) return result; + throw new RetcodeException(this.retcode, this.retinfo); + } + public static RetResult get(CompletableFuture> future, long timeout, TimeUnit unit) { try { return future.get(timeout, unit); @@ -226,6 +242,7 @@ public class RetResult implements Serializable { */ @Deprecated public RetResult attach(String key, Object value) { + System.err.println("RetResult.attach is deprecated"); 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))); @@ -257,6 +274,16 @@ public class RetResult implements Serializable { this.retcode = retcode; } + /** + * retinfo鍊兼槸鍚︿负绌 + * + * @return 鏄惁涓虹┖ + * @since 2.7.0 + */ + public boolean emptyRetinfo() { + return retinfo == null || retinfo.trim().isEmpty(); + } + /** * 缁撴灉淇℃伅锛岄氬父retcode != 0鏃跺间负閿欒淇℃伅 * @@ -305,6 +332,7 @@ public class RetResult implements Serializable { */ @Deprecated public String getAttach(String name, String defValue) { + System.err.println("RetResult.attach is deprecated"); return attach == null ? defValue : attach.getOrDefault(name, defValue); } diff --git a/src/main/java/org/redkale/service/WebSocketNodeService.java b/src/main/java/org/redkale/service/WebSocketNodeService.java index cbde439e0..3d8192be9 100644 --- a/src/main/java/org/redkale/service/WebSocketNodeService.java +++ b/src/main/java/org/redkale/service/WebSocketNodeService.java @@ -5,16 +5,17 @@ */ package org.redkale.service; +import java.util.logging.Level; import org.redkale.net.http.*; import org.redkale.util.*; /** - * 鐢 org.redkale.net.http.WebSocketNodeService 浠f浛 + * 鐢 org.redkale.net.http.WebSocketNodeService 浠f浛 * *

* 璇︽儏瑙: https://redkale.org * - * @deprecated 2.6.0 + * @deprecated 2.6.0 * @author zhangjx */ @Deprecated @@ -22,4 +23,9 @@ import org.redkale.util.*; @ResourceType(WebSocketNode.class) public class WebSocketNodeService extends org.redkale.net.http.WebSocketNodeService { + @Override + public void init(AnyValue conf) { + super.init(conf); + logger.log(Level.WARNING, WebSocketNodeService.class.getName() + "is replaced by " + org.redkale.net.http.WebSocketNodeService.class.getName()); + } } diff --git a/src/main/java/org/redkale/source/AbstractCacheSource.java b/src/main/java/org/redkale/source/AbstractCacheSource.java new file mode 100644 index 000000000..66ff6f84b --- /dev/null +++ b/src/main/java/org/redkale/source/AbstractCacheSource.java @@ -0,0 +1,47 @@ +/* + */ +package org.redkale.source; + +import org.redkale.service.*; +import org.redkale.util.*; + +/** + * CacheSource鐨凷鎶借薄瀹炵幇绫
+ * + * + * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @since 2.7.0 + */ +@Local +@AutoLoad(false) +@SuppressWarnings("unchecked") +@ResourceType(CacheSource.class) +public abstract class AbstractCacheSource extends AbstractService implements CacheSource, AutoCloseable, Resourcable { + + //@since 2.7.0 + public static final String CACHE_SOURCE_URL = "url"; + + //@since 2.7.0 + public static final String CACHE_SOURCE_DB = "db"; + + //@since 2.7.0 + public static final String CACHE_SOURCE_USER = "user"; + + //@since 2.7.0 + public static final String CACHE_SOURCE_PASSWORD = "password"; + + //@since 2.7.0 + public static final String CACHE_SOURCE_ENCODING = "encoding"; + + //@since 2.7.0 + public static final String CACHE_SOURCE_NODE = "node"; + + //@since 2.7.0 + public static final String CACHE_SOURCE_MAXCONNS = "maxconns"; + + //@since 2.7.0 + public static final String CACHE_SOURCE_PIPELINES = "pipelines"; + +} diff --git a/src/main/java/org/redkale/source/AbstractDataSource.java b/src/main/java/org/redkale/source/AbstractDataSource.java index 763c2798b..19658fcb5 100644 --- a/src/main/java/org/redkale/source/AbstractDataSource.java +++ b/src/main/java/org/redkale/source/AbstractDataSource.java @@ -6,11 +6,13 @@ package org.redkale.source; import java.io.Serializable; +import java.net.InetSocketAddress; import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.function.*; import java.util.stream.Stream; import javax.persistence.Entity; +import org.redkale.convert.json.JsonConvert; import org.redkale.service.*; import org.redkale.util.*; @@ -30,6 +32,141 @@ import org.redkale.util.*; @ResourceType(DataSource.class) public abstract class AbstractDataSource extends AbstractService implements DataSource, AutoCloseable, Resourcable { + //@since 2.7.0 鏍煎紡: x.x.x.x:yyyy + public static final String DATA_SOURCE_PROXY_ADDRESS = "proxy-address"; + + //@since 2.7.0 鍊: SOCKS/DIRECT/HTTP锛岄粯璁ゅ: http + public static final String DATA_SOURCE_PROXY_TYPE = "proxy-type"; + + //@since 2.7.0 + public static final String DATA_SOURCE_PROXY_USER = "proxy-user"; + + //@since 2.7.0 + public static final String DATA_SOURCE_PROXY_PASSWORD = "proxy-password"; + + //@since 2.7.0 鍊: true/false锛岄粯璁ゅ: true + public static final String DATA_SOURCE_PROXY_ENABLE = "proxy-enable"; + + //@since 2.7.0 + public static final String DATA_SOURCE_URL = "url"; + + //@since 2.7.0 + public static final String DATA_SOURCE_USER = "user"; + + //@since 2.7.0 + public static final String DATA_SOURCE_PASSWORD = "password"; + + //@since 2.7.0 + public static final String DATA_SOURCE_ENCODING = "encoding"; + + //@since 2.7.0 + public static final String DATA_SOURCE_MAXCONNS = "maxconns"; + + //@since 2.7.0 + public static final String DATA_SOURCE_PIPELINES = "pipelines"; + + //@since 2.7.0 + public static final String DATA_SOURCE_AUTOMAPPING = "auto-mapping"; + + //@since 2.7.0 + public static final String DATA_SOURCE_TABLE_AUTODDL = "table-autoddl"; + + //@since 2.7.0 + public static final String DATA_SOURCE_CONNECTTIMEOUT_SECONDS = "connecttimeout"; + + //@since 2.7.0 //NONE ALL 璁剧疆@Cacheable鏄惁鐢熸晥 + public static final String DATA_SOURCE_CACHEMODE = "cachemode"; + + //@since 2.7.0 + public static final String DATA_SOURCE_CONNECTIONS_CAPACITY = "connections-bufcapacity"; + + //@since 2.7.0 + public static final String DATA_SOURCE_CONTAIN_SQLTEMPLATE = "contain-sqltemplate"; + + //@since 2.7.0 + public static final String DATA_SOURCE_NOTCONTAIN_SQLTEMPLATE = "notcontain-sqltemplate"; + + //@since 2.7.0 + public static final String DATA_SOURCE_TABLENOTEXIST_SQLSTATES = "tablenotexist-sqlstates"; + + //@since 2.7.0 + public static final String DATA_SOURCE_TABLECOPY_SQLTEMPLATE = "tablecopy-sqltemplate"; + + public static String parseDbtype(String url) { + String dbtype = null; + if (url == null) return dbtype; + 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; + } + + protected 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; + } + + protected 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); + } + } + /** * 鏄惁铏氭嫙鍖栫殑鎸佷箙瀵硅薄 * @@ -398,12 +535,12 @@ public abstract class AbstractDataSource extends AbstractService implements Data @Override public T find(final Class clazz, final String column, final Serializable colval) { - return find(clazz, null, FilterNode.create(column, colval)); + return find(clazz, null, FilterNode.filter(column, colval)); } @Override public CompletableFuture findAsync(final Class clazz, final String column, final Serializable colval) { - return findAsync(clazz, null, FilterNode.create(column, colval)); + return findAsync(clazz, null, FilterNode.filter(column, colval)); } @Override @@ -489,12 +626,12 @@ public abstract class AbstractDataSource extends AbstractService implements Data //-----------------------list set---------------------------- @Override public Set queryColumnSet(final String selectedColumn, final Class clazz, final String column, final Serializable colval) { - return queryColumnSet(selectedColumn, clazz, null, FilterNode.create(column, colval)); + return queryColumnSet(selectedColumn, clazz, null, FilterNode.filter(column, colval)); } @Override public CompletableFuture> queryColumnSetAsync(final String selectedColumn, final Class clazz, final String column, final Serializable colval) { - return queryColumnSetAsync(selectedColumn, clazz, null, FilterNode.create(column, colval)); + return queryColumnSetAsync(selectedColumn, clazz, null, FilterNode.filter(column, colval)); } @Override @@ -529,12 +666,12 @@ public abstract class AbstractDataSource extends AbstractService implements Data @Override public List queryColumnList(final String selectedColumn, final Class clazz, final String column, final Serializable colval) { - return queryColumnList(selectedColumn, clazz, null, FilterNode.create(column, colval)); + return queryColumnList(selectedColumn, clazz, null, FilterNode.filter(column, colval)); } @Override public CompletableFuture> queryColumnListAsync(final String selectedColumn, final Class clazz, final String column, final Serializable colval) { - return queryColumnListAsync(selectedColumn, clazz, null, FilterNode.create(column, colval)); + return queryColumnListAsync(selectedColumn, clazz, null, FilterNode.filter(column, colval)); } @Override @@ -686,12 +823,12 @@ public abstract class AbstractDataSource extends AbstractService implements Data */ @Override public Set querySet(final Class clazz, final String column, final Serializable colval) { - return querySet(clazz, (SelectColumn) null, null, FilterNode.create(column, colval)); + return querySet(clazz, (SelectColumn) null, null, FilterNode.filter(column, colval)); } @Override public CompletableFuture> querySetAsync(final Class clazz, final String column, final Serializable colval) { - return querySetAsync(clazz, (SelectColumn) null, null, FilterNode.create(column, colval)); + return querySetAsync(clazz, (SelectColumn) null, null, FilterNode.filter(column, colval)); } @Override @@ -765,12 +902,12 @@ public abstract class AbstractDataSource extends AbstractService implements Data @Override public Set querySet(final Class clazz, final Flipper flipper, final String column, final Serializable colval) { - return querySet(clazz, null, flipper, FilterNode.create(column, colval)); + return querySet(clazz, null, flipper, FilterNode.filter(column, colval)); } @Override public CompletableFuture> querySetAsync(final Class clazz, final Flipper flipper, final String column, final Serializable colval) { - return querySetAsync(clazz, null, flipper, FilterNode.create(column, colval)); + return querySetAsync(clazz, null, flipper, FilterNode.filter(column, colval)); } @Override @@ -815,12 +952,12 @@ public abstract class AbstractDataSource extends AbstractService implements Data */ @Override public List queryList(final Class clazz, final String column, final Serializable colval) { - return queryList(clazz, (SelectColumn) null, null, FilterNode.create(column, colval)); + return queryList(clazz, (SelectColumn) null, null, FilterNode.filter(column, colval)); } @Override public CompletableFuture> queryListAsync(final Class clazz, final String column, final Serializable colval) { - return queryListAsync(clazz, (SelectColumn) null, null, FilterNode.create(column, colval)); + return queryListAsync(clazz, (SelectColumn) null, null, FilterNode.filter(column, colval)); } @Override @@ -894,12 +1031,12 @@ public abstract class AbstractDataSource extends AbstractService implements Data @Override public List queryList(final Class clazz, final Flipper flipper, final String column, final Serializable colval) { - return queryList(clazz, null, flipper, FilterNode.create(column, colval)); + return queryList(clazz, null, flipper, FilterNode.filter(column, colval)); } @Override public CompletableFuture> queryListAsync(final Class clazz, final Flipper flipper, final String column, final Serializable colval) { - return queryListAsync(clazz, null, flipper, FilterNode.create(column, colval)); + return queryListAsync(clazz, null, flipper, FilterNode.filter(column, colval)); } @Override diff --git a/src/main/java/org/redkale/source/CacheMemorySource.java b/src/main/java/org/redkale/source/CacheMemorySource.java index 7bee93cc3..ff3faf97d 100644 --- a/src/main/java/org/redkale/source/CacheMemorySource.java +++ b/src/main/java/org/redkale/source/CacheMemorySource.java @@ -20,6 +20,7 @@ import org.redkale.util.*; /** * CacheSource鐨勯粯璁ゅ疄鐜--鍐呭瓨缂撳瓨 + * 娉ㄦ剰: url 闇瑕佹寚瀹氫负 memory:cachesource * *

* 璇︽儏瑙: https://redkale.org @@ -30,7 +31,7 @@ import org.redkale.util.*; @AutoLoad(false) @SuppressWarnings("unchecked") @ResourceType(CacheSource.class) -public final class CacheMemorySource extends AbstractService implements CacheSource, Service, AutoCloseable, Resourcable { +public final class CacheMemorySource extends AbstractCacheSource { @Resource private JsonConvert defaultConvert; @@ -61,14 +62,13 @@ public final class CacheMemorySource extends AbstractService implements CacheSou return "memory"; } - @Override - public String toString() { - return "CacheMemorySource(type=memory, name='" + resourceName() + "')"; + public static boolean acceptsConf(AnyValue config) { + return config.getValue(CACHE_SOURCE_URL).startsWith("memory:"); } - @Override //ServiceLoader鏃跺垽鏂厤缃槸鍚︾鍚堝綋鍓嶅疄鐜扮被 - public boolean acceptsConf(AnyValue config) { - return false; + @Override + public String toString() { + return getClass().getSimpleName() + "{type=memory, name='" + resourceName() + "'}"; } @Override @@ -112,10 +112,10 @@ public final class CacheMemorySource extends AbstractService implements CacheSou 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"); + logger.info(self.getClass().getSimpleName() + ":" + self.resourceName() + " start schedule expire executor"); } } - + @Override public void close() throws Exception { //缁橝pplication 鍏抽棴鏃惰皟鐢 destroy(null); @@ -330,6 +330,13 @@ public final class CacheMemorySource extends AbstractService implements CacheSou return (String) entry.objectValue; } + @Override + public String getSetString(String key, String value) { + String old = getString(key); + setString(key, value); + return old; + } + @Override public long getLong(String key, long defValue) { if (key == null) return defValue; @@ -337,8 +344,15 @@ public final class CacheMemorySource extends AbstractService implements CacheSou 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 long getSetLong(String key, long value, long defValue) { + long old = getLong(key, defValue); + setLong(key, value); + return old; + } + + //----------- hxxx -------------- @Override public CompletableFuture hremoveAsync(final String key, String... fields) { return CompletableFuture.supplyAsync(() -> hremove(key, fields), getExecutor()); @@ -455,6 +469,11 @@ public final class CacheMemorySource extends AbstractService implements CacheSou return CompletableFuture.supplyAsync(() -> getLong(key, defValue), getExecutor()); } + @Override + public CompletableFuture getSetLongAsync(final String key, long value, long defValue) { + return CompletableFuture.supplyAsync(() -> getSetLong(key, value, defValue), getExecutor()); + } + @Override public T getAndRefresh(final String key, final int expireSeconds, final Type type) { if (key == null) return null; @@ -560,6 +579,20 @@ public final class CacheMemorySource extends AbstractService implements CacheSou set(CacheEntryType.OBJECT, key, value); } + @Override + public T getSet(String key, Type type, T value) { + T old = get(key, type); + set(CacheEntryType.OBJECT, key, value); + return old; + } + + @Override + public T getSet(String key, Convert convert, Type type, T value) { + T old = get(key, type); + set(CacheEntryType.OBJECT, key, value); + return old; + } + @Override public void setString(String key, String value) { set(CacheEntryType.STRING, key, value); @@ -585,11 +618,26 @@ public final class CacheMemorySource extends AbstractService implements CacheSou return CompletableFuture.runAsync(() -> set(key, convert, type, value), getExecutor()).whenComplete(futureCompleteConsumer); } + @Override + public CompletableFuture getSetAsync(String key, Type type, T value) { + return CompletableFuture.runAsync(() -> getSet(key, type, value), getExecutor()).whenComplete(futureCompleteConsumer); + } + + @Override + public CompletableFuture getSetAsync(String key, Convert convert, Type type, T value) { + return CompletableFuture.runAsync(() -> getSet(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 getSetStringAsync(String key, String value) { + return CompletableFuture.runAsync(() -> getSetString(key, value), getExecutor()).whenComplete(futureCompleteConsumer); + } + @Override public CompletableFuture setLongAsync(String key, long value) { return CompletableFuture.runAsync(() -> setLong(key, value), getExecutor()).whenComplete(futureCompleteConsumer); @@ -1190,11 +1238,23 @@ public final class CacheMemorySource extends AbstractService implements CacheSou return (byte[]) entry.objectValue; } + @Override + public byte[] getSetBytes(final String key, byte[] value) { + byte[] old = getBytes(key); + setBytes(key, value); + return old; + } + @Override public CompletableFuture getBytesAsync(final String key) { return CompletableFuture.supplyAsync(() -> getBytes(key), getExecutor()).whenComplete(futureCompleteConsumer); } + @Override + public CompletableFuture getSetBytesAsync(final String key, byte[] value) { + return CompletableFuture.supplyAsync(() -> getSetBytes(key, value), getExecutor()).whenComplete(futureCompleteConsumer); + } + @Override public byte[] getBytesAndRefresh(String key, final int expireSeconds) { if (key == null) return null; diff --git a/src/main/java/org/redkale/source/CacheSource.java b/src/main/java/org/redkale/source/CacheSource.java index 36cff644f..8f0823a2a 100644 --- a/src/main/java/org/redkale/source/CacheSource.java +++ b/src/main/java/org/redkale/source/CacheSource.java @@ -10,7 +10,6 @@ import java.lang.reflect.Type; import java.util.*; import java.util.concurrent.*; import org.redkale.convert.*; -import org.redkale.util.*; /** * Redkale涓紦瀛樻暟鎹簮鐨勬牳蹇冪被銆 涓昏渚涗笟鍔″紑鍙戣呬娇鐢紝 鎶鏈紑鍙戣呮彁渚汣acheSource鐨勫疄鐜般
@@ -30,9 +29,6 @@ public interface CacheSource { public String getType(); - //ServiceLoader鏃跺垽鏂厤缃槸鍚︾鍚堝綋鍓嶅疄鐜扮被 - public boolean acceptsConf(AnyValue config); - default boolean isOpen() { return true; } @@ -93,6 +89,10 @@ public interface CacheSource { public void set(final String key, final Convert convert, final Type type, final T value); + public T getSet(final String key, final Type type, final T value); + + public T getSet(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); @@ -137,6 +137,8 @@ public interface CacheSource { public byte[] getBytes(final String key); + public byte[] getSetBytes(final String key, final byte[] value); + public byte[] getBytesAndRefresh(final String key, final int expireSeconds); public void setBytes(final String key, final byte[] value); @@ -157,6 +159,8 @@ public interface CacheSource { public String getString(final String key); + public String getSetString(final String key, final String value); + public String getStringAndRefresh(final String key, final int expireSeconds); public void setString(final String key, final String value); @@ -189,6 +193,8 @@ public interface CacheSource { public long getLong(final String key, long defValue); + public long getSetLong(final String key, long value, long defValue); + public long getLongAndRefresh(final String key, final int expireSeconds, long defValue); public void setLong(final String key, final long value); @@ -234,6 +240,10 @@ public interface CacheSource { public CompletableFuture setAsync(final String key, final Convert convert, final Type type, final T value); + public CompletableFuture getSetAsync(final String key, final Type type, final T value); + + public CompletableFuture getSetAsync(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); @@ -320,6 +330,8 @@ public interface CacheSource { public CompletableFuture getBytesAsync(final String key); + public CompletableFuture getSetBytesAsync(final String key, final byte[] value); + public CompletableFuture getBytesAndRefreshAsync(final String key, final int expireSeconds); public CompletableFuture setBytesAsync(final String key, final byte[] value); @@ -340,6 +352,8 @@ public interface CacheSource { public CompletableFuture getStringAsync(final String key); + public CompletableFuture getSetStringAsync(final String key, final String value); + public CompletableFuture getStringAndRefreshAsync(final String key, final int expireSeconds); public CompletableFuture setStringAsync(final String key, final String value); @@ -372,6 +386,8 @@ public interface CacheSource { public CompletableFuture getLongAsync(final String key, long defValue); + public CompletableFuture getSetLongAsync(final String key, long value, long defValue); + public CompletableFuture getLongAndRefreshAsync(final String key, final int expireSeconds, long defValue); public CompletableFuture setLongAsync(final String key, long value); diff --git a/src/main/java/org/redkale/source/CacheSourceProvider.java b/src/main/java/org/redkale/source/CacheSourceProvider.java index f43b4af9f..cdfb84e22 100644 --- a/src/main/java/org/redkale/source/CacheSourceProvider.java +++ b/src/main/java/org/redkale/source/CacheSourceProvider.java @@ -8,7 +8,7 @@ package org.redkale.source; import org.redkale.util.AnyValue; /** - * + * * 鑷畾涔夌殑CacheSource鍔犺浇鍣, 濡傛灉鏍囪@Priority鍔犺浇鍣ㄧ殑浼樺厛绾ч渶瑕佸ぇ浜1000锛 1000浠ヤ笅棰勭暀缁欏畼鏂瑰姞杞藉櫒 * *

diff --git a/src/main/java/org/redkale/source/ColumnNodeValue.java b/src/main/java/org/redkale/source/ColumnNodeValue.java index 5405bec1d..5fe87f8e2 100644 --- a/src/main/java/org/redkale/source/ColumnNodeValue.java +++ b/src/main/java/org/redkale/source/ColumnNodeValue.java @@ -13,7 +13,9 @@ import static org.redkale.source.ColumnExpress.*; * String 瑙嗕负 瀛楁鍚
* Number 瑙嗕负 鏁板
* 渚嬪锛 UPDATE Reord SET updateTime = createTime + 10 WHERE id = 1
- * source.updateColumn(Record.class, 1, ColumnValue.mov("updateTime", ColumnNodeValue.inc("createTime", 10))); + * source.updateColumn(Record.class, 1, ColumnValue.mov("updateTime", ColumnNodeValue.inc("createTime", 10)));
+ * 渚嬪锛 UPDATE Reord SET updateTime = createTime * 10 / createCount WHERE id = 1
+ * source.updateColumn(Record.class, 1, ColumnValue.mov("updateTime", ColumnNodeValue.div(ColumnNodeValue.mul("createTime", 10), "createCount")));
* *

* 璇︽儏瑙: https://redkale.org diff --git a/src/main/java/org/redkale/source/CryptColumn.java b/src/main/java/org/redkale/source/CryptColumn.java deleted file mode 100644 index 35a5c39c9..000000000 --- a/src/main/java/org/redkale/source/CryptColumn.java +++ /dev/null @@ -1,30 +0,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.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 deleted file mode 100644 index cf08dc0fd..000000000 --- a/src/main/java/org/redkale/source/CryptHandler.java +++ /dev/null @@ -1,38 +0,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.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 be30fede3..4f6d1bc4a 100644 --- a/src/main/java/org/redkale/source/DataJdbcSource.java +++ b/src/main/java/org/redkale/source/DataJdbcSource.java @@ -6,7 +6,6 @@ package org.redkale.source; import java.io.*; -import java.net.URL; import java.sql.*; import java.util.*; import java.util.concurrent.*; @@ -14,7 +13,6 @@ 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.*; /** @@ -35,8 +33,8 @@ public class DataJdbcSource extends DataSqlSource { protected ConnectionPool writePool; - public DataJdbcSource(String unitName, URL persistFile, String dbtype, Properties readprop, Properties writeprop) { - super(unitName, persistFile, dbtype, readprop, writeprop); + public DataJdbcSource() { + super(); } @Override @@ -64,9 +62,11 @@ public class DataJdbcSource extends DataSqlSource { if (writePool != null) writePool.close(); } - public static boolean acceptsConf(Properties property) { + public static boolean acceptsConf(AnyValue conf) { try { - final Class driverClass = DriverManager.getDriver(property.getProperty(JDBC_URL)).getClass(); + AnyValue read = conf.getAnyValue("read"); + AnyValue node = read == null ? conf : read; + final Class driverClass = DriverManager.getDriver(node.getValue(DATA_SOURCE_URL)).getClass(); RedkaleClassLoader.putReflectionDeclaredConstructors(driverClass, driverClass.getName()); RedkaleClassLoader.putServiceLoader(java.sql.Driver.class); } catch (Exception e) { @@ -118,10 +118,17 @@ public class DataJdbcSource extends DataSqlSource { } catch (SQLException se) { if (!isTableNotExist(info, se.getSQLState())) throw se; if (info.getTableStrategy() == null) { - String tablesql = createTableSql(info); - if (tablesql == null) throw se; + String[] tablesqls = createTableSqls(info); + if (tablesqls == null) throw se; Statement st = conn.createStatement(); - st.execute(tablesql); + if (tablesqls.length == 1) { + st.execute(tablesqls[0]); + } else { + for (String tablesql : tablesqls) { + st.addBatch(tablesql); + } + st.executeBatch(); + } st.close(); } else { synchronized (info.disTableLock()) { @@ -138,10 +145,17 @@ public class DataJdbcSource extends DataSqlSource { } catch (SQLException sqle) { //澶氳繘绋嬪苟鍙戞椂鍙兘浼氬嚭鐜伴噸澶嶅缓琛 if (isTableNotExist(info, sqle.getSQLState())) { if (newTable.indexOf('.') < 0) { - String tablesql = createTableSql(info); - if (tablesql != null) { + String[] tablesqls = createTableSqls(info); + if (tablesqls != null) { Statement st = conn.createStatement(); - st.execute(tablesql); + if (tablesqls.length == 1) { + st.execute(tablesqls[0]); + } else { + for (String tablesql : tablesqls) { + st.addBatch(tablesql); + } + st.executeBatch(); + } st.close(); //鍐嶆墽琛屼竴閬嶅鍒惰〃鎿嶄綔 st = conn.createStatement(); @@ -166,10 +180,17 @@ public class DataJdbcSource extends DataSqlSource { info.addDisTable(tablekey); } catch (SQLException sqle2) { if (isTableNotExist(info, sqle2.getSQLState())) { - String tablesql = createTableSql(info); - if (tablesql != null) { + String[] tablesqls = createTableSqls(info); + if (tablesqls != null) { st = conn.createStatement(); - st.execute(tablesql); + if (tablesqls.length == 1) { + st.execute(tablesqls[0]); + } else { + for (String tablesql : tablesqls) { + st.addBatch(tablesql); + } + st.executeBatch(); + } st.close(); //鍐嶆墽琛屼竴閬嶅鍒惰〃鎿嶄綔 st = conn.createStatement(); @@ -243,7 +264,7 @@ public class DataJdbcSource extends DataSqlSource { 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); + Object val = getEntityAttrValue(info, attr, entity); if (val instanceof byte[]) { Blob blob = conn.createBlob(); blob.setBytes(1, (byte[]) val); @@ -254,11 +275,6 @@ public class DataJdbcSource extends DataSqlSource { 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); } @@ -282,11 +298,18 @@ public class DataJdbcSource extends DataSqlSource { } catch (SQLException e) { if (isTableNotExist(info, e.getSQLState())) { if (info.getTableStrategy() == null) { - String tablesql = createTableSql(info); - if (tablesql != null) { + String[] tablesqls = createTableSqls(info); + if (tablesqls != null) { try { Statement st = conn.createStatement(); - st.execute(tablesql); + if (tablesqls.length == 1) { + st.execute(tablesqls[0]); + } else { + for (String tablesql : tablesqls) { + st.addBatch(tablesql); + } + st.executeBatch(); + } st.close(); return CompletableFuture.completedFuture(0); } catch (SQLException e2) { @@ -390,11 +413,18 @@ public class DataJdbcSource extends DataSqlSource { } catch (SQLException e) { if (isTableNotExist(info, e.getSQLState())) { if (info.getTableStrategy() == null) { - String tablesql = createTableSql(info); - if (tablesql != null) { + String[] tablesqls = createTableSqls(info); + if (tablesqls != null) { try { Statement st = conn.createStatement(); - st.execute(tablesql); + if (tablesqls.length == 1) { + st.execute(tablesqls[0]); + } else { + for (String tablesql : tablesqls) { + st.addBatch(tablesql); + } + st.executeBatch(); + } st.close(); } catch (SQLException e2) { } @@ -436,11 +466,18 @@ public class DataJdbcSource extends DataSqlSource { } catch (SQLException e) { if (isTableNotExist(info, e.getSQLState())) { if (info.getTableStrategy() == null) { - String tablesql = createTableSql(info); - if (tablesql != null) { + String[] tablesqls = createTableSqls(info); + if (tablesqls != null) { try { Statement st = conn.createStatement(); - st.execute(tablesql); + if (tablesqls.length == 1) { + st.execute(tablesqls[0]); + } else { + for (String tablesql : tablesqls) { + st.addBatch(tablesql); + } + st.executeBatch(); + } st.close(); } catch (SQLException e2) { } @@ -480,11 +517,18 @@ public class DataJdbcSource extends DataSqlSource { } catch (SQLException e) { if (isTableNotExist(info, e.getSQLState())) { if (info.getTableStrategy() == null) { - String tablesql = createTableSql(info); - if (tablesql != null) { + String[] tablesqls = createTableSqls(info); + if (tablesqls != null) { try { Statement st = conn.createStatement(); - st.execute(tablesql); + if (tablesqls.length == 1) { + st.execute(tablesqls[0]); + } else { + for (String tablesql : tablesqls) { + st.addBatch(tablesql); + } + st.executeBatch(); + } st.close(); } catch (SQLException e2) { } @@ -517,11 +561,18 @@ public class DataJdbcSource extends DataSqlSource { } catch (SQLException e) { if (isTableNotExist(info, e.getSQLState())) { if (info.getTableStrategy() == null) { - String tablesql = createTableSql(info); - if (tablesql != null) { + String[] tablesqls = createTableSqls(info); + if (tablesqls != null) { try { Statement st = conn.createStatement(); - st.execute(tablesql); + if (tablesqls.length == 1) { + st.execute(tablesqls[0]); + } else { + for (String tablesql : tablesqls) { + st.addBatch(tablesql); + } + st.executeBatch(); + } st.close(); } catch (SQLException e2) { } @@ -555,11 +606,18 @@ public class DataJdbcSource extends DataSqlSource { } catch (SQLException e) { if (isTableNotExist(info, e.getSQLState())) { if (info.getTableStrategy() == null) { - String tablesql = createTableSql(info); - if (tablesql != null) { + String[] tablesqls = createTableSqls(info); + if (tablesqls != null) { try { Statement st = conn.createStatement(); - st.execute(tablesql); + if (tablesqls.length == 1) { + st.execute(tablesqls[0]); + } else { + for (String tablesql : tablesqls) { + st.addBatch(tablesql); + } + st.executeBatch(); + } st.close(); } catch (SQLException e2) { } @@ -608,11 +666,18 @@ public class DataJdbcSource extends DataSqlSource { } catch (SQLException e) { if (isTableNotExist(info, e.getSQLState())) { if (info.getTableStrategy() == null) { - String tablesql = createTableSql(info); - if (tablesql != null) { + String[] tablesqls = createTableSqls(info); + if (tablesqls != null) { try { Statement st = conn.createStatement(); - st.execute(tablesql); + if (tablesqls.length == 1) { + st.execute(tablesqls[0]); + } else { + for (String tablesql : tablesqls) { + st.addBatch(tablesql); + } + st.executeBatch(); + } st.close(); } catch (SQLException e2) { } @@ -634,7 +699,7 @@ public class DataJdbcSource extends DataSqlSource { //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()); + final DataResultSet set = createDataResultSet(info, ps.executeQuery()); T rs = set.next() ? selects == null ? info.getFullEntityValue(set) : info.getEntityValue(selects, set) : null; set.close(); ps.close(); @@ -642,11 +707,18 @@ public class DataJdbcSource extends DataSqlSource { } catch (SQLException e) { if (isTableNotExist(info, e.getSQLState())) { if (info.getTableStrategy() == null) { - String tablesql = createTableSql(info); - if (tablesql != null) { + String[] tablesqls = createTableSqls(info); + if (tablesqls != null) { try { Statement st = conn.createStatement(); - st.execute(tablesql); + if (tablesqls.length == 1) { + st.execute(tablesqls[0]); + } else { + for (String tablesql : tablesqls) { + st.addBatch(tablesql); + } + st.executeBatch(); + } st.close(); } catch (SQLException e2) { } @@ -669,7 +741,7 @@ public class DataJdbcSource extends DataSqlSource { 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()); + final DataResultSet set = createDataResultSet(info, ps.executeQuery()); Serializable val = defValue; if (set.next()) { val = info.getFieldValue(attr, set, 1); @@ -680,11 +752,18 @@ public class DataJdbcSource extends DataSqlSource { } catch (SQLException e) { if (isTableNotExist(info, e.getSQLState())) { if (info.getTableStrategy() == null) { - String tablesql = createTableSql(info); - if (tablesql != null) { + String[] tablesqls = createTableSqls(info); + if (tablesqls != null) { try { Statement st = conn.createStatement(); - st.execute(tablesql); + if (tablesqls.length == 1) { + st.execute(tablesqls[0]); + } else { + for (String tablesql : tablesqls) { + st.addBatch(tablesql); + } + st.executeBatch(); + } st.close(); } catch (SQLException e2) { } @@ -714,11 +793,18 @@ public class DataJdbcSource extends DataSqlSource { } catch (SQLException e) { if (isTableNotExist(info, e.getSQLState())) { if (info.getTableStrategy() == null) { - String tablesql = createTableSql(info); - if (tablesql != null) { + String[] tablesqls = createTableSqls(info); + if (tablesqls != null) { try { Statement st = conn.createStatement(); - st.execute(tablesql); + if (tablesqls.length == 1) { + st.execute(tablesqls[0]); + } else { + for (String tablesql : tablesqls) { + st.addBatch(tablesql); + } + st.executeBatch(); + } st.close(); } catch (SQLException e2) { } @@ -752,7 +838,7 @@ public class DataJdbcSource extends DataSqlSource { } PreparedStatement ps = conn.prepareStatement(listsql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); ResultSet set = ps.executeQuery(); - final DataResultSet rr = createDataResultSet(set); + final DataResultSet rr = createDataResultSet(info, set); while (set.next()) { list.add(getEntityValue(info, sels, rr)); } @@ -784,7 +870,7 @@ public class DataJdbcSource extends DataSqlSource { 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); + final DataResultSet rr = createDataResultSet(info, set); if (sels == null) { while (set.next()) { i++; @@ -809,11 +895,18 @@ public class DataJdbcSource extends DataSqlSource { } catch (SQLException e) { if (isTableNotExist(info, e.getSQLState())) { if (info.getTableStrategy() == null) { - String tablesql = createTableSql(info); - if (tablesql != null) { + String[] tablesqls = createTableSqls(info); + if (tablesqls != null) { try { Statement st = conn.createStatement(); - st.execute(tablesql); + if (tablesqls.length == 1) { + st.execute(tablesqls[0]); + } else { + for (String tablesql : tablesqls) { + st.addBatch(tablesql); + } + st.executeBatch(); + } st.close(); } catch (SQLException e2) { } @@ -891,7 +984,7 @@ public class DataJdbcSource extends DataSqlSource { 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)); + V rs = handler.apply(createDataResultSet(null, set)); set.close(); statement.close(); return rs; @@ -902,7 +995,7 @@ public class DataJdbcSource extends DataSqlSource { } } - public static DataResultSet createDataResultSet(ResultSet set) { + public static DataResultSet createDataResultSet(EntityInfo info, ResultSet set) { final ResultSet rr = set; @@ -978,6 +1071,11 @@ public class DataJdbcSource extends DataSqlSource { } } + @Override + public EntityInfo getEntityInfo() { + return info; + } + }; } @@ -1006,12 +1104,12 @@ public class DataJdbcSource extends DataSqlSource { 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.connectTimeoutSeconds = Integer.decode(prop.getProperty(DATA_SOURCE_CONNECTTIMEOUT_SECONDS, "6")); + this.maxconns = Math.max(1, Integer.decode(prop.getProperty(DATA_SOURCE_MAXCONNS, "" + 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.url = prop.getProperty(DATA_SOURCE_URL); + String username = prop.getProperty(DATA_SOURCE_USER, ""); + String password = prop.getProperty(DATA_SOURCE_PASSWORD, ""); this.connectAttrs = new Properties(); if (username != null) this.connectAttrs.put("user", username); if (password != null) this.connectAttrs.put("password", password); diff --git a/src/main/java/org/redkale/source/DataMemorySource.java b/src/main/java/org/redkale/source/DataMemorySource.java index b9a80fd44..6308c3aed 100644 --- a/src/main/java/org/redkale/source/DataMemorySource.java +++ b/src/main/java/org/redkale/source/DataMemorySource.java @@ -6,7 +6,6 @@ package org.redkale.source; import java.io.Serializable; -import java.net.URL; import java.util.*; import java.util.concurrent.*; import java.util.function.*; @@ -20,7 +19,7 @@ import org.redkale.util.*; */ /** * DataSource鐨凪emory瀹炵幇绫
- * 娉ㄦ剰: javax.persistence.jdbc.url 闇瑕佹寚瀹氫负 memory:source + * 娉ㄦ剰: url 闇瑕佹寚瀹氫负 memory:datasource * *

* 璇︽儏瑙: https://redkale.org @@ -33,8 +32,8 @@ import org.redkale.util.*; @ResourceType(DataSource.class) public class DataMemorySource extends DataSqlSource implements SearchSource { - public DataMemorySource(String unitName, URL persistFile, Properties readprop, Properties writeprop) { - super(unitName, persistFile, "memory", readprop, writeprop); + public DataMemorySource(String name) { + this.name = name; this.cacheForbidden = false; } @@ -44,6 +43,19 @@ public class DataMemorySource extends DataSqlSource implements SearchSource { return "memory"; } + public static boolean acceptsConf(AnyValue config) { + return config.getValue(DATA_SOURCE_URL).startsWith("memory:"); + } + + public static boolean isSearchType(AnyValue config) { + return config.getValue(DATA_SOURCE_URL).startsWith("memory:search"); + } + + @Override + public String toString() { + return getClass().getSimpleName() + "{type=memory, name='" + resourceName() + "'}"; + } + @Override @Local public void compile(Class clazz) { @@ -52,12 +64,12 @@ public class DataMemorySource extends DataSqlSource implements SearchSource { } @Override - public int updateMapping(final Class clazz) { + public int updateMapping(final Class clazz, String table) { return 0; } @Override - public CompletableFuture updateMappingAsync(final Class clazz) { + public CompletableFuture updateMappingAsync(final Class clazz, String table) { return CompletableFuture.completedFuture(0); } diff --git a/src/main/java/org/redkale/source/DataResultSet.java b/src/main/java/org/redkale/source/DataResultSet.java index b0f883386..0e6124600 100644 --- a/src/main/java/org/redkale/source/DataResultSet.java +++ b/src/main/java/org/redkale/source/DataResultSet.java @@ -47,12 +47,13 @@ public interface DataResultSet extends EntityInfo.DataResultSetRow { 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鐨勬暟鎹 + Serializable o = null; + try { + 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 { @@ -61,98 +62,97 @@ public interface DataResultSet extends EntityInfo.DataResultSetRow { // 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(); + o = (byte[]) blob; + //} + } + } else { + o = (Serializable) (index > 0 ? row.getObject(index) : row.getObject(column)); + 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 = ((Number) o).longValue(); + o = 0L; } else if (t == short.class) { - o = ((Number) o).shortValue(); + o = (short) 0; } else if (t == float.class) { - o = ((Number) o).floatValue(); + o = 0.0f; } else if (t == double.class) { - o = ((Number) o).doubleValue(); + o = 0.0d; } else if (t == byte.class) { - o = ((Number) o).byteValue(); - } else if (t == char.class) { - o = (char) ((Number) o).intValue(); + o = (byte) 0; } else if (t == boolean.class) { - o = (Boolean) o; + o = false; + } else if (t == char.class) { + o = (char) 0; } - } 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 if (t == AtomicInteger.class) { + if (o != null) { + o = new AtomicInteger(((Number) o).intValue()); } else { - o = new BigInteger(o.toString(), 10); + o = new AtomicInteger(); } - } - } else if (t == BigDecimal.class) { - if (o != null && !(o instanceof BigDecimal)) { - if (o instanceof byte[]) { - o = new BigDecimal(new String((byte[]) o)); + } else if (t == AtomicLong.class) { + if (o != null) { + o = new AtomicLong(((Number) o).longValue()); } else { - o = new BigInteger(o.toString()); + 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 (t == String.class) { + if (o == null) { + o = ""; + } else if (o instanceof byte[]) { + o = new String((byte[]) o, StandardCharsets.UTF_8); + } else { + o = 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()); } - } else if (t == String.class) { - if (o == null) { - o = ""; - } else if (o instanceof byte[]) { - o = new String((byte[]) o, StandardCharsets.UTF_8); - } else { - o = 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()); } + } catch (Exception e) { + throw new RuntimeException(row.getEntityInfo() + "." + attr.field() + ".value=" + o + ": " + e.getMessage(), e.getCause()); } return o; } diff --git a/src/main/java/org/redkale/source/DataSource.java b/src/main/java/org/redkale/source/DataSource.java index 63d0e6d64..919189eeb 100644 --- a/src/main/java/org/redkale/source/DataSource.java +++ b/src/main/java/org/redkale/source/DataSource.java @@ -1553,6 +1553,32 @@ public interface DataSource { return findsAsync(clazz, selects, pks.toArray(v -> new Serializable[v])); } + /** + * 鑾峰彇鎸囧畾涓婚敭鍊肩殑澶氫釜璁板綍, 杩斿洖鍒楄〃
+ * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {primary} = {id1,id2, ···}
+ * + * @param 涓婚敭娉涘瀷 + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param pks 涓婚敭鍊奸泦鍚 + * + * @return Entity瀵硅薄 + */ + public List findsList(final Class clazz, final Stream pks); + + /** + * 鑾峰彇鎸囧畾涓婚敭鍊肩殑澶氫釜璁板綍, 杩斿洖鍒楄〃
+ * 绛変环SQL: SELECT {column1},{column2}, ··· FROM {table} WHERE {primary} = {id1,id2, ···}
+ * + * @param 涓婚敭娉涘瀷 + * @param Entity娉涘瀷 + * @param clazz Entity绫 + * @param pks 涓婚敭鍊奸泦鍚 + * + * @return Entity瀵硅薄 + */ + public CompletableFuture> findsListAsync(final Class clazz, final Stream pks); + /** * 鑾峰彇绗﹀悎杩囨护鏉′欢鍗曚釜璁板綍, 杩斿洖null琛ㄧず涓嶅瓨鍦ㄥ
* 绛変环SQL: SELECT * FROM {table} WHERE {column} = {key}
diff --git a/src/main/java/org/redkale/source/DataSourceProvider.java b/src/main/java/org/redkale/source/DataSourceProvider.java index ffbc21b7a..e8e605ed0 100644 --- a/src/main/java/org/redkale/source/DataSourceProvider.java +++ b/src/main/java/org/redkale/source/DataSourceProvider.java @@ -8,7 +8,7 @@ package org.redkale.source; import org.redkale.util.AnyValue; /** - * + * * 鑷畾涔夌殑DataSource鍔犺浇鍣, 濡傛灉鏍囪@Priority鍔犺浇鍣ㄧ殑浼樺厛绾ч渶瑕佸ぇ浜1000锛 1000浠ヤ笅棰勭暀缁欏畼鏂瑰姞杞藉櫒 * *

diff --git a/src/main/java/org/redkale/source/DataSources.java b/src/main/java/org/redkale/source/DataSources.java index daf0d13d3..0f9b5d2b7 100644 --- a/src/main/java/org/redkale/source/DataSources.java +++ b/src/main/java/org/redkale/source/DataSources.java @@ -6,66 +6,84 @@ 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.AnyValue.DefaultAnyValue; import org.redkale.util.RedkaleClassLoader; /** + * 甯搁噺鏀惧叆 AbstractDataSource 绫讳腑锛屾柟娉曢兘宸蹭綔搴燂紝persistence.xml 閲囩敤 source.properties 浠f浛 * * @author zhangjx */ +@Deprecated //@deprecated @since 2.7.0 public final class DataSources { - public static final String DATASOURCE_CONFPATH = "DATASOURCE_CONFPATH"; + @Deprecated //@deprecated @since 2.7.0 + private static final String DATASOURCE_CONFPATH = "DATASOURCE_CONFPATH"; - public static final String JDBC_DATASOURCE_CLASS = "javax.persistence.datasource"; + @Deprecated //@deprecated @since 2.7.0 + private static final String JDBC_DATASOURCE_CLASS = "javax.persistence.datasource"; - public static final String JDBC_TABLE_AUTODDL = "javax.persistence.table.autoddl"; + @Deprecated //@deprecated @since 2.7.0 + private static final String JDBC_TABLE_AUTODDL = "javax.persistence.table.autoddl"; - public static final String JDBC_CACHE_MODE = "javax.persistence.cachemode"; + @Deprecated //@deprecated @since 2.7.0 + private static final String JDBC_CACHE_MODE = "javax.persistence.cachemode"; - public static final String JDBC_CONNECTIONS_LIMIT = "javax.persistence.connections.limit"; + @Deprecated //@deprecated @since 2.7.0 + private static final String JDBC_CONNECTIONS_LIMIT = "javax.persistence.connections.limit"; - public static final String JDBC_CONNECTIONSCAPACITY = "javax.persistence.connections.bufcapacity"; + @Deprecated //@deprecated @since 2.7.0 + private static final String JDBC_CONNECTIONSCAPACITY = "javax.persistence.connections.bufcapacity"; - public static final String JDBC_CONTAIN_SQLTEMPLATE = "javax.persistence.contain.sqltemplate"; + @Deprecated //@deprecated @since 2.7.0 + private static final String JDBC_CONTAIN_SQLTEMPLATE = "javax.persistence.contain.sqltemplate"; - public static final String JDBC_NOTCONTAIN_SQLTEMPLATE = "javax.persistence.notcontain.sqltemplate"; + @Deprecated //@deprecated @since 2.7.0 + private static final String JDBC_NOTCONTAIN_SQLTEMPLATE = "javax.persistence.notcontain.sqltemplate"; - public static final String JDBC_TABLENOTEXIST_SQLSTATES = "javax.persistence.tablenotexist.sqlstates"; + @Deprecated //@deprecated @since 2.7.0 + private static final String JDBC_TABLENOTEXIST_SQLSTATES = "javax.persistence.tablenotexist.sqlstates"; - public static final String JDBC_TABLECOPY_SQLTEMPLATE = "javax.persistence.tablecopy.sqltemplate"; + @Deprecated //@deprecated @since 2.7.0 + private static final String JDBC_TABLECOPY_SQLTEMPLATE = "javax.persistence.tablecopy.sqltemplate"; - public static final String JDBC_CONNECTTIMEOUT_SECONDS = "javax.persistence.connecttimeout"; + @Deprecated //@deprecated @since 2.7.0 + private static final String JDBC_CONNECTTIMEOUT_SECONDS = "javax.persistence.connecttimeout"; - public static final String JDBC_READTIMEOUT_SECONDS = "javax.persistence.readtimeout"; + @Deprecated //@deprecated @since 2.7.0 + private static final String JDBC_READTIMEOUT_SECONDS = "javax.persistence.readtimeout"; - public static final String JDBC_WRITETIMEOUT_SECONDS = "javax.persistence.writetimeout"; + @Deprecated //@deprecated @since 2.7.0 + private static final String JDBC_WRITETIMEOUT_SECONDS = "javax.persistence.writetimeout"; - public static final String JDBC_URL = "javax.persistence.jdbc.url"; + @Deprecated //@deprecated @since 2.7.0 + private static final String JDBC_URL = "javax.persistence.jdbc.url"; - public static final String JDBC_USER = "javax.persistence.jdbc.user"; + @Deprecated //@deprecated @since 2.7.0 + private static final String JDBC_USER = "javax.persistence.jdbc.user"; - public static final String JDBC_PWD = "javax.persistence.jdbc.password"; + @Deprecated //@deprecated @since 2.7.0 + private static final String JDBC_PWD = "javax.persistence.jdbc.password"; - public static final String JDBC_ENCODING = "javax.persistence.jdbc.encoding"; + @Deprecated //@deprecated @since 2.7.0 + private 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"; + private 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"; + private 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 static final String JDBC_AUTO_MAPPING = "javax.persistence.jdbc.auto-mapping"; private DataSources() { } + @Deprecated //@deprecated @since 2.7.0 public static DataSource createDataSource(final String unitName, final AnyValue conf) throws IOException { Properties prop = new Properties(); AnyValue[] confs = conf.getAnyValues("property"); @@ -79,118 +97,99 @@ public final class DataSources { return createDataSource(unitName, prop, prop); } + @Deprecated //@deprecated @since 2.7.0 public static DataSource createDataSource(final String unitName, Properties prop) throws IOException { return createDataSource(unitName, prop, prop); } + @Deprecated //@deprecated @since 2.7.0 public static DataSource createDataSource(final String unitName, Properties readprop, Properties writeprop) throws IOException { return createDataSource(unitName, null, readprop, writeprop); } + @Deprecated //@deprecated @since 2.7.0 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; + throw new UnsupportedOperationException("Not supported yet."); +// 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, AbstractDataSource.parseDbtype(readprop.getProperty(JDBC_URL)), readprop, writeprop); +// } +// String url = readprop.getProperty(JDBC_URL); +// dbtype = AbstractDataSource.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 = AbstractDataSource.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); +// } } + @Deprecated //@deprecated @since 2.7.0 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())); } + @Deprecated //@deprecated @since 2.7.0 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(); @@ -224,13 +223,79 @@ public final class DataSources { } 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); + if (readprop.getProperty(JDBC_URL, "").startsWith("memory:source")) return new DataMemorySource(unitName); return createDataSource(unitName, readprop, writeprop); } + //@since 2.7.0 + public static Map loadAnyValuePersistenceXml(final InputStream in) { + try { + Map map = loadPersistenceXml(in); + Map rs = new HashMap<>(); + map.forEach((unitName, prop) -> { + if (unitName.endsWith(".write")) return; + DefaultAnyValue v = parseProperties(prop); + if (unitName.endsWith(".read")) { + String name = unitName.replace(".read", ""); + DefaultAnyValue parent = DefaultAnyValue.create(); + parent.addValue("read", v); + parent.addValue("write", parseProperties(map.get(name + ".write"))); + parent.setValue("name", name); + rs.put(name, parent); + } else { + v.setValue("name", unitName); + rs.put(unitName, v); + } + }); + return rs; + } catch (RuntimeException e) { + throw e; + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + + private static DefaultAnyValue parseProperties(Properties prop) { + DefaultAnyValue v = DefaultAnyValue.create(); + prop.forEach((x, y) -> { + if (JDBC_TABLE_AUTODDL.equalsIgnoreCase(x.toString())) { + x = AbstractDataSource.DATA_SOURCE_TABLE_AUTODDL; + } else if (JDBC_CACHE_MODE.equalsIgnoreCase(x.toString())) { + x = AbstractDataSource.DATA_SOURCE_CACHEMODE; + } else if (JDBC_CONNECTIONS_LIMIT.equalsIgnoreCase(x.toString())) { + x = AbstractDataSource.DATA_SOURCE_MAXCONNS; + } else if (JDBC_CONNECTIONSCAPACITY.equalsIgnoreCase(x.toString())) { + x = AbstractDataSource.DATA_SOURCE_CONNECTIONS_CAPACITY; + } else if (JDBC_CONTAIN_SQLTEMPLATE.equalsIgnoreCase(x.toString())) { + x = AbstractDataSource.DATA_SOURCE_CONTAIN_SQLTEMPLATE; + } else if (JDBC_NOTCONTAIN_SQLTEMPLATE.equalsIgnoreCase(x.toString())) { + x = AbstractDataSource.DATA_SOURCE_NOTCONTAIN_SQLTEMPLATE; + } else if (JDBC_TABLENOTEXIST_SQLSTATES.equalsIgnoreCase(x.toString())) { + x = AbstractDataSource.DATA_SOURCE_TABLENOTEXIST_SQLSTATES; + } else if (JDBC_TABLECOPY_SQLTEMPLATE.equalsIgnoreCase(x.toString())) { + x = AbstractDataSource.DATA_SOURCE_TABLECOPY_SQLTEMPLATE; + } else if (JDBC_CONNECTTIMEOUT_SECONDS.equalsIgnoreCase(x.toString())) { + x = AbstractDataSource.DATA_SOURCE_CONNECTTIMEOUT_SECONDS; + } else if (JDBC_URL.equalsIgnoreCase(x.toString())) { + x = AbstractDataSource.DATA_SOURCE_URL; + } else if (JDBC_USER.equalsIgnoreCase(x.toString())) { + x = AbstractDataSource.DATA_SOURCE_USER; + } else if (JDBC_PWD.equalsIgnoreCase(x.toString())) { + x = AbstractDataSource.DATA_SOURCE_PASSWORD; + } else if (JDBC_AUTO_MAPPING.equalsIgnoreCase(x.toString())) { + x = AbstractDataSource.DATA_SOURCE_AUTOMAPPING; + } else if (JDBC_ENCODING.equalsIgnoreCase(x.toString())) { + x = AbstractDataSource.DATA_SOURCE_ENCODING; + } + v.addValue(x.toString(), y.toString()); + }); + return v; + } + + @Deprecated //@deprecated @since 2.7.0 public static Map loadPersistenceXml(final InputStream in0) { - final Map map = new LinkedHashMap(); + final Map map = new TreeMap<>(); boolean flag = false; try (final InputStream in = in0) { @@ -264,52 +329,4 @@ public final class DataSources { 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 be99b0dfa..e5edb717a 100644 --- a/src/main/java/org/redkale/source/DataSqlSource.java +++ b/src/main/java/org/redkale/source/DataSqlSource.java @@ -7,7 +7,7 @@ package org.redkale.source; import java.io.Serializable; import java.math.*; -import java.net.URL; +import java.net.*; import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.*; @@ -18,7 +18,6 @@ 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.*; @@ -47,9 +46,9 @@ public abstract class DataSqlSource extends AbstractDataSource implements Functi protected boolean cacheForbidden; - private final String dbtype; + protected String dbtype; - private final boolean autoddl; + private boolean autoddl; protected Properties readConfProps; @@ -61,7 +60,7 @@ public abstract class DataSqlSource extends AbstractDataSource implements Functi @Resource(name = RESNAME_APP_EXECUTOR) protected ExecutorService workExecutor; - protected final BiFunction sqlFormatter; + protected BiFunction sqlFormatter; protected BiConsumer futureCompleteConsumer = (r, t) -> { if (t != null) logger.log(Level.INFO, "CompletableFuture complete error", (Throwable) t); @@ -71,66 +70,98 @@ public abstract class DataSqlSource extends AbstractDataSource implements Functi -> ((CompletableFuture) querySheetDB(i, false, false, false, null, null, (FilterNode) null)).thenApply(e -> e == null ? new ArrayList() : e.list(true)); //鐢ㄤ簬鍙嶅悜LIKE浣跨敤 - protected final String containSQL; + protected String containSQL; //鐢ㄤ簬鍙嶅悜LIKE浣跨敤 - protected final String notcontainSQL; + protected String notContainSQL; //鐢ㄤ簬鍒ゆ柇琛ㄤ笉瀛樺湪鐨勪娇鐢, 澶氫釜SQLState鐢;闅斿紑 - protected final String tablenotexistSqlstates; + protected String tableNotExistSqlstates; //鐢ㄤ簬澶嶅埗琛ㄧ粨鏋勪娇鐢 - protected final String tablecopySQL; + protected 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; + public DataSqlSource() { + } + + @Override + public void init(AnyValue conf) { + if (conf.getAnyValue("read") == null) { //娌℃湁璇诲啓鍒嗙 + Properties rwConf = new Properties(); + conf.forEach((k, v) -> rwConf.put(k, v)); + this.dbtype = parseDbtype(rwConf.getProperty(DATA_SOURCE_URL)); + decryptProperties(rwConf); + initProperties(rwConf); + this.readConfProps = rwConf; + this.writeConfProps = rwConf; + } else { //璇诲啓鍒嗙 + Properties readConf = new Properties(); + Properties writeConf = new Properties(); + conf.getAnyValue("read").forEach((k, v) -> readConf.put(k, v)); + conf.getAnyValue("write").forEach((k, v) -> writeConf.put(k, v)); + this.dbtype = parseDbtype(readConf.getProperty(DATA_SOURCE_URL)); + decryptProperties(readConf); + decryptProperties(writeConf); + initProperties(readConf); + initProperties(writeConf); + this.readConfProps = readConf; + this.writeConfProps = writeConf; + } + this.name = conf.getValue("name", ""); this.sqlFormatter = (info, val) -> formatValueToString(info, val); - this.autoddl = "true".equals(readConf.getProperty(DataSources.JDBC_TABLE_AUTODDL, "false").trim()); + this.autoddl = "true".equals(readConfProps.getProperty(DATA_SOURCE_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.containSQL = readConfProps.getProperty(DATA_SOURCE_CONTAIN_SQLTEMPLATE, "LOCATE(${keystr}, ${column}) > 0"); + this.notContainSQL = readConfProps.getProperty(DATA_SOURCE_NOTCONTAIN_SQLTEMPLATE, "LOCATE(${keystr}, ${column}) = 0"); + + this.tableNotExistSqlstates = ";" + readConfProps.getProperty(DATA_SOURCE_TABLENOTEXIST_SQLSTATES, "42000;42S02") + ";"; + this.tablecopySQL = readConfProps.getProperty(DATA_SOURCE_TABLECOPY_SQLTEMPLATE, "CREATE TABLE IF NOT EXISTS ${newtable} LIKE ${oldtable}"); + this.cacheForbidden = "NONE".equalsIgnoreCase(readConfProps.getProperty(DATA_SOURCE_CACHEMODE)); + } + + //瑙e瘑鍙兘瀛樺湪鐨勫姞瀵嗗瓧娈, 鍙噸杞 + protected void decryptProperties(Properties props) { - 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"); + props.setProperty(DATA_SOURCE_CONTAIN_SQLTEMPLATE, "INSTR(${keystr}, ${column}) > 0"); + props.setProperty(DATA_SOURCE_NOTCONTAIN_SQLTEMPLATE, "INSTR(${keystr}, ${column}) = 0"); + if (!props.containsKey(DATA_SOURCE_TABLENOTEXIST_SQLSTATES)) { + props.setProperty(DATA_SOURCE_TABLENOTEXIST_SQLSTATES, "42000;42S02"); } - if (!props.containsKey(JDBC_TABLECOPY_SQLTEMPLATE)) { + if (!props.containsKey(DATA_SOURCE_TABLECOPY_SQLTEMPLATE)) { //娉ㄦ剰锛氭璇彞澶嶅埗琛ㄧ粨鏋勪細瀵艰嚧榛樿鍊煎拰涓婚敭淇℃伅鐨勪涪澶 - props.setProperty(JDBC_TABLECOPY_SQLTEMPLATE, "CREATE TABLE IF NOT EXISTS ${newtable} AS SELECT * FROM ${oldtable} WHERE 1=2"); + props.setProperty(DATA_SOURCE_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"); + props.setProperty(DATA_SOURCE_CONTAIN_SQLTEMPLATE, "CHARINDEX(${column}, ${keystr}) > 0"); + props.setProperty(DATA_SOURCE_NOTCONTAIN_SQLTEMPLATE, "CHARINDEX(${column}, ${keystr}) = 0"); } else if ("postgresql".equals(this.dbtype)) { - if (!props.containsKey(JDBC_TABLECOPY_SQLTEMPLATE)) { //娉ㄦ剰锛氭璇彞澶嶅埗琛ㄧ粨鏋勪細瀵艰嚧榛樿鍊煎拰涓婚敭淇℃伅鐨勪涪澶 + if (!props.containsKey(DATA_SOURCE_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)"); + //props.setProperty(DATA_SOURCE_TABLECOPY_SQLTEMPLATE, "CREATE TABLE ${newtable} AS (SELECT * FROM ${oldtable} LIMIT 0)"); + props.setProperty(DATA_SOURCE_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"); + if (!props.containsKey(DATA_SOURCE_TABLENOTEXIST_SQLSTATES)) { + props.setProperty(DATA_SOURCE_TABLENOTEXIST_SQLSTATES, "42P01;3F000"); } } } + @Override + public String toString() { + if (readConfProps == null) return getClass().getSimpleName() + "{}"; //compileMode妯″紡涓嬩細涓簄ull + if (readConfProps == writeConfProps) { + return getClass().getSimpleName() + "{url=" + readConfProps.getProperty(DATA_SOURCE_URL) + "}"; + } else { + return getClass().getSimpleName() + "{readurl=" + readConfProps.getProperty(DATA_SOURCE_URL) + ",writeurl=" + writeConfProps.getProperty(DATA_SOURCE_URL) + "}"; + } + } + //鐢熸垚鍒涘缓琛ㄧ殑SQL - protected String createTableSql(EntityInfo info) { + protected String[] createTableSqls(EntityInfo info) { if (info == null || !autoddl) return null; javax.persistence.Table table = info.getType().getAnnotation(javax.persistence.Table.class); if ("mysql".equals(dbtype())) { //mysql @@ -240,7 +271,7 @@ public abstract class DataSqlSource extends AbstractDataSource implements Functi if (table != null && !table.comment().isEmpty()) { sb.append(" COMMENT '").append(table.comment().replace('\'', '"')).append("'"); } - return sb.toString(); + return Utility.ofArray(sb.toString()); } else if ("postgresql".equals(dbtype())) { //postgresql StringBuilder sb = new StringBuilder(); sb.append("CREATE TABLE IF NOT EXISTS ").append(info.getOriginTable()).append("(\n"); @@ -311,7 +342,7 @@ public abstract class DataSqlSource extends AbstractDataSource implements Functi if (!column.nullable) sqlnull = "NOT NULL"; } } else if (column.type == byte[].class) { - sqltype = "OID"; + sqltype = "BYTEA"; 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"; @@ -331,7 +362,7 @@ public abstract class DataSqlSource extends AbstractDataSource implements Functi } sb.append(" PRIMARY KEY (").append(primary.column).append(")\n"); sb.append(")"); - return sb.toString(); + return Utility.ofArray(sb.toString()); } return null; } @@ -339,7 +370,7 @@ public abstract class DataSqlSource extends AbstractDataSource implements Functi @Local protected boolean isTableNotExist(EntityInfo info, String code) { if (code == null || code.isEmpty()) return false; - return tablenotexistSqlstates.contains(';' + code + ';'); + return tableNotExistSqlstates.contains(';' + code + ';'); } @Local @@ -347,9 +378,21 @@ public abstract class DataSqlSource extends AbstractDataSource implements Functi return tablecopySQL.replace("${newtable}", newTable).replace("${oldtable}", info.table); } - @Override - public void init(AnyValue conf) { - this.cacheForbidden = "NONE".equalsIgnoreCase(readConfProps.getProperty(JDBC_CACHE_MODE)); + @Local + protected Serializable getSQLAttrValue(EntityInfo info, Attribute attr, Serializable val) { + 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.")) { + val = info.jsonConvert.convertTo(attr.genericType(), val); + } else if (val == null && info.isNotNullJson(attr)) { + val = ""; + } + return val; + } + + @Local + protected Serializable getEntityAttrValue(EntityInfo info, Attribute attr, T entity) { + Serializable val = info.getSQLValue(attr, entity); + return getSQLAttrValue(info, attr, val); } @Override @@ -484,7 +527,6 @@ public abstract class DataSqlSource extends AbstractDataSource implements Functi } 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) { @@ -699,6 +741,7 @@ public abstract class DataSqlSource extends AbstractDataSource implements Functi } protected CompletableFuture deleteCompose(final EntityInfo info, final Flipper flipper, final FilterNode node) { + boolean pgsql = "postgresql".equals(dbtype()); Map joinTabalis = null; CharSequence join = null; CharSequence where = null; @@ -714,11 +757,19 @@ public abstract class DataSqlSource extends AbstractDataSource implements Functi 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())))); + String sql; + if (pgsql && flipper != null && flipper.getLimit() > 0) { + String wherestr = ((where == null || where.length() == 0) ? (join2 == null ? "" : (" WHERE " + join2)) + : (" WHERE " + where + (join2 == null ? "" : (" AND " + join2)))); + sql = "DELETE FROM " + info.getTable(node) + " a" + (join1 == null ? "" : (", " + join1)) + + " WHERE " + info.getPrimarySQLColumn() + " IN (SELECT " + info.getPrimaryColumn() + " FROM " + info.getTable(node) + + wherestr + info.createSQLOrderby(flipper) + " OFFSET 0 LIMIT " + flipper.getLimit() + ")"; + } else { + sql = "DELETE " + (("mysql".equals(dbtype()) && join1 != null) ? "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) + + (("mysql".equals(dbtype()) && flipper != null && flipper.getLimit() > 0) ? (" LIMIT " + flipper.getLimit()) : ""); + } return deleteDB(info, flipper, sql); } @@ -807,9 +858,9 @@ public abstract class DataSqlSource extends AbstractDataSource implements Functi } 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); + final String table = node == null ? info.getOriginTable() : info.getTable(node); + String sql = "DROP TABLE IF EXISTS " + table; + //if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(info.getType().getSimpleName() + " dropTable sql=" + sql); return dropTableDB(info, table, sql); } @@ -951,12 +1002,14 @@ public abstract class DataSqlSource extends AbstractDataSource implements Functi } protected CompletableFuture updateColumnCompose(final EntityInfo info, Serializable pk, String column, final Serializable colval) { - if (colval instanceof byte[]) { + Attribute attr = info.getAttribute(column); + Serializable val = getSQLAttrValue(info, attr, colval); + if (val 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); + return updateColumnDB(info, null, sql, true, val); } 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); + + info.formatSQLValue(column, val, sqlFormatter) + " WHERE " + info.getPrimarySQLColumn() + "=" + info.formatSQLValue(info.getPrimarySQLColumn(), pk, sqlFormatter); return updateColumnDB(info, null, sql, false); } } @@ -1019,16 +1072,18 @@ public abstract class DataSqlSource extends AbstractDataSource implements Functi join1 = multisplit('[', ']', ",", new StringBuilder(), joinstr, 0); join2 = multisplit('{', '}', " AND ", new StringBuilder(), joinstr, 0); } + Attribute attr = info.getAttribute(column); + Serializable val = getSQLAttrValue(info, attr, colval); String alias = "postgresql".equals(dbtype()) ? null : "a"; //postgresql鐨凚UG锛 UPDATE鐨凷ET涓笉鑳藉惈鍒悕 - if (colval instanceof byte[]) { + if (val 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); + return updateColumnDB(info, null, sql, true, val); } else { String sql = "UPDATE " + info.getTable(node) + " a " + (join1 == null ? "" : (", " + join1)) - + " SET " + info.getSQLColumn(alias, column) + "=" + info.formatSQLValue(colval, sqlFormatter) + + " SET " + info.getSQLColumn(alias, column) + "=" + info.formatSQLValue(val, sqlFormatter) + ((where == null || where.length() == 0) ? (join2 == null ? "" : (" WHERE " + join2)) : (" WHERE " + where + (join2 == null ? "" : (" AND " + join2)))); return updateColumnDB(info, null, sql, false); @@ -1147,7 +1202,8 @@ public abstract class DataSqlSource extends AbstractDataSource implements Functi StringBuilder setsql = new StringBuilder(); List blobs = null; int index = 0; - String alias = "postgresql".equals(dbtype()) ? null : "a"; //postgresql鐨凚UG锛 UPDATE鐨凷ET涓笉鑳藉惈鍒悕 + boolean pgsql = "postgresql".equals(dbtype()); + String alias = pgsql ? null : "a"; //postgresql鐨凚UG锛 UPDATE鐨凷ET涓笉鑳藉惈鍒悕 for (ColumnValue col : values) { if (col == null) continue; Attribute attr = info.getUpdateAttribute(col.getColumn()); @@ -1173,19 +1229,44 @@ public abstract class DataSqlSource extends AbstractDataSource implements Functi 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); + String sql; + if (pgsql && flipper != null && flipper.getLimit() > 0) { + String wherestr = ((where == null || where.length() == 0) ? (join2 == null ? "" : (" WHERE " + join2)) + : (" WHERE " + where + (join2 == null ? "" : (" AND " + join2)))); + sql = "UPDATE " + info.getTable(node) + " a " + (join1 == null ? "" : (", " + join1)) + " SET " + setsql + + " WHERE " + info.getPrimarySQLColumn() + " IN (SELECT " + info.getPrimaryColumn() + " FROM " + info.getTable(node) + + wherestr + info.createSQLOrderby(flipper) + " OFFSET 0 LIMIT " + flipper.getLimit() + ")"; + } else { + 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) + + (("mysql".equals(dbtype()) && flipper != null && flipper.getLimit() > 0) ? (" LIMIT " + flipper.getLimit()) : ""); + } + if (blobs == null) return updateColumnDB(info, flipper, sql, false); return updateColumnDB(info, flipper, sql, true, blobs.toArray()); } + //杩斿洖涓嶅瓨鍦ㄧ殑瀛楁鍚,null琛ㄧず瀛楁閮藉悎娉; + protected String checkIllegalColumn(final EntityInfo info, SelectColumn selects) { + if (selects == null) return null; + String[] columns = selects.getColumns(); + if (columns == null) return null; + for (String col : columns) { + if (info.getAttribute(col) == null) return col; + } + return null; + } + @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); + String illegalColumn = checkIllegalColumn(info, selects); + if (illegalColumn != null) { + throw new RuntimeException(info.getType() + " cannot found column " + illegalColumn); + } 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) { @@ -1201,6 +1282,10 @@ public abstract class DataSqlSource extends AbstractDataSource implements Functi if (entity == null || selects == null) return CompletableFuture.completedFuture(-1); Class clazz = (Class) entity.getClass(); final EntityInfo info = loadEntityInfo(clazz); + String illegalColumn = checkIllegalColumn(info, selects); + if (illegalColumn != null) { + return CompletableFuture.failedFuture(new RuntimeException(info.getType() + " cannot found column " + illegalColumn)); + } if (isOnlyCache(info)) { return CompletableFuture.completedFuture(updateCache(info, -1, false, entity, null, selects)); } @@ -1225,6 +1310,10 @@ public abstract class DataSqlSource extends AbstractDataSource implements Functi if (entity == null || node == null || selects == null) return -1; Class clazz = (Class) entity.getClass(); final EntityInfo info = loadEntityInfo(clazz); + String illegalColumn = checkIllegalColumn(info, selects); + if (illegalColumn != null) { + throw new RuntimeException(info.getType() + " cannot found column " + illegalColumn); + } 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) { @@ -1240,6 +1329,10 @@ public abstract class DataSqlSource extends AbstractDataSource implements Functi if (entity == null || node == null || selects == null) return CompletableFuture.completedFuture(-1); Class clazz = (Class) entity.getClass(); final EntityInfo info = loadEntityInfo(clazz); + String illegalColumn = checkIllegalColumn(info, selects); + if (illegalColumn != null) { + return CompletableFuture.failedFuture(new RuntimeException(info.getType() + " cannot found column " + illegalColumn)); + } if (isOnlyCache(info)) { return CompletableFuture.completedFuture(updateCache(info, -1, true, entity, node, selects)); } @@ -1383,7 +1476,7 @@ public abstract class DataSqlSource extends AbstractDataSource implements Functi 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(); + Sheet sheet = querySheetCompose(false, true, false, clazz, null, FLIPPER_ONE, FilterNode.filter(column, id)).join(); T value = sheet.isEmpty() ? null : sheet.list().get(0); if (value != null) c += cache.update(value); } @@ -1499,7 +1592,7 @@ public abstract class DataSqlSource extends AbstractDataSource implements Functi 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); + if (info.isLoggable(logger, Level.FINEST, sql)) logger.finest(entityClass.getSimpleName() + " getNumberResult sql=" + sql); return getNumberResultDB(info, sql, defVal, column); } @@ -1680,7 +1773,7 @@ public abstract class DataSqlSource extends AbstractDataSource implements Functi 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 -> { + return queryListAsync(info.getType(), selects, null, FilterNode.filter(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; @@ -1697,6 +1790,18 @@ public abstract class DataSqlSource extends AbstractDataSource implements Functi }); } + @Override + public List findsList(Class clazz, Stream pks) { + return findsListAsync(clazz, pks).join(); + } + + @Override + public CompletableFuture> findsListAsync(final Class clazz, final Stream pks) { + final EntityInfo info = loadEntityInfo(clazz); + Serializable[] ids = pks.toArray(v -> new Serializable[v]); + return queryListAsync(info.getType(), null, null, FilterNode.filter(info.getPrimarySQLColumn(), FilterExpress.IN, ids)); + } + @Override public T find(Class clazz, final SelectColumn selects, Serializable pk) { final EntityInfo info = loadEntityInfo(clazz); @@ -2016,7 +2121,7 @@ public abstract class DataSqlSource extends AbstractDataSource implements Functi 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)); + List rs = queryList(clazz, FilterNode.filter(primary.field(), ids)); Map map = new LinkedHashMap<>(); if (rs.isEmpty()) return new LinkedHashMap<>(); for (T item : rs) { @@ -2032,7 +2137,7 @@ public abstract class DataSqlSource extends AbstractDataSource implements Functi 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) -> { + return queryListAsync(clazz, FilterNode.filter(primary.field(), pks)).thenApply((List rs) -> { Map map = new LinkedHashMap<>(); if (rs.isEmpty()) return new LinkedHashMap<>(); for (T item : rs) { @@ -2127,4 +2232,5 @@ public abstract class DataSqlSource extends AbstractDataSource implements Functi protected static enum UpdateMode { INSERT, DELETE, UPDATE, CLEAR, DROP, ALTER, OTHER; } + } diff --git a/src/main/java/org/redkale/source/EntityInfo.java b/src/main/java/org/redkale/source/EntityInfo.java index 3f224b1aa..708b4e5a8 100644 --- a/src/main/java/org/redkale/source/EntityInfo.java +++ b/src/main/java/org/redkale/source/EntityInfo.java @@ -82,10 +82,6 @@ public final class EntityInfo { //鍙湁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<>(); @@ -138,6 +134,12 @@ public final class EntityInfo { //鏍规嵁涓婚敭鏇存柊鎵鏈夊彲鏇存柊瀛楁鐨凷QL锛屽惈 $ private final String updateDollarPrepareSQL; + //鏍规嵁涓婚敭鏇存柊鎵鏈夊彲鏇存柊瀛楁鐨凷QL锛屽惈 锛 + private final String[] updateQuestionPrepareCaseSQLs; + + //鏍规嵁涓婚敭鏇存柊鎵鏈夊彲鏇存柊瀛楁鐨凷QL锛屽惈 $ + private final String[] updateDollarPrepareCaseSQLs; + //鏍规嵁涓婚敭鏇存柊鎵鏈夊彲鏇存柊瀛楁鐨凷QL锛屽惈 :name private final String updateNamesPrepareSQL; @@ -174,7 +176,7 @@ public final class EntityInfo { * * @param clazz Entity绫 * @param cacheForbidden 鏄惁绂佺敤EntityCache - * @param conf 閰嶇疆淇℃伅, persistence.xml涓殑property鑺傜偣鍊 + * @param conf 閰嶇疆淇℃伅, source.properties涓殑灞炴ц妭鐐瑰 * @param source DataSource,鍙负null * @param fullloader 鍏ㄩ噺鍔犺浇鍣,鍙负null */ @@ -302,7 +304,6 @@ public final class EntityInfo { } 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<>(); @@ -313,7 +314,6 @@ public final class EntityInfo { List updatecols = new ArrayList<>(); List> updateattrs = new ArrayList<>(); List> ddlList = new ArrayList<>(); - Map> cryptCreatorMap = new HashMap<>(); do { List ddl = new ArrayList<>(); ddlList.add(ddl); @@ -330,16 +330,9 @@ public final class EntityInfo { 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); + attr = Attribute.create(type, cltmp, field); } catch (RuntimeException e) { continue; } @@ -391,7 +384,6 @@ public final class EntityInfo { this.primary = idAttr0; this.aliasmap = aliasmap0; - this.cryptmap = cryptmap0; List ddls = new ArrayList<>(); Collections.reverse(ddlList); //鐖剁被鐨勫瓧娈垫帓鍦ㄥ墠闈 for (List ls : ddlList) { @@ -489,6 +481,39 @@ public final class EntityInfo { 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); + + if (this.tableStrategy == null && this.updateAttributes.length == 1) { //涓嶅垎琛ㄤ笖鍙湁涓や釜瀛楁鐨勮〃鎵嶄娇鐢–ase鏂瑰紡 + String[] dollarPrepareCaseSQLs = new String[51]; //涓婇檺50涓 + String[] questionPrepareCaseSQLs = new String[dollarPrepareCaseSQLs.length]; + String idsqlfield = getPrimarySQLColumn(); + String otherfield = getSQLColumn(null, this.updateAttributes[0].field()); + for (int i = 2; i < dollarPrepareCaseSQLs.length; i++) { + StringBuilder ds = new StringBuilder(); + StringBuilder qs = new StringBuilder(); + ds.append("UPDATE ").append(table).append(" SET ").append(otherfield).append(" = CASE ").append(idsqlfield); + qs.append("UPDATE ").append(table).append(" SET ").append(otherfield).append(" = ( CASE"); + for (int j = 1; j <= i; j++) { + ds.append(" WHEN $").append(j).append(" THEN $").append(j + i); + qs.append(" WHEN ").append(idsqlfield).append(" = ? THEN ?"); + } + ds.append(" ELSE ").append(otherfield).append(" END WHERE ").append(idsqlfield).append(" IN ($1"); + qs.append(" END ) WHERE ").append(idsqlfield).append(" IN (?"); + for (int j = 2; j <= i; j++) { + ds.append(",$").append(j); + qs.append(",?"); + } + ds.append(")"); + qs.append(")"); + dollarPrepareCaseSQLs[i] = ds.toString(); + questionPrepareCaseSQLs[i] = qs.toString(); + } + this.updateDollarPrepareCaseSQLs = dollarPrepareCaseSQLs; + this.updateQuestionPrepareCaseSQLs = questionPrepareCaseSQLs; + } else { + this.updateDollarPrepareCaseSQLs = null; + this.updateQuestionPrepareCaseSQLs = null; + } + } else { this.allQueryPrepareSQL = null; @@ -506,6 +531,9 @@ public final class EntityInfo { this.updateNamesPrepareSQL = null; this.deleteNamesPrepareSQL = null; this.findNamesPrepareSQL = null; + + this.updateDollarPrepareCaseSQLs = null; + this.updateQuestionPrepareCaseSQLs = null; } //----------------cache-------------- Cacheable c = type.getAnnotation(Cacheable.class); @@ -738,6 +766,34 @@ public final class EntityInfo { return updateDollarPrepareSQL.replace("${newtable}", getTable(bean)); } + /** + * 鑾峰彇Entity鐨刄PDATE CASE SQL + * + * @param beans Entity瀵硅薄 + * + * @return String + */ + public String getUpdateQuestionPrepareCaseSQL(T[] beans) { + if (beans == null || beans.length < 2) return null; + if (this.updateQuestionPrepareCaseSQLs == null) return null; + if (this.updateQuestionPrepareCaseSQLs.length <= beans.length) return null; + return this.updateQuestionPrepareCaseSQLs[beans.length]; + } + + /** + * 鑾峰彇Entity鐨刄PDATE CASE SQL + * + * @param beans Entity瀵硅薄 + * + * @return String + */ + public String getUpdateDollarPrepareCaseSQL(T[] beans) { + if (beans == null || beans.length < 2) return null; + if (this.updateDollarPrepareCaseSQLs == null) return null; + if (this.updateDollarPrepareCaseSQLs.length <= beans.length) return null; + return this.updateDollarPrepareCaseSQLs[beans.length]; + } + /** * 鑾峰彇Entity鐨刄PDATE SQL * @@ -989,10 +1045,7 @@ public final class EntityInfo { 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); + return fieldvalue; } /** @@ -1030,11 +1083,8 @@ public final class EntityInfo { * * @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; + public Serializable getSQLValue(Attribute attr, T entity) { + return (Serializable) attr.get(entity); } /** @@ -1048,7 +1098,7 @@ public final class EntityInfo { * @return CharSequence */ public CharSequence formatSQLValue(Attribute attr, T entity, BiFunction sqlFormatter) { - Object val = getSQLValue(attr, entity); + Serializable val = getSQLValue(attr, entity); return sqlFormatter == null ? formatToString(val) : sqlFormatter.apply(this, val); } @@ -1061,10 +1111,7 @@ public final class EntityInfo { * @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 attr.get(entity); } /** @@ -1128,14 +1175,10 @@ public final class EntityInfo { 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); } @@ -1221,7 +1264,7 @@ public final class EntityInfo { && 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.sql.") //閬垮厤寮曠敤import java.sql.* 鍑忓皯妯″潡渚濊禆 && !attr.type().getName().startsWith("java.time."); } @@ -1337,8 +1380,16 @@ public final class EntityInfo { return row.getObject(attr, index, index > 0 ? null : this.getSQLColumn(null, attr.field())); } + @Override + public String toString() { + return getClass().getSimpleName() + "(" + type.getName() + ")@" + Objects.hashCode(this); + } + public static interface DataResultSetRow { + //鍙互涓虹┖ + public EntityInfo getEntityInfo(); + //index浠1寮濮 public Object getObject(int index); diff --git a/src/main/java/org/redkale/source/FilterColumn.java b/src/main/java/org/redkale/source/FilterColumn.java index 69998ef64..9ec08dfd2 100644 --- a/src/main/java/org/redkale/source/FilterColumn.java +++ b/src/main/java/org/redkale/source/FilterColumn.java @@ -31,7 +31,8 @@ public @interface FilterColumn { String name() default ""; /** - * 褰撳瓧娈电被鍨嬫槸Number鏃讹紝 濡傛灉鍊>=least() 鍒欓渶瑕佽繃婊わ紝 鍚﹀垯璺宠繃璇ュ瓧娈 + * 褰撳瓧娈电被鍨嬫槸Number鏃讹紝 濡傛灉鍊>=least() 鍒欓渶瑕佽繃婊わ紝 鍚﹀垯璺宠繃璇ュ瓧娈
+ * 褰撳瓧娈电被鍨嬫槸String鏃讹紝 濡傛灉瀛楃涓.length == 0 涓 least() == 0 鍒欓渶瑕佽繃婊わ紝 鍚﹀垯璺宠繃璇ュ瓧娈 * * @return 鏈灏忓彲杩囨护鍊 */ diff --git a/src/main/java/org/redkale/source/FilterNode.java b/src/main/java/org/redkale/source/FilterNode.java index 1ef9059ab..9a76bc04c 100644 --- a/src/main/java/org/redkale/source/FilterNode.java +++ b/src/main/java/org/redkale/source/FilterNode.java @@ -299,14 +299,17 @@ public class FilterNode { //FilterNode 涓嶈兘瀹炵幇Serializable鎺ュ彛锛 鍚﹀垯 return rs; } + @Deprecated //@deprecated @since 2.7.0 浣跨敤 filter 鏂规硶鏇挎崲 public static FilterNode create(String column, Serializable value) { return filter(column, null, value); } + @Deprecated //@deprecated @since 2.7.0 浣跨敤 filter 鏂规硶鏇挎崲 public static FilterNode create(String column, FilterExpress express, Serializable value) { return filter(column, express, true, value); } + @Deprecated //@deprecated @since 2.7.0 浣跨敤 filter 鏂规硶鏇挎崲 public static FilterNode create(String column, FilterExpress express, boolean itemand, Serializable value) { return new FilterNode(column, express, itemand, value); } @@ -411,8 +414,8 @@ public class FilterNode { //FilterNode 涓嶈兘瀹炵幇Serializable鎺ュ彛锛 鍚﹀垯 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 == 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) { diff --git a/src/main/java/org/redkale/source/FilterNodeBean.java b/src/main/java/org/redkale/source/FilterNodeBean.java index f6c8a3007..e15c4a6d2 100644 --- a/src/main/java/org/redkale/source/FilterNodeBean.java +++ b/src/main/java/org/redkale/source/FilterNodeBean.java @@ -155,14 +155,14 @@ public final class FilterNodeBean implements Comparable 0 && ((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); + node = FilterNode.filter(column, express, itemand, val); } else { node = FilterJoinNode.create(joinClass, joinColumns, column, express, itemand, val); } diff --git a/src/main/java/org/redkale/source/Flipper.java b/src/main/java/org/redkale/source/Flipper.java index cb72a5b03..7a8721104 100644 --- a/src/main/java/org/redkale/source/Flipper.java +++ b/src/main/java/org/redkale/source/Flipper.java @@ -90,7 +90,7 @@ public final class Flipper implements Serializable, Cloneable { @Override public String toString() { - return this.getClass().getSimpleName() + "{offset:" + this.offset + ", limit:" + this.limit + ", sort:" + this.sort + "}"; + return "{offset:" + this.offset + ",limit:" + this.limit + ((sort == null || sort.isEmpty()) ? "" : (",sort:\"" + this.sort.replace('"', '\'') + "\"")) + "}"; } @Override diff --git a/src/main/java/org/redkale/source/PageBean.java b/src/main/java/org/redkale/source/PageBean.java new file mode 100644 index 000000000..ba052d249 --- /dev/null +++ b/src/main/java/org/redkale/source/PageBean.java @@ -0,0 +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; + +import org.redkale.convert.ConvertColumn; +import org.redkale.convert.json.JsonConvert; +import org.redkale.util.Bean; + +/** + * 缈婚〉瀵硅薄涓庤繃婊ゆ潯浠禕ean鐨勭粍鍚堝璞 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @param Bean绫 + * + * @since 2.7.0 + */ +@Bean +public class PageBean { + + @ConvertColumn(index = 1) + protected T bean; + + @ConvertColumn(index = 2) + protected Flipper flipper; + + public PageBean() { + } + + public PageBean(T bean, Flipper flipper) { + this.bean = bean; + this.flipper = flipper; + } + + public PageBean bean(T bean) { + this.bean = bean; + return this; + } + + public PageBean flipper(Flipper flipper) { + this.flipper = flipper; + return this; + } + + public T getBean() { + return bean; + } + + public void setBean(T bean) { + this.bean = bean; + } + + public Flipper getFlipper() { + return flipper; + } + + public void setFlipper(Flipper flipper) { + this.flipper = flipper; + } + + @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 d6670865b..6aee00ea2 100644 --- a/src/main/java/org/redkale/source/SearchColumn.java +++ b/src/main/java/org/redkale/source/SearchColumn.java @@ -57,7 +57,7 @@ public @interface SearchColumn { boolean ignore() default false; /** - * 璁剧疆绱㈠紩鍙傛暟 + * 璁剧疆绱㈠紩鍙傛暟, 鐗规畩鍊"false"琛ㄧず涓嶈绱㈠紩 * * @return String */ @@ -70,6 +70,20 @@ public @interface SearchColumn { */ boolean html() default false; + /** + * 鍐呭鏄惁鏃堕棿绫诲瀷锛屽彧鏈夋暟鎹被鍨嬩负int銆乴ong銆丼tring鎵嶆湁鏁 + * + * @return boolean + */ + boolean date() default false; + + /** + * 鍐呭鏄惁ip绫诲瀷锛屽彧鏈夋暟鎹被鍨嬩负String鎵嶆湁鏁 + * + * @return boolean + */ + boolean ip() default false; + /** * 璁剧疆绱㈠紩鍒嗚瘝鍣 * diff --git a/src/main/java/org/redkale/source/SearchBean.java b/src/main/java/org/redkale/source/SearchQuery.java similarity index 74% rename from src/main/java/org/redkale/source/SearchBean.java rename to src/main/java/org/redkale/source/SearchQuery.java index 6b7301302..48362e96e 100644 --- a/src/main/java/org/redkale/source/SearchBean.java +++ b/src/main/java/org/redkale/source/SearchQuery.java @@ -10,7 +10,7 @@ import org.redkale.convert.*; import org.redkale.convert.json.JsonConvert; /** - * SearchFilterBean鐢ㄤ簬鎼滅储鏉′欢锛 鎵鏈夌殑FilterBean閮藉繀椤诲彲浠ヨ浆鎹㈡垚FilterNode
+ * SearchQuery鐢ㄤ簬鏋勫缓鎼滅储杩囨护鏉′欢
* * 涓嶈鏍囪涓@javax.persistence.Transient 鐨勫瓧娈靛潎瑙嗕负杩囨护鏉′欢
* @@ -19,19 +19,23 @@ import org.redkale.convert.json.JsonConvert; * * @author zhangjx * - * @since 2.4.0 + * @since 2.7.0 */ -@ConvertImpl(SearchBean.SearchSimpleBean.class) -public interface SearchBean extends java.io.Serializable { +@ConvertImpl(SearchQuery.SearchSimpleQuery.class) +public interface SearchQuery extends java.io.Serializable { public static final String SEARCH_FILTER_NAME = "#search"; - public static SearchSimpleBean create() { - return new SearchSimpleBean(); + public static SearchSimpleQuery create() { + return new SearchSimpleQuery(); } - public static SearchSimpleBean create(String keyword, String... fields) { - return new SearchSimpleBean(keyword, fields); + public static SearchSimpleQuery create(String keyword, String... fields) { + return new SearchSimpleQuery(keyword, fields); + } + + public static SearchSimpleHighlight createHighlight() { + return new SearchSimpleHighlight(); } /** @@ -74,15 +78,19 @@ public interface SearchBean extends java.io.Serializable { /** * 楂樹寒鏄剧ず * - * @return SearchHighlightBean + * @return SearchHighlight */ - public SearchHighlightBean highlight(); + public SearchHighlight highlight(); - @ConvertImpl(SearchBean.SearchSimpleHighlightBean.class) - public static interface SearchHighlightBean { + @ConvertImpl(SearchQuery.SearchSimpleHighlight.class) + public static interface SearchHighlight { - public static SearchSimpleHighlightBean create() { - return new SearchSimpleHighlightBean(); + public static SearchSimpleHighlight create() { + return new SearchSimpleHighlight(); + } + + public static SearchSimpleHighlight createTag(String preTag, String postTag) { + return new SearchSimpleHighlight().tag(preTag, postTag); } public String preTag(); @@ -102,7 +110,7 @@ public interface SearchBean extends java.io.Serializable { } } - public static class SearchSimpleBean implements SearchBean { + public static class SearchSimpleQuery implements SearchQuery { @ConvertColumn(index = 1) @FilterColumn(ignore = true) @@ -122,53 +130,53 @@ public interface SearchBean extends java.io.Serializable { @ConvertColumn(index = 5) @FilterColumn(ignore = true) - private SearchHighlightBean highlight; + private SearchHighlight highlight; @ConvertColumn(index = 6) @FilterColumn(ignore = true) private Map extras; - public SearchSimpleBean() { + public SearchSimpleQuery() { } - public SearchSimpleBean(String keyword, String... fields) { + public SearchSimpleQuery(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) { + public SearchSimpleQuery keyword(String keyword) { this.keyword = keyword; return this; } - public SearchSimpleBean analyzer(String analyzer) { + public SearchSimpleQuery analyzer(String analyzer) { this.analyzer = analyzer; return this; } - public SearchSimpleBean fields(String... fields) { + public SearchSimpleQuery 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) { + public SearchSimpleQuery classes(Class[] classes) { this.classes = classes; return this; } - public SearchSimpleBean highlight(SearchHighlightBean highlight) { + public SearchSimpleQuery highlight(SearchHighlight highlight) { this.highlight = highlight; return this; } - public SearchSimpleBean extras(Map map) { + public SearchSimpleQuery extras(Map map) { this.extras = map; return this; } - public SearchSimpleBean extras(String key, Object value) { + public SearchSimpleQuery extras(String key, Object value) { if (this.extras == null) this.extras = new LinkedHashMap<>(); this.extras.put(key, value); return this; @@ -200,7 +208,7 @@ public interface SearchBean extends java.io.Serializable { } @Override - public SearchHighlightBean highlight() { + public SearchHighlight highlight() { return highlight; } @@ -236,11 +244,11 @@ public interface SearchBean extends java.io.Serializable { this.analyzer = analyzer; } - public SearchHighlightBean getHighlight() { + public SearchHighlight getHighlight() { return highlight; } - public void setHighlight(SearchHighlightBean highlight) { + public void setHighlight(SearchHighlight highlight) { this.highlight = highlight; } @@ -259,7 +267,7 @@ public interface SearchBean extends java.io.Serializable { } - public static class SearchSimpleHighlightBean implements SearchHighlightBean { + public static class SearchSimpleHighlight implements SearchHighlight { @ConvertColumn(index = 1) private String preTag; @@ -280,33 +288,33 @@ public interface SearchBean extends java.io.Serializable { @FilterColumn(ignore = true) private Map extras; - public SearchSimpleHighlightBean tag(String preTag, String postTag) { + public SearchSimpleHighlight tag(String preTag, String postTag) { this.preTag = preTag; this.postTag = postTag; return this; } - public SearchSimpleHighlightBean boundaryLocale(String boundaryLocale) { + public SearchSimpleHighlight boundaryLocale(String boundaryLocale) { this.boundaryLocale = boundaryLocale; return this; } - public SearchSimpleHighlightBean fragmentSize(int fragmentSize) { + public SearchSimpleHighlight fragmentSize(int fragmentSize) { this.fragmentSize = fragmentSize; return this; } - public SearchSimpleHighlightBean fragmentCount(int fragmentCount) { + public SearchSimpleHighlight fragmentCount(int fragmentCount) { this.fragmentCount = fragmentCount; return this; } - public SearchSimpleHighlightBean extras(Map map) { + public SearchSimpleHighlight extras(Map map) { this.extras = map; return this; } - public SearchSimpleHighlightBean extras(String key, Object value) { + public SearchSimpleHighlight extras(String key, Object value) { if (this.extras == null) this.extras = new LinkedHashMap<>(); this.extras.put(key, value); return this; diff --git a/src/main/java/org/redkale/source/SearchSource.java b/src/main/java/org/redkale/source/SearchSource.java index f32b7d15e..7a2b1783a 100644 --- a/src/main/java/org/redkale/source/SearchSource.java +++ b/src/main/java/org/redkale/source/SearchSource.java @@ -20,7 +20,19 @@ import java.util.concurrent.CompletableFuture; */ public interface SearchSource extends DataSource { - public int updateMapping(final Class clazz); + //涓嶅瓨鍦ㄥ垎琛ㄦ椂鐢ㄦ鏂规硶 + default int updateMapping(final Class clazz) { + return updateMapping(clazz, null); + } - public CompletableFuture updateMappingAsync(final Class clazz); + //涓嶅瓨鍦ㄥ垎琛ㄦ椂鐢ㄦ鏂规硶 + default CompletableFuture updateMappingAsync(final Class clazz) { + return updateMappingAsync(clazz, null); + } + + //瀛樺湪鍒嗚〃鏃剁敤姝ゆ柟娉 + public int updateMapping(final Class clazz, String table); + + //瀛樺湪鍒嗚〃鏃剁敤姝ゆ柟娉 + public CompletableFuture updateMappingAsync(final Class clazz, String table); } diff --git a/src/main/java/org/redkale/util/AnyValue.java b/src/main/java/org/redkale/util/AnyValue.java index 3394f7d06..22e5036c8 100644 --- a/src/main/java/org/redkale/util/AnyValue.java +++ b/src/main/java/org/redkale/util/AnyValue.java @@ -554,19 +554,224 @@ public abstract class AnyValue { } /** - * 鏂囨湰鍐呭杞崲鎴怉nyValue瀵硅薄 + * Properties鍐呭杞崲鎴怉nyValue瀵硅薄锛 灞傜骇閲囩敤key鐨.鍒嗛殧
+ * key涓寘鍚玔xx]涓攛x涓嶆槸鏁板瓧涓斾笉鏄綅浜庢渶鍚庣殑瑙嗕负name锛屼細鍦ㄥ搴旂殑鑺傜偣瀵硅薄涓姞鍏ame灞炴 * * @param text 鏂囨湰鍐呭 * * @return AnyValue + */ + public static AnyValue loadFromProperties(String text) { + Properties properties = new Properties(); + try { + properties.load(new StringReader(text)); + } catch (IOException e) { + //涓嶄細鍙戠敓 + } + return loadFromProperties(properties); + } + + /** + * Properties鍐呭杞崲鎴怉nyValue瀵硅薄锛 灞傜骇閲囩敤key鐨.鍒嗛殧
+ * key涓寘鍚玔xx]涓攛x涓嶆槸鏁板瓧涓斾笉鏄綅浜庢渶鍚庣殑瑙嗕负name锛屼細鍦ㄥ搴旂殑鑺傜偣瀵硅薄涓姞鍏ame灞炴 + * + * @param text 鏂囨湰鍐呭 + * @param nameName String + * + * @return AnyValue + */ + public static AnyValue loadFromProperties(String text, String nameName) { + Properties properties = new Properties(); + try { + properties.load(new StringReader(text)); + } catch (IOException e) { + //涓嶄細鍙戠敓 + } + return loadFromProperties(properties, nameName); + } + + /** + * Properties鍐呭杞崲鎴怉nyValue瀵硅薄锛 灞傜骇閲囩敤key鐨.鍒嗛殧
+ * key涓寘鍚玔xx]涓攛x涓嶆槸鏁板瓧涓斾笉鏄綅浜庢渶鍚庣殑瑙嗕负name锛屼細鍦ㄥ搴旂殑鑺傜偣瀵硅薄涓姞鍏ame灞炴 + * + * @param in 鍐呭娴 + * + * @return AnyValue * @throws IOException 寮傚父 */ - public static AnyValue loadFromXml(String text) throws IOException { + public static AnyValue loadFromProperties(InputStream in) throws IOException { + Properties properties = new Properties(); + properties.load(in); + return loadFromProperties(properties); + } + + /** + * Properties鍐呭杞崲鎴怉nyValue瀵硅薄锛 灞傜骇閲囩敤key鐨.鍒嗛殧
+ * key涓寘鍚玔xx]涓攛x涓嶆槸鏁板瓧涓斾笉鏄綅浜庢渶鍚庣殑瑙嗕负name锛屼細鍦ㄥ搴旂殑鑺傜偣瀵硅薄涓姞鍏ame灞炴 + * + * @param in 鍐呭娴 + * @param charset 瀛楃缂栫爜 + * + * @return AnyValue + * @throws IOException 寮傚父 + */ + public static AnyValue loadFromProperties(InputStream in, Charset charset) throws IOException { + Properties properties = new Properties(); + properties.load(in); + return loadFromProperties(properties); + } + + /** + * Properties鍐呭杞崲鎴怉nyValue瀵硅薄锛 灞傜骇閲囩敤key鐨.鍒嗛殧
+ * key涓寘鍚玔xx]涓攛x涓嶆槸鏁板瓧涓斾笉鏄綅浜庢渶鍚庣殑瑙嗕负name锛屼細鍦ㄥ搴旂殑鑺傜偣瀵硅薄涓姞鍏ame灞炴 + * + * @param properties Properties + * + * @return AnyValue + */ + public static AnyValue loadFromProperties(Properties properties) { + return loadFromProperties(properties, null); + } + + /** + * Properties鍐呭杞崲鎴怉nyValue瀵硅薄锛 灞傜骇閲囩敤key鐨.鍒嗛殧
+ * key涓寘鍚玔xx]涓攛x涓嶆槸鏁板瓧涓斾笉鏄綅浜庢渶鍚庣殑瑙嗕负name锛屼細鍦ㄥ搴旂殑鑺傜偣瀵硅薄涓姞鍏ameName灞炴 + * + * @param properties Properties + * @param nameName String + * + * @return AnyValue + */ + public static AnyValue loadFromProperties(Properties properties, String nameName) { + if (properties == null) return null; + DefaultAnyValue conf = new DefaultAnyValue(); + Map prefixArray = new TreeMap<>(); //宸插鐞嗙殑鏁扮粍key锛屽 redkale.source[0].xx 瀛榬edkale.source[0] + properties.forEach((key, value) -> { + String[] keys = key.toString().split("\\."); + DefaultAnyValue parent = conf; + if (keys.length > 1) { + for (int i = 0; i < keys.length - 1; i++) { + String item = keys[i]; + int pos = item.indexOf('['); + if (pos < 0) { + DefaultAnyValue child = (DefaultAnyValue) parent.getAnyValue(item); + if (child == null) { + child = new DefaultAnyValue(); + parent.addValue(item, child); + } + parent = child; + } else { //鏁扮粍鎴朚ap缁撴瀯, []涓棿鏄暟瀛楀紑澶寸殑瑙嗕负鏁扮粍锛屽叾浠栬涓簃ap + String itemField = item.substring(0, pos); //[鍓嶉潰涓閮ㄥ垎 + String itemIndex = item.substring(pos + 1, item.indexOf(']')); + if (!itemIndex.isEmpty() && itemIndex.charAt(0) >= '0' && itemIndex.charAt(0) <= '9') { //鏁扮粍 + String prefixKey = ""; + for (int j = 0; j < i; j++) { + prefixKey += keys[j] + "."; + } + DefaultAnyValue array = prefixArray.get(prefixKey + item); + if (array == null) { + final int ii = i; + String findkey = prefixKey + itemField + "["; + Map keymap = new TreeMap<>(); + Map sortmap = new TreeMap<>(); + properties.keySet().stream().filter(x -> x.toString().startsWith(findkey)).forEach(k -> { + String[] ks = k.toString().split("\\."); + String prefixKey2 = ""; + for (int j = 0; j < ii; j++) { + prefixKey2 += ks[j] + "."; + } + prefixKey2 += ks[ii]; + if (!keymap.containsKey(prefixKey2)) { + DefaultAnyValue vv = new DefaultAnyValue(); + keymap.put(prefixKey2, vv); + sortmap.put(Integer.parseInt(ks[ii].substring(ks[ii].indexOf('[') + 1, ks[ii].lastIndexOf(']'))), vv); + } + }); + prefixArray.putAll(keymap); + DefaultAnyValue pv = parent; + sortmap.values().forEach(v -> pv.addValue(itemField, v)); + array = prefixArray.get(prefixKey + item); + } + parent = array; + } else { //Map + DefaultAnyValue field = (DefaultAnyValue) parent.getAnyValue(itemField); + if (field == null) { + field = new DefaultAnyValue(); + parent.addValue(itemField, field); + } + DefaultAnyValue index = (DefaultAnyValue) field.getAnyValue(itemIndex); + if (index == null) { + index = new DefaultAnyValue(); + if (nameName != null) index.setValue(nameName, itemIndex); + field.addValue(itemIndex, index); + } + parent = index; + } + } + } + } + + String lastItem = keys[keys.length - 1]; + int pos = lastItem.indexOf('['); + if (pos < 0) { + parent.addValue(lastItem, value.toString()); + } else { + String itemField = lastItem.substring(0, pos); //[鍓嶉潰涓閮ㄥ垎 + String itemIndex = lastItem.substring(pos + 1, lastItem.indexOf(']')); + if (!itemIndex.isEmpty() && itemIndex.charAt(0) >= '0' && itemIndex.charAt(0) <= '9') { //鏁扮粍 + //parent.addValue(itemField, value.toString()); + String[] tss = parent.getValues(itemField); + if (tss == null || tss.length == 0) { + String prefixKey = ""; + for (int j = 0; j < keys.length - 1; j++) { + prefixKey += keys[j] + "."; + } + final int ii = keys.length - 1; + String findkey = prefixKey + itemField + "["; + Map keymap = new TreeMap<>(); + Map sortmap = new TreeMap<>(); + properties.keySet().stream().filter(x -> x.toString().startsWith(findkey)).forEach(k -> { + String[] ks = k.toString().split("\\."); + String prefixKey2 = ""; + for (int j = 0; j < ii; j++) { + prefixKey2 += ks[j] + "."; + } + prefixKey2 += ks[ii]; + if (!keymap.containsKey(prefixKey2)) { + String vv = properties.getProperty(k.toString()); + keymap.put(prefixKey2, vv); + sortmap.put(Integer.parseInt(ks[ii].substring(ks[ii].indexOf('[') + 1, ks[ii].lastIndexOf(']'))), vv); + } + }); + DefaultAnyValue pv = parent; + sortmap.values().forEach(v -> pv.addValue(itemField, v)); + } + } else { //Map + DefaultAnyValue child = (DefaultAnyValue) parent.getAnyValue(itemField); + if (child == null) { + child = new DefaultAnyValue(); + parent.addValue(itemField, child); + } + child.addValue(itemIndex, value.toString()); + } + } + }); + return conf; + } + + /** + * xml鏂囨湰鍐呭杞崲鎴怉nyValue瀵硅薄 + * + * @param text 鏂囨湰鍐呭 + * + * @return AnyValue + */ + public static AnyValue loadFromXml(String text) { return new XmlReader(text).read(); } /** - * 鍐呭娴佽浆鎹㈡垚AnyValue瀵硅薄 + * xml鍐呭娴佽浆鎹㈡垚AnyValue瀵硅薄 * * @param in 鍐呭娴 * @@ -578,7 +783,7 @@ public abstract class AnyValue { } /** - * 鍐呭娴佽浆鎹㈡垚AnyValue瀵硅薄 + * xml鍐呭娴佽浆鎹㈡垚AnyValue瀵硅薄 * * @param in 鍐呭娴 * @param charset 瀛楃缂栫爜 @@ -591,7 +796,7 @@ public abstract class AnyValue { } /** - * 鍐呭娴佽浆鎹㈡垚AnyValue瀵硅薄 + * xml鍐呭娴佽浆鎹㈡垚AnyValue瀵硅薄 * * @param text 鏂囨湰鍐呭 * @param attrFunc 瀛楁鍥炶皟鍑芥暟 @@ -604,7 +809,7 @@ public abstract class AnyValue { } /** - * 鍐呭娴佽浆鎹㈡垚AnyValue瀵硅薄 + * xml鍐呭娴佽浆鎹㈡垚AnyValue瀵硅薄 * * @param in 鍐呭娴 * @param attrFunc 瀛楁鍥炶皟鍑芥暟 @@ -617,7 +822,7 @@ public abstract class AnyValue { } /** - * 鍐呭娴佽浆鎹㈡垚AnyValue瀵硅薄 + * xml鍐呭娴佽浆鎹㈡垚AnyValue瀵硅薄 * * @param in 鍐呭娴 * @param charset 瀛楃缂栫爜 @@ -639,9 +844,7 @@ public abstract class AnyValue { */ 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); + final String space = " ".repeat(indent); StringBuilder sb = new StringBuilder(); sb.append("{\r\n"); for (Entry en : getStringEntrys()) { @@ -1126,9 +1329,7 @@ public abstract class AnyValue { */ 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); + final String space = " ".repeat(indent); Entry[] anys = conf.getAnyEntrys(); sb.append(space).append('<').append(nodeName); for (Entry en : conf.getStringEntrys()) { diff --git a/src/main/java/org/redkale/util/Attribute.java b/src/main/java/org/redkale/util/Attribute.java index 8c3f9ab82..80af3b764 100644 --- a/src/main/java/org/redkale/util/Attribute.java +++ b/src/main/java/org/redkale/util/Attribute.java @@ -184,14 +184,14 @@ public interface Attribute { * * @param 渚濋檮绫荤殑绫诲瀷 * @param 瀛楁绫诲瀷 - * @param fieldalias 鍒悕 + * @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); + 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); } /** @@ -199,15 +199,15 @@ public interface Attribute { * * @param 渚濋檮绫荤殑绫诲瀷 * @param 瀛楁绫诲瀷 - * @param fieldalias 鍒悕 + * @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); + 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); } /** @@ -216,13 +216,13 @@ public interface Attribute { * @param 渚濋檮绫荤殑绫诲瀷 * @param 瀛楁绫诲瀷 * @param clazz 鎸囧畾渚濋檮鐨勭被 - * @param fieldname 瀛楁鍚嶏紝濡傛灉璇ュ瓧娈典笉瀛樺湪鍒欐姏寮傚父 + * @param fieldName 瀛楁鍚嶏紝濡傛灉璇ュ瓧娈典笉瀛樺湪鍒欐姏寮傚父 * * @return Attribute瀵硅薄 */ - public static Attribute create(Class clazz, final String fieldname) { + 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); + 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); } @@ -234,14 +234,14 @@ public interface Attribute { * @param 渚濋檮绫荤殑绫诲瀷 * @param 瀛楁绫诲瀷 * @param clazz 鎸囧畾渚濋檮鐨勭被 - * @param fieldname 瀛楁鍚嶏紝濡傛灉璇ュ瓧娈典笉瀛樺湪鍒欐姏寮傚父 + * @param fieldName 瀛楁鍚嶏紝濡傛灉璇ュ瓧娈典笉瀛樺湪鍒欐姏寮傚父 * @param attach 闄勫姞瀵硅薄 * * @return Attribute瀵硅薄 */ - public static Attribute create(Class clazz, final String fieldname, Object attach) { + 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); + 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); } @@ -313,13 +313,13 @@ public interface Attribute { * @param 渚濋檮绫荤殑绫诲瀷 * @param 瀛楁绫诲瀷 * @param clazz 鎸囧畾渚濋檮鐨勭被 - * @param fieldalias 瀛楁鍒悕 + * @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); + 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); } /** @@ -328,14 +328,14 @@ public interface Attribute { * @param 渚濋檮绫荤殑绫诲瀷 * @param 瀛楁绫诲瀷 * @param clazz 鎸囧畾渚濋檮鐨勭被 - * @param fieldalias 瀛楁鍒悕 + * @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); + 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); } /** @@ -457,7 +457,8 @@ public interface Attribute { 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") + if ((method.getName().startsWith("get") && method.getName().length() > 3) + || (method.getName().startsWith("is") && method.getName().length() > 2) || Utility.isRecordGetter(clazz, method)) { list.add(create(clazz, method, null)); } @@ -497,14 +498,14 @@ public interface Attribute { * @param 渚濋檮绫荤殑绫诲瀷 * @param 瀛楁绫诲瀷 * @param clazz 鎸囧畾渚濋檮鐨勭被 - * @param fieldalias 瀛楁鍒悕 + * @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); + 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); } /** @@ -513,15 +514,15 @@ public interface Attribute { * @param 渚濋檮绫荤殑绫诲瀷 * @param 瀛楁绫诲瀷 * @param clazz 鎸囧畾渚濋檮鐨勭被 - * @param fieldalias 瀛楁鍒悕 + * @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); + 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); } /** @@ -530,15 +531,15 @@ public interface Attribute { * @param 渚濋檮绫荤殑绫诲瀷 * @param 瀛楁绫诲瀷 * @param clazz 鎸囧畾渚濋檮鐨勭被 - * @param fieldalias 瀛楁鍒悕 + * @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); + 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); } /** @@ -547,7 +548,7 @@ public interface Attribute { * @param 渚濋檮绫荤殑绫诲瀷 * @param 瀛楁绫诲瀷 * @param clazz 鎸囧畾渚濋檮鐨勭被 - * @param fieldalias 瀛楁鍒悕 + * @param fieldAlias 瀛楁鍒悕 * @param field 瀛楁 * @param getter getter鏂规硶 * @param setter setter鏂规硶 @@ -555,8 +556,8 @@ public interface Attribute { * * @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); + 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); } /** @@ -565,13 +566,13 @@ public interface Attribute { * @param 渚濋檮绫荤殑绫诲瀷 * @param 瀛楁绫诲瀷 * @param clazz 鎸囧畾渚濋檮鐨勭被 - * @param fieldalias 瀛楁鍒悕 - * @param fieldtype 瀛楁鐨勭被 + * @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); + 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); } /** @@ -580,24 +581,24 @@ public interface Attribute { * @param 渚濋檮绫荤殑绫诲瀷 * @param 瀛楁绫诲瀷 * @param clazz 鎸囧畾渚濋檮鐨勭被 - * @param fieldalias 瀛楁鍒悕 - * @param fieldtype 瀛楁鐨勭被 + * @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); + 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. + * 鏍规嵁Class銆佸瓧娈靛埆鍚嶃佸瓧娈电被鍨嬨丗ield銆乬etter鍜宻etter鏂规硶鐢熸垚 Attribute 瀵硅薄銆 fieldAlias/fieldType銆丗ield銆乼getter銆乻etter涓嶈兘鍚屾椂涓簄ull. * * @param 渚濋檮绫荤殑绫诲瀷 * @param 瀛楁绫诲瀷 * @param clazz 鎸囧畾渚濋檮鐨勭被 - * @param fieldalias 瀛楁鍒悕 - * @param fieldtype 瀛楁绫诲瀷 + * @param fieldAlias 瀛楁鍒悕 + * @param fieldType 瀛楁绫诲瀷 * @param field 瀛楁 * @param getter getter鏂规硶 * @param setter setter鏂规硶 @@ -605,18 +606,18 @@ public interface Attribute { * @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); + 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. + * 鏍规嵁Class銆佸瓧娈靛埆鍚嶃佸瓧娈电被鍨嬨丗ield銆乬etter鍜宻etter鏂规硶鐢熸垚 Attribute 瀵硅薄銆 fieldAlias/fieldType銆丗ield銆乼getter銆乻etter涓嶈兘鍚屾椂涓簄ull. * * @param 渚濋檮绫荤殑绫诲瀷 * @param 瀛楁绫诲瀷 * @param clazz 鎸囧畾渚濋檮鐨勭被 - * @param fieldalias 瀛楁鍒悕 - * @param fieldtype 瀛楁绫诲瀷 + * @param fieldAlias 瀛楁鍒悕 + * @param fieldType 瀛楁绫诲瀷 * @param field 瀛楁 * @param getter getter鏂规硶 * @param setter setter鏂规硶 @@ -625,19 +626,19 @@ public interface Attribute { * @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); + 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. + * 鏍规嵁Class銆佸瓧娈靛埆鍚嶃佸瓧娈电被鍨嬨丗ield銆乬etter鍜宻etter鏂规硶鐢熸垚 Attribute 瀵硅薄銆 fieldAlias/fieldType銆丗ield銆乼getter銆乻etter涓嶈兘鍚屾椂涓簄ull. * * @param 渚濋檮绫荤殑绫诲瀷 * @param 瀛楁绫诲瀷 * @param subclass 鎸囧畾渚濋檮鐨勫瓙绫 * @param clazz 鎸囧畾渚濋檮鐨勭被 - * @param fieldalias 瀛楁鍒悕 - * @param fieldtype 瀛楁绫诲瀷 + * @param fieldAlias 瀛楁鍒悕 + * @param fieldType 瀛楁绫诲瀷 * @param field 瀛楁 * @param getter getter鏂规硶 * @param setter setter鏂规硶 @@ -646,9 +647,9 @@ public interface Attribute { * @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) { + 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; + 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(); @@ -677,11 +678,11 @@ public interface Attribute { 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) { + String fieldkey = fieldAlias; + if (fieldAlias == null) { if (field != null) { - fieldalias = field.getName(); - fieldkey = fieldalias; + fieldAlias = field.getName(); + fieldkey = fieldAlias; } else { String s = null; if (getter != null) { @@ -696,26 +697,26 @@ public interface Attribute { if (d.length < 2 || Character.isLowerCase(d[1])) { d[0] = Character.toLowerCase(d[0]); } - fieldalias = new String(d); - fieldkey = fieldalias; + fieldAlias = new String(d); + fieldkey = fieldAlias; } } } - if (getter != null) { //闃叉fieldname/getter/setter鍚嶅瓧鐩稿悓,鎵浠ュ姞涓1/2/3 + if (getter != null) { //闃叉fieldName/getter/setter鍚嶅瓧鐩稿悓,鎵浠ュ姞涓1/2/3 if (setter == null) { - fieldkey = (fieldalias == null ? "" : ("0_" + fieldalias + "_")) + "1_" + getter.getName(); + fieldkey = (fieldAlias == null ? "" : ("0_" + fieldAlias + "_")) + "1_" + getter.getName(); } else { - fieldkey = (fieldalias == null ? "" : ("0_" + fieldalias + "_")) + "3_" + getter.getName() + "_" + setter.getName(); + fieldkey = (fieldAlias == null ? "" : ("0_" + fieldAlias + "_")) + "3_" + getter.getName() + "_" + setter.getName(); } } else if (setter != null) { - fieldkey = (fieldalias == null ? "" : ("0_" + fieldalias + "_")) + "2_" + setter.getName(); + fieldkey = (fieldAlias == null ? "" : ("0_" + fieldAlias + "_")) + "2_" + setter.getName(); } - if (fieldalias == null && fieldtype == null && tgetter == null && tsetter == null && tfield == null) { + 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; + final String fieldName = fieldAlias; + Class column = fieldType; + java.lang.reflect.Type generictype = fieldType; if (tfield != null) { // public tfield column = tfield.getType(); generictype = tfield.getGenericType(); @@ -725,7 +726,7 @@ public interface Attribute { } else if (tsetter != null) { column = tsetter.getParameterTypes()[0]; generictype = tsetter.getGenericParameterTypes()[0]; - } else if (fieldtype == null) { + } 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"); @@ -748,7 +749,7 @@ public interface Attribute { newsubname.append('_'); } } - String tostr = "Dyn" + Attribute.class.getSimpleName() + "_" + fieldname + "_" + column.getSimpleName(); + String tostr = "Dyn" + Attribute.class.getSimpleName() + "_" + fieldName + "_" + column.getSimpleName(); if (fieldkey.contains("1_")) { tostr += "_getter"; } else if (fieldkey.contains("2_")) { @@ -816,7 +817,7 @@ public interface Attribute { { //field 鏂规硶 mv = cw.visitMethod(ACC_PUBLIC, "field", "()Ljava/lang/String;", null, null); - mv.visitLdcInsn(fieldname); + mv.visitLdcInsn(fieldName); mv.visitInsn(ARETURN); mv.visitMaxs(1, 1); mv.visitEnd(); @@ -998,67 +999,67 @@ public interface Attribute { } /** - * 鏍规嵁Class銆佸瓧娈靛悕銆佸瓧娈电被鍨嬨乬etter鍜宻etter鏂规硶鐢熸垚 Attribute 瀵硅薄銆 clazz銆乫ieldname銆乫ieldtype閮戒笉鑳戒负null + * 鏍规嵁Class銆佸瓧娈靛悕銆佸瓧娈电被鍨嬨乬etter鍜宻etter鏂规硶鐢熸垚 Attribute 瀵硅薄銆 clazz銆乫ieldName銆乫ieldType閮戒笉鑳戒负null * * @param 渚濋檮绫荤殑绫诲瀷 * @param 瀛楁绫诲瀷 * @param clazz 鎸囧畾渚濋檮鐨勭被 - * @param fieldname 瀛楁鍚 - * @param fieldtype 瀛楁绫诲瀷 + * @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); + 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 + * 鏍规嵁Class銆佸瓧娈靛悕銆佸瓧娈电被鍨嬨乬etter鍜宻etter鏂规硶鐢熸垚 Attribute 瀵硅薄銆 clazz銆乫ieldName銆乫ieldType閮戒笉鑳戒负null * * @param 渚濋檮绫荤殑绫诲瀷 * @param 瀛楁绫诲瀷 * @param clazz 鎸囧畾渚濋檮鐨勭被 - * @param fieldname 瀛楁鍚 - * @param fieldtype 瀛楁绫诲瀷 + * @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); + 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 + * 鏍规嵁Class銆佸瓧娈靛悕銆佸瓧娈电被鍨嬨乬etter鍜宻etter鏂规硶鐢熸垚 Attribute 瀵硅薄銆 clazz銆乫ieldName銆乫ieldType閮戒笉鑳戒负null * * @param 渚濋檮绫荤殑绫诲瀷 * @param 瀛楁绫诲瀷 * @param clazz 鎸囧畾渚濋檮鐨勭被 - * @param fieldname 瀛楁鍚 - * @param fieldtype 瀛楁绫诲瀷 + * @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, + 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); + return create(clazz, fieldName, fieldType, fieldGenericType, getter, setter, null); } /** - * 鏍规嵁Class銆佸瓧娈靛悕銆佸瓧娈电被鍨嬨乬etter鍜宻etter鏂规硶鐢熸垚 Attribute 瀵硅薄銆 clazz銆乫ieldname銆乫ieldtype閮戒笉鑳戒负null + * 鏍规嵁Class銆佸瓧娈靛悕銆佸瓧娈电被鍨嬨乬etter鍜宻etter鏂规硶鐢熸垚 Attribute 瀵硅薄銆 clazz銆乫ieldName銆乫ieldType閮戒笉鑳戒负null * * @param 渚濋檮绫荤殑绫诲瀷 * @param 瀛楁绫诲瀷 * @param clazz 鎸囧畾渚濋檮鐨勭被 - * @param fieldname 瀛楁鍚 - * @param fieldtype 瀛楁绫诲瀷 + * @param fieldName 瀛楁鍚 + * @param fieldType 瀛楁绫诲瀷 * @param fieldGenericType 瀛楁娉涘瀷 * @param getter getter鏂规硶 * @param setter setter鏂规硶 @@ -1066,19 +1067,19 @@ public interface Attribute { * * @return Attribute瀵硅薄 */ - public static Attribute create(final Class clazz, final String fieldname, final Class fieldtype, + 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(); + 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; + return fieldType; } @Override @@ -1098,7 +1099,7 @@ public interface Attribute { @Override public String field() { - return fieldname; + return fieldName; } @Override diff --git a/src/main/java/org/redkale/util/Command.java b/src/main/java/org/redkale/util/Command.java index 80397eb27..2e06f85ae 100644 --- a/src/main/java/org/redkale/util/Command.java +++ b/src/main/java/org/redkale/util/Command.java @@ -10,7 +10,7 @@ import static java.lang.annotation.ElementType.*; import static java.lang.annotation.RetentionPolicy.RUNTIME; /** - * 鎺ユ敹鍛戒护鐨勬爣璁帮紝 鍙兘鏍囪鍦ㄦ湰鍦版ā寮忎笅Service閲屽弬鏁颁负String涓旇繑鍥炵被鍨嬩负void鐨刾ublic鏂规硶涓 + * 鎺ユ敹鍛戒护鐨勬爣璁帮紝 鍙兘鏍囪鍦ㄦ湰鍦版ā寮忎笅Service閲屽弬鏁颁负(String)鎴(String, String[])鐨刾ublic鏂规硶涓 * *

* 璇︽儏瑙: https://redkale.org @@ -25,4 +25,26 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME; @Retention(RUNTIME) public @interface Command { + /** + * 鍛戒护鍙凤紝娌℃湁鎸囧畾鍊煎垯鎺ユ敹鎵鏈夌殑鍛戒护 + * + * @return String + */ + String value() default ""; + + /** + * 鍙傛暟甯姪璇存槑锛屽湪value涓嶄负绌哄懡浠edkale --help鏃舵樉绀 + * + * @return String + * + * @since 2.7.0 + */ + String description() default ""; + + /** + * 鎻忚堪 + * + * @return String + */ + String comment() default ""; } diff --git a/src/main/java/org/redkale/util/OneOrList.java b/src/main/java/org/redkale/util/OneOrList.java new file mode 100644 index 000000000..e47c4b1f1 --- /dev/null +++ b/src/main/java/org/redkale/util/OneOrList.java @@ -0,0 +1,151 @@ +/* + */ +package org.redkale.util; + +import java.lang.reflect.*; +import java.math.BigInteger; +import java.util.List; +import org.redkale.convert.*; +import org.redkale.convert.json.*; + +/** + * 鍗曚釜瀵硅薄鎴栧璞℃暟缁勭殑鍚堝苟绫 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @since 2.7.0 + * + * @param 娉涘瀷 + */ +public class OneOrList implements java.io.Serializable { + + public static final Type TYPE_OL_LONG = new TypeToken>() { + }.getType(); + + public static final Type TYPE_OL_STRING = new TypeToken>() { + }.getType(); + + public static final Type TYPE_OL_INTEGER = new TypeToken>() { + }.getType(); + + public static final Type TYPE_OL_BIGINTEGER = new TypeToken>() { + }.getType(); + + @ConvertColumn(index = 1) + protected T one; + + @ConvertColumn(index = 2) + protected List list; + + public OneOrList() { + } + + public OneOrList(T one) { + this.one = one; + } + + public OneOrList(List list) { + this.list = list; + } + + //搴忓垪鍖 + protected static Encodeable createEncoder(final org.redkale.convert.json.JsonFactory factory, final Type type) { + Type itemType = parseItemType(type); + if (itemType == null) return null; + Encodeable oneEncoder = factory.loadEncoder(itemType); + Encodeable listEncoder = factory.loadEncoder(TypeToken.createParameterizedType(null, List.class, itemType)); + return new Encodeable() { + @Override + public void convertTo(JsonWriter out, OneOrList value) { + if (value == null) { + out.writeNull(); + } else if (value.isTypeOne()) { + oneEncoder.convertTo(out, value.getOne()); + } else { + listEncoder.convertTo(out, value.getList()); + } + } + + @Override + public Type getType() { + return type; + } + + }; + } + + //鍙嶅簭鍒楀寲 + protected static Decodeable createDecoder(final org.redkale.convert.json.JsonFactory factory, final Type type) { + Type itemType = parseItemType(type); + if (itemType == null) return null; + Creator creator = Creator.create(type instanceof Class ? (Class) type : (Class) ((ParameterizedType) type).getRawType()); + Decodeable oneDecoder = factory.loadDecoder(itemType); + Decodeable listDecoder = factory.loadDecoder(TypeToken.createParameterizedType(null, List.class, itemType)); + return new Decodeable() { + @Override + public OneOrList convertFrom(JsonReader in) { + if (in.isNextArray()) { + List list = (List) listDecoder.convertFrom(in); + OneOrList rs = creator.create(); + rs.setList(list); + return rs; + } else { + Object one = oneDecoder.convertFrom(in); + OneOrList rs = creator.create(); + rs.setOne(one); + return rs; + } + } + + @Override + public Type getType() { + return type; + } + }; + } + + protected static Type parseItemType(Type type) { + if (type instanceof ParameterizedType) { + ParameterizedType pt = (ParameterizedType) type; + if (pt.getRawType() != OneOrList.class) return null; + return pt.getActualTypeArguments()[0]; + } else if (type instanceof Class) { + Class clz = (Class) type; + while (clz.getSuperclass() != OneOrList.class) { + clz = clz.getSuperclass(); + if (clz == Object.class) return null; + } + return ((ParameterizedType) clz.getGenericSuperclass()).getActualTypeArguments()[0]; + } else { + return null; + } + } + + @ConvertDisabled + public boolean isTypeOne() { + return list == null; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(isTypeOne() ? this.one : this.list); + } + + public T getOne() { + return one; + } + + public void setOne(T one) { + this.one = one; + } + + public List getList() { + return list; + } + + public void setList(List list) { + this.list = list; + } +} diff --git a/src/main/java/org/redkale/util/Redkale.java b/src/main/java/org/redkale/util/Redkale.java index d90ae4998..79f8c4d38 100644 --- a/src/main/java/org/redkale/util/Redkale.java +++ b/src/main/java/org/redkale/util/Redkale.java @@ -24,7 +24,7 @@ public final class Redkale { } public static String getDotedVersion() { - return "2.6.0"; + return "2.7.0"; } public static int getMajorVersion() { @@ -32,6 +32,6 @@ public final class Redkale { } public static int getMinorVersion() { - return 6; + return 7; } } diff --git a/src/main/java/org/redkale/util/RedkaleClassLoader.java b/src/main/java/org/redkale/util/RedkaleClassLoader.java index 84b21d79e..ae5a3a215 100644 --- a/src/main/java/org/redkale/util/RedkaleClassLoader.java +++ b/src/main/java/org/redkale/util/RedkaleClassLoader.java @@ -74,6 +74,7 @@ public class RedkaleClassLoader extends URLClassLoader { } public static URI getConfResourceAsURI(String confURI, String file) { + if (file.startsWith("http:") || file.startsWith("https:") || file.startsWith("ftp:")) return URI.create(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()) { diff --git a/src/main/java/org/redkale/util/Reproduce.java b/src/main/java/org/redkale/util/Reproduce.java index cb8da999c..1ef81d079 100644 --- a/src/main/java/org/redkale/util/Reproduce.java +++ b/src/main/java/org/redkale/util/Reproduce.java @@ -122,6 +122,7 @@ public interface Reproduce extends BiFunction { 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.isEmpty()) continue; if (sfname.length() < 2 || Character.isLowerCase(sfname.charAt(1))) { char[] cs = sfname.toCharArray(); cs[0] = Character.toLowerCase(cs[0]); diff --git a/src/main/java/org/redkale/util/ResourceInjectLoader.java b/src/main/java/org/redkale/util/ResourceAnnotationProvider.java similarity index 66% rename from src/main/java/org/redkale/util/ResourceInjectLoader.java rename to src/main/java/org/redkale/util/ResourceAnnotationProvider.java index 26cd4ab54..ef7fb2e17 100644 --- a/src/main/java/org/redkale/util/ResourceInjectLoader.java +++ b/src/main/java/org/redkale/util/ResourceAnnotationProvider.java @@ -17,9 +17,9 @@ import java.lang.reflect.Field; * @author zhangjx * @param Annotation */ -public interface ResourceInjectLoader { +public interface ResourceAnnotationProvider { - public void load(ResourceFactory factory, Object src, T annotation, Field field, Object attachment); + public void load(ResourceFactory factory, String srcResourceName, Object srcObj, T annotation, Field field, Object attachment); public Class annotationType(); } diff --git a/src/main/java/org/redkale/util/ResourceFactory.java b/src/main/java/org/redkale/util/ResourceFactory.java index e4266331e..4430b87f7 100644 --- a/src/main/java/org/redkale/util/ResourceFactory.java +++ b/src/main/java/org/redkale/util/ResourceFactory.java @@ -42,22 +42,22 @@ public final class ResourceFactory { private final List> chidren = new CopyOnWriteArrayList<>(); - private final ConcurrentHashMap injectLoaderMap = new ConcurrentHashMap(); + private final ConcurrentHashMap resAnnotationProviderMap = new ConcurrentHashMap(); - private final ConcurrentHashMap resLoaderMap = new ConcurrentHashMap(); + private final ConcurrentHashMap resTypeLoaderMap = 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(); + ServiceLoader loaders = ServiceLoader.load(ResourceAnnotationProvider.class); + RedkaleClassLoader.putServiceLoader(ResourceAnnotationProvider.class); + Iterator it = loaders.iterator(); while (it.hasNext()) { - ResourceInjectLoader ril = it.next(); + ResourceAnnotationProvider ril = it.next(); RedkaleClassLoader.putReflectionPublicConstructors(ril.getClass(), ril.getClass().getName()); - this.injectLoaderMap.put(ril.annotationType(), ril); + this.resAnnotationProviderMap.put(ril.annotationType(), ril); } } } @@ -109,7 +109,7 @@ public final class ResourceFactory { *

      * name瑙勫垯:
      *    1: "$"鏈夌壒娈婂惈涔, 琛ㄧず璧勬簮鏈韩锛"$"涓嶈兘鍗曠嫭浣跨敤
-     *    2: 鍙兘鏄瓧姣嶃佹暟瀛椼(鐭í)-銆(涓嬪垝绾)_銆佺偣(.)鐨勭粍鍚
+     *    2: 鍙兘鏄瓧姣嶃佹暟瀛椼(鐭í)-銆(涓嬪垝绾)_銆佺偣(.)銆佸皬鎷彿銆佷腑鎷彿鐨勭粍鍚
      * 
* * @param name String @@ -120,6 +120,12 @@ public final class ResourceFactory { } } + public static Class getResourceType(Type type) { + Class clazz = TypeToken.typeToClass(type); + ResourceType rt = clazz.getAnnotation(ResourceType.class); + return rt == null ? clazz : rt.value(); + } + /** * 灏嗗璞℃寚瀹氱被鍨嬩笖name=""娉ㄥ叆鍒拌祫婧愭睜涓紝骞跺悓姝ュ凡琚敞鍏ョ殑璧勬簮 * @@ -412,6 +418,10 @@ public final class ResourceFactory { */ public
A register(final boolean autoSync, final String name, final Type clazz, final A rs) { checkResourceName(name); + Class clz = TypeToken.typeToClass(clazz); + if (clz != null && !clz.isPrimitive() && rs != null && !clz.isAssignableFrom(rs.getClass())) { + throw new RuntimeException(clz + "not isAssignableFrom (" + rs + ") class " + rs.getClass()); + } ConcurrentHashMap map = this.store.get(clazz); if (map == null) { synchronized (clazz) { @@ -424,9 +434,9 @@ public final class ResourceFactory { } ResourceEntry re = map.get(name); if (re == null) { - map.put(name, new ResourceEntry(rs)); + map.put(name, new ResourceEntry(name, rs)); } else { - map.put(name, new ResourceEntry(rs, name, re.elements, autoSync)); + map.put(name, new ResourceEntry(name, rs, re.elements, autoSync)); } return re == null ? null : (A) re.value; } @@ -543,41 +553,61 @@ public final class ResourceFactory { return null; } - public boolean inject(final Object src) { - return inject(src, null); + public boolean inject(final Object srcObj) { + return inject(srcObj, null); } - public boolean inject(final Object src, final T attachment) { - return inject(src, attachment, null); + public boolean inject(final Object srcObj, final T attachment) { + return inject(srcObj, attachment, null); } - public boolean inject(final Object src, final BiConsumer consumer) { - return inject(src, null, consumer); + public boolean inject(final Object srcObj, final BiConsumer consumer) { + return inject(srcObj, null, consumer); } - public boolean inject(final Object src, final T attachment, final BiConsumer consumer) { - return inject(src, attachment, consumer, new ArrayList()); + public boolean inject(final Object srcObj, final T attachment, final BiConsumer consumer) { + return inject(null, srcObj, attachment, consumer, new ArrayList()); + } + + public boolean inject(final String srcResourceName, final Object srcObj) { + return inject(srcResourceName, srcObj, null); + } + + public boolean inject(final String srcResourceName, final Object srcObj, final T attachment) { + return inject(srcResourceName, srcObj, attachment, null); + } + + public boolean inject(final String srcResourceName, final Object srcObj, final BiConsumer consumer) { + return inject(srcResourceName, srcObj, null, consumer); + } + + public boolean inject(final String srcResourceName, final Object srcObj, final T attachment, final BiConsumer consumer) { + return inject(srcResourceName, srcObj, attachment, consumer, new ArrayList()); } public static String formatResourceName(String name) { + return formatResourceName(null, name); + } + + public static String formatResourceName(String parent, String name) { if (name == null) return null; int pos = name.indexOf("{system.property."); - if (pos < 0) return name; + if (pos < 0) return (name.contains(RESOURCE_PARENT_NAME) && parent != null) ? name.replace(RESOURCE_PARENT_NAME, parent) : name; String prefix = name.substring(0, pos); String subname = name.substring(pos + "{system.property.".length()); pos = subname.lastIndexOf('}'); - if (pos < 0) return name; + if (pos < 0) return (name.contains(RESOURCE_PARENT_NAME) && parent != null) ? name.replace(RESOURCE_PARENT_NAME, parent) : name; String postfix = subname.substring(pos + 1); String property = subname.substring(0, pos); - return formatResourceName(prefix + System.getProperty(property, "") + postfix); + return formatResourceName(parent, 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; + private boolean inject(String srcResourceName, final Object srcObj, final T attachment, final BiConsumer consumer, final List list) { + if (srcObj == null) return false; try { - list.add(src); - Class clazz = src.getClass(); - final boolean diyloaderflag = !parentRoot().injectLoaderMap.isEmpty(); + list.add(srcObj); + Class clazz = srcObj.getClass(); + final boolean diyloaderflag = !parentRoot().resAnnotationProviderMap.isEmpty(); do { if (java.lang.Enum.class.isAssignableFrom(clazz)) break; final String cname = clazz.getName(); @@ -596,7 +626,7 @@ public final class ResourceFactory { if (ConvertFactory.class.isAssignableFrom(classtype)) continue; if (ResourceFactory.class.isAssignableFrom(classtype)) continue; boolean flag = true; //鏄惁娌℃湁閲嶅 - Object ns = field.get(src); + Object ns = field.get(srcObj); for (Object o : list) { if (o == ns) { flag = false; @@ -604,10 +634,10 @@ public final class ResourceFactory { } } if (flag && diyloaderflag) { - parentRoot().injectLoaderMap.values().stream().forEach(iloader -> { + parentRoot().resAnnotationProviderMap.values().stream().forEach(iloader -> { Annotation ann = field.getAnnotation(iloader.annotationType()); if (ann == null) return; - iloader.load(this, src, ann, field, attachment); + iloader.load(this, srcResourceName, srcObj, ann, field, attachment); }); } if (ns == null) continue; @@ -615,30 +645,31 @@ public final class ResourceFactory { 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); + if (flag) this.inject(null, 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); + ? TypeToken.getGenericType(field.getGenericType(), srcObj.getClass()) : field.getGenericType(); + if (consumer != null) consumer.accept(srcObj, 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()); + Resource res = srcObj.getClass().getAnnotation(Resource.class); + String presname = res == null ? srcResourceName : res.name(); + if (presname == null) { + if (srcObj instanceof Resourcable) { + tname = tname.replace(RESOURCE_PARENT_NAME, ((Resourcable) srcObj).resourceName()); } else { - logger.log(Level.SEVERE, src.getClass().getName() + " not found @Resource on Class or not implements Resourcable"); + logger.log(Level.SEVERE, srcObj.getClass().getName() + " not found @Resource on Class or not implements Resourcable"); } } else { - tname = tname.replace(RESOURCE_PARENT_NAME, res.name()); + tname = tname.replace(RESOURCE_PARENT_NAME, presname); } } boolean autoregnull = true; - final String rcname = formatResourceName(tname); + final String rcname = formatResourceName(srcResourceName, tname); Object rs; if (rcname.startsWith("system.property.")) { rs = System.getProperty(rcname.substring("system.property.".length())); @@ -652,9 +683,9 @@ public final class ResourceFactory { } } if (re == null) { - ResourceLoader it = findLoader(genctype, field); + ResourceTypeLoader it = findTypeLoader(genctype, field); if (it != null) { - it.load(this, src, rcname, field, attachment); + it.load(this, srcResourceName, srcObj, rcname, field, attachment); autoregnull = it.autoNone(); re = findEntry(rcname, genctype); } @@ -669,9 +700,9 @@ public final class ResourceFactory { } } if (re == null) { - ResourceLoader it = findLoader(classtype, field); + ResourceTypeLoader it = findTypeLoader(classtype, field); if (it != null) { - it.load(this, src, rcname, field, attachment); + it.load(this, srcResourceName, srcObj, rcname, field, attachment); autoregnull = it.autoNone(); re = findEntry(rcname, classtype); } @@ -682,7 +713,7 @@ public final class ResourceFactory { re = findEntry(rcname, genctype); } if (re == null) continue; - re.elements.add(new ResourceElement<>(src, field)); + re.elements.add(new ResourceElement<>(srcObj, field)); rs = re.value; } if (rs != null && !rs.getClass().isPrimitive() && classtype.isPrimitive()) { @@ -702,68 +733,78 @@ public final class ResourceFactory { rs = Double.parseDouble(rs.toString()); } } - if (rs != null) field.set(src, rs); + if (rs != null) field.set(srcObj, rs); } } while ((clazz = clazz.getSuperclass()) != Object.class); return true; } catch (Exception ex) { - logger.log(Level.SEVERE, "inject " + src + " error", ex); + logger.log(Level.SEVERE, "inject " + srcObj + " error", ex); return false; } } - public void register(final ResourceInjectLoader loader) { + public void register(final ResourceAnnotationProvider loader) { if (loader == null) return; - parentRoot().injectLoaderMap.put(loader.annotationType(), loader); + parentRoot().resAnnotationProviderMap.put(loader.annotationType(), loader); } - public void register(final ResourceLoader rs, final Type... clazzs) { + public void register(final ResourceTypeLoader rs, final Type... clazzs) { if (clazzs == null || rs == null) return; for (Type clazz : clazzs) { - resLoaderMap.put(clazz, rs); + resTypeLoaderMap.put(clazz, rs); } } + public ResourceTypeLoader findResourceTypeLoader(Type clazz) { + ResourceTypeLoader it = this.resTypeLoaderMap.get(clazz); + if (it != null) return it; + return parent == null ? null : parent.findResourceTypeLoader(clazz); + } + 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()); + private ResourceTypeLoader findMatchTypeLoader(Type ft, Field field) { + ResourceTypeLoader it = this.resTypeLoaderMap.get(ft); + if (it == null && field != null) it = this.resTypeLoaderMap.get(field.getType()); if (it != null) return it; - return parent == null ? null : parent.findMatchLoader(ft, field); + return parent == null ? null : parent.findMatchTypeLoader(ft, field); } - private ResourceLoader findRegxLoader(Type ft, Field field) { + private ResourceTypeLoader findRegxTypeLoader(Type ft, Field field) { if (field == null) return null; Class c = field.getType(); - for (Map.Entry en : this.resLoaderMap.entrySet()) { + for (Map.Entry en : this.resTypeLoaderMap.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); + return parent == null ? null : parent.findRegxTypeLoader(ft, field); } - public ResourceLoader findLoader(Type ft, Field field) { - ResourceLoader it = this.findMatchLoader(ft, field); - return it == null ? findRegxLoader(ft, field) : it; + public ResourceTypeLoader findTypeLoader(Type ft, Field field) { + ResourceTypeLoader it = this.findMatchTypeLoader(ft, field); + return it == null ? findRegxTypeLoader(ft, field) : it; } private static class ResourceEntry { + public final String name; + public final T value; public final List elements; - public ResourceEntry(T value) { + public ResourceEntry(final String name, T value) { + this.name = name; this.value = value; this.elements = new CopyOnWriteArrayList<>(); } - public ResourceEntry(T value, final String name, final List elements, boolean sync) { + public ResourceEntry(final String name, T value, final List elements, boolean sync) { + this.name = name; this.value = value; this.elements = elements == null ? new CopyOnWriteArrayList<>() : elements; if (sync && elements != null && !elements.isEmpty()) { @@ -863,15 +904,48 @@ public final class ResourceFactory { } } - @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; - } - } - +// public static class SimpleResourceTypeLoader implements ResourceTypeLoader { +// +// protected Class type; +// +// protected Creator creator; +// +// protected ResourceFactory factory; +// +// public SimpleResourceTypeLoader(Class type) { +// this(null, type, Creator.create(type)); +// } +// +// public SimpleResourceTypeLoader(Class type, Creator creator) { +// this(null, type, Creator.create(type)); +// } +// +// public SimpleResourceTypeLoader(ResourceFactory factory, Class type) { +// this(factory, type, Creator.create(type)); +// } +// +// public SimpleResourceTypeLoader(ResourceFactory factory, Class type, Creator creator) { +// this.factory = factory; +// this.type = type; +// this.creator = creator == null ? Creator.create(type) : creator; +// } +// +// @Override +// public void load(ResourceFactory resFactory, String srcResourceName, Object srcObj, String resourceName, Field field, Object attachment) { +// try { +// if (field.getAnnotation(Resource.class) == null) return; +// Object bean = creator.create(); +// field.set(srcObj, bean); +// ResourceFactory rf = factory == null ? resFactory : factory; +// ResourceType rtype = bean.getClass().getAnnotation(ResourceType.class); +// Class resType = rtype == null ? type : rtype.value(); +// rf.register(resourceName, resType, bean); +// resFactory.inject(resourceName, bean, srcObj); +// } catch (RuntimeException ex) { +// throw ex; +// } catch (Exception e) { +// throw new RuntimeException(e); +// } +// } +// } } diff --git a/src/main/java/org/redkale/util/ResourceTypeLoader.java b/src/main/java/org/redkale/util/ResourceTypeLoader.java new file mode 100644 index 000000000..be1133c1e --- /dev/null +++ b/src/main/java/org/redkale/util/ResourceTypeLoader.java @@ -0,0 +1,23 @@ +/* + */ +package org.redkale.util; + +import java.lang.reflect.Field; + +/** + * 鑷畾涔夋敞鍏ュ姞杞藉櫒 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public interface ResourceTypeLoader { + + public void load(ResourceFactory factory, String srcResourceName, Object srcObj, 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/RetcodeException.java b/src/main/java/org/redkale/util/RetcodeException.java new file mode 100644 index 000000000..fd18feb43 --- /dev/null +++ b/src/main/java/org/redkale/util/RetcodeException.java @@ -0,0 +1,39 @@ +/* + */ +package org.redkale.util; + +/** + * 甯etcode閿欒鐮佺殑寮傚父
+ *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + */ +public class RetcodeException extends RuntimeException { + + private int retcode; + + public RetcodeException(int retcode) { + this.retcode = retcode; + } + + public RetcodeException(int retcode, Throwable cause) { + super(cause); + this.retcode = retcode; + } + + public RetcodeException(int retcode, String message) { + super(message); + this.retcode = retcode; + } + + public RetcodeException(int retcode, String message, Throwable cause) { + super(message, cause); + this.retcode = retcode; + } + + public int getRetcode() { + return retcode; + } + +} diff --git a/src/main/java/org/redkale/util/SignalShutDown.java b/src/main/java/org/redkale/util/SignalShutDown.java new file mode 100644 index 000000000..c5f8612cc --- /dev/null +++ b/src/main/java/org/redkale/util/SignalShutDown.java @@ -0,0 +1,50 @@ +//package org.redkale.util; +// +//import java.util.function.*; +// +///** +// * +// * @author zhangjx +// * @since 2.7.0 +// */ +//public class SignalShutDown implements Consumer>, sun.misc.SignalHandler { +// +// private Consumer shutdownConsumer; +// +// @Override +// public void accept(Consumer consumer) { +// this.shutdownConsumer = consumer; +// //Linux: +// //HUP 1 缁堢鏂嚎 +// //INT 2 涓柇锛堝悓 Ctrl + C锛 +// //QUIT 3 閫鍑猴紙鍚 Ctrl + \锛 +// //TERM 15 缁堟 +// //KILL 9 寮哄埗缁堟 +// //CONT 18 缁х画锛堜笌STOP鐩稿弽锛 fg/bg鍛戒护锛 +// //Windows: +// //SIGINT锛圛NT锛 Ctrl+C涓柇 +// //SIGILL 锛圛LL锛 闈炴硶鎸囦护 +// //SIGFPE锛團PE锛 娴偣寮傚父 +// //SIGSEGV锛圫EGV锛 鏃犳晥鐨勫唴瀛樺紩鐢 +// //SIGTERM锛圱ERM锛 kill鍙戝嚭鐨勮蒋浠剁粓姝 +// //SIGBREAK锛圔REAK锛 Ctrl+Break涓柇 +// //SIGABRT锛圓BRT锛 璋冪敤abort瀵艰嚧 +// //http://www.comptechdoc.org/os/linux/programming/linux_pgsignals.html +// try { +// String[] sigs = new String[]{"HUP", "TERM", "INT", "QUIT", "KILL", "TSTP", "USR1", "USR2", "STOP"}; +// for (String sig : sigs) { +// try { +// sun.misc.Signal.handle(new sun.misc.Signal(sig), this); +// } catch (Exception e) { +// } +// } +// } catch (Throwable t) { +// } +// } +// +// @Override +// public synchronized void handle(sun.misc.Signal sig) { +// String sigstr = sig + "," + sig.getName() + "," + sig.getNumber(); +// shutdownConsumer.accept(sigstr); +// } +//} diff --git a/src/main/java/org/redkale/util/SimpleProxySelector.java b/src/main/java/org/redkale/util/SimpleProxySelector.java new file mode 100644 index 000000000..d38466f48 --- /dev/null +++ b/src/main/java/org/redkale/util/SimpleProxySelector.java @@ -0,0 +1,47 @@ +/* + */ +package org.redkale.util; + +import java.io.IOException; +import java.net.*; +import java.util.List; + +/** + * 绠鍗曠殑http浠g悊鍣 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * + * @since 2.7.0 + */ +public class SimpleProxySelector extends ProxySelector { + + private static final List NO_PROXY_LIST = List.of(Proxy.NO_PROXY); + + final List list; + + SimpleProxySelector(Proxy... proxys) { + list = proxys.length == 0 ? NO_PROXY_LIST : List.of(proxys); + } + + public static SimpleProxySelector create(Proxy... proxys) { + return new SimpleProxySelector(proxys); + } + + @Override + public void connectFailed(URI uri, SocketAddress sa, IOException e) { + /* ignore */ + } + + @Override + public synchronized List select(URI uri) { + String scheme = uri.getScheme().toLowerCase(); + if (scheme.equals("http") || scheme.equals("https")) { + return list; + } else { + return NO_PROXY_LIST; + } + } +} diff --git a/src/main/java/org/redkale/util/Traces.java b/src/main/java/org/redkale/util/Traces.java new file mode 100644 index 000000000..88712d09c --- /dev/null +++ b/src/main/java/org/redkale/util/Traces.java @@ -0,0 +1,46 @@ +/* + */ +package org.redkale.util; + +/** + * 鍒涘缓traceid宸ュ叿绫 + * + *

+ * 璇︽儏瑙: https://redkale.org + * + * @author zhangjx + * @since 2.7.0 + */ +public class Traces { + + private static final boolean disabled = !Boolean.getBoolean("redkale.trace.enable"); + + private static ThreadLocal localTrace = new ThreadLocal<>(); + + public static boolean enable() { + return !disabled; + } + + public static String onceTraceid() { + return disabled ? null : Utility.uuid(); + } + + public static String createTraceid() { + if (disabled) return null; + String traceid = localTrace.get(); + if (traceid == null) { + traceid = Utility.uuid(); + localTrace.set(traceid); + } + return traceid; + } + + public static void currTraceid(String traceid) { + localTrace.set(traceid); + } + + public static String currTraceid() { + return disabled ? null : localTrace.get(); + } + +} diff --git a/src/main/java/org/redkale/util/Utility.java b/src/main/java/org/redkale/util/Utility.java index dc6e1b3a3..32f61a758 100644 --- a/src/main/java/org/redkale/util/Utility.java +++ b/src/main/java/org/redkale/util/Utility.java @@ -19,6 +19,8 @@ import java.util.concurrent.*; import java.util.function.*; import java.util.stream.Stream; import java.util.zip.GZIPInputStream; +import javax.crypto.*; +import javax.crypto.spec.SecretKeySpec; /** * @@ -39,10 +41,14 @@ public final class Utility { 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 cpus = Integer.getInteger("redkale.cpus", Runtime.getRuntime().availableProcessors()); + private static final int MAX_POW2 = 1 << 30; private static final Class JAVA_RECORD_CLASS; + private static final SecureRandom random = new SecureRandom(); + private static final IntFunction futureArrayFunc = c -> new CompletableFuture[c]; static { @@ -54,6 +60,12 @@ public final class Utility { JAVA_RECORD_CLASS = clz; } + //org.redkale.util.SignalShutDown + private static final String consumerSignalShutdownBinary = "cafebabe00000037006b0a0019003a090018003b07003c08003d08003e08003f0800400800410800420800430800440800450700460a000d00470a000d004807004907004a0a000d004b0a000d004c12000000500b001600510700520a0018005307005407005507005601001073687574646f776e436f6e73756d657201001d4c6a6176612f7574696c2f66756e6374696f6e2f436f6e73756d65723b0100095369676e61747572650100314c6a6176612f7574696c2f66756e6374696f6e2f436f6e73756d65723c4c6a6176612f6c616e672f537472696e673b3e3b0100063c696e69743e010003282956010004436f646501000f4c696e654e756d6265725461626c650100124c6f63616c5661726961626c655461626c65010004746869730100214c6f72672f7265646b616c652f7574696c2f5369676e616c53687574446f776e3b010006616363657074010020284c6a6176612f7574696c2f66756e6374696f6e2f436f6e73756d65723b29560100037369670100124c6a6176612f6c616e672f537472696e673b010004736967730100135b4c6a6176612f6c616e672f537472696e673b010008636f6e73756d65720100164c6f63616c5661726961626c65547970655461626c6501000d537461636b4d61705461626c6507002b0100104d6574686f64506172616d6574657273010034284c6a6176612f7574696c2f66756e6374696f6e2f436f6e73756d65723c4c6a6176612f6c616e672f537472696e673b3e3b295601000668616e646c65010014284c73756e2f6d6973632f5369676e616c3b29560100114c73756e2f6d6973632f5369676e616c3b010006736967737472010015284c6a6176612f6c616e672f4f626a6563743b295601007a4c6a6176612f6c616e672f4f626a6563743b4c6a6176612f7574696c2f66756e6374696f6e2f436f6e73756d65723c4c6a6176612f7574696c2f66756e6374696f6e2f436f6e73756d65723c4c6a6176612f6c616e672f537472696e673b3e3b3e3b4c73756e2f6d6973632f5369676e616c48616e646c65723b01000a536f7572636546696c650100135369676e616c53687574446f776e2e6a6176610c001f00200c001b001c0100106a6176612f6c616e672f537472696e670100034855500100045445524d010003494e54010004515549540100044b494c4c01000454535450010004555352310100045553523201000453544f5001000f73756e2f6d6973632f5369676e616c0c001f00570c003200580100136a6176612f6c616e672f457863657074696f6e0100136a6176612f6c616e672f5468726f7761626c650c0059005a0c005b005c010010426f6f7473747261704d6574686f64730f06005d08005e0c005f00600c0026003601001b6a6176612f7574696c2f66756e6374696f6e2f436f6e73756d65720c0026002701001f6f72672f7265646b616c652f7574696c2f5369676e616c53687574446f776e0100106a6176612f6c616e672f4f626a65637401001673756e2f6d6973632f5369676e616c48616e646c6572010015284c6a6176612f6c616e672f537472696e673b2956010043284c73756e2f6d6973632f5369676e616c3b4c73756e2f6d6973632f5369676e616c48616e646c65723b294c73756e2f6d6973632f5369676e616c48616e646c65723b0100076765744e616d6501001428294c6a6176612f6c616e672f537472696e673b0100096765744e756d6265720100032829490a00610062010005012c012c010100176d616b65436f6e63617457697468436f6e7374616e7473010038284c73756e2f6d6973632f5369676e616c3b4c6a6176612f6c616e672f537472696e673b49294c6a6176612f6c616e672f537472696e673b0700630c005f00670100246a6176612f6c616e672f696e766f6b652f537472696e67436f6e636174466163746f72790700690100064c6f6f6b757001000c496e6e6572436c6173736573010098284c6a6176612f6c616e672f696e766f6b652f4d6574686f6448616e646c6573244c6f6f6b75703b4c6a6176612f6c616e672f537472696e673b4c6a6176612f6c616e672f696e766f6b652f4d6574686f64547970653b4c6a6176612f6c616e672f537472696e673b5b4c6a6176612f6c616e672f4f626a6563743b294c6a6176612f6c616e672f696e766f6b652f43616c6c536974653b07006a0100256a6176612f6c616e672f696e766f6b652f4d6574686f6448616e646c6573244c6f6f6b757001001e6a6176612f6c616e672f696e766f6b652f4d6574686f6448616e646c657300210018001900020016001a00010002001b001c0001001d00000002001e00040001001f0020000100210000002f00010001000000052ab70001b10000000200220000000600010000000c00230000000c000100000005002400250000000100260027000300210000014a000400080000006f2a2bb500021009bd0003590312045359041205535905120653590612075359071208535908120953591006120a53591007120b53591008120c534d2c4e2dbe360403360515051504a200222d1505323a06bb000d591906b7000e2ab8000f57a700053a07840501a7ffdda700044db100020051005f006200100005006a006d0011000400220000002a000a0000001200050014003b001500510017005f00190062001800640015006a001c006d001b006e001d00230000002a000400510013002800290006003b002f002a002b00020000006f0024002500000000006f002c001c0001002d0000000c00010000006f002c001e0001002e000000470006ff0044000607001807001607002f07002f01010000ff001d000707001807001607002f07002f01010700030001070010fa0001ff000500020700180700160000420700110000300000000501002c0000001d0000000200310021003200330002002100000060000300030000001a2b2bb600122bb60013ba001400004d2ab400022cb900150200b10000000200220000000e000300000021000f00220019002300230000002000030000001a0024002500000000001a002800340001000f000b0035002900020030000000050100280000104100260036000200210000003300020002000000092a2bc00016b60017b10000000200220000000600010000000c00230000000c00010000000900240025000000300000000501002c10000004001d000000020037003800000002003900660000000a00010064006800650019004d000000080001004e0001004f"; + + private static final Consumer> signalShutdownConsumer; + + //org.redkale.util.AnonymousUnsafe private static final String funcAnonymousUnsafeBinary = "cafebabe0000003701710a000200030700040c000500060100106a6176612f6c616e672f4f626a6563740100063c696e69743e01000328295607000801000f73756e2f6d6973632f556e7361666509000a000b07000c0c000d000e0100206f72672f7265646b616c652f7574696c2f416e6f6e796d6f7573556e73616665010006756e736166650100114c73756e2f6d6973632f556e736166653b0a000700100c00110012010006676574496e74010016284c6a6176612f6c616e672f4f626a6563743b4a29490a000700140c00150016010006707574496e74010017284c6a6176612f6c616e672f4f626a6563743b4a4929560a000700180c0019001a0100096765744f626a656374010027284c6a6176612f6c616e672f4f626a6563743b4a294c6a6176612f6c616e672f4f626a6563743b0a0007001c0c001d001e0100097075744f626a656374010028284c6a6176612f6c616e672f4f626a6563743b4a4c6a6176612f6c616e672f4f626a6563743b29560a000700200c0021002201000a676574426f6f6c65616e010016284c6a6176612f6c616e672f4f626a6563743b4a295a0a000700240c0025002601000a707574426f6f6c65616e010017284c6a6176612f6c616e672f4f626a6563743b4a5a29560a000700280c0029002a01000767657442797465010016284c6a6176612f6c616e672f4f626a6563743b4a29420a0007002c0c002d002e01000770757442797465010017284c6a6176612f6c616e672f4f626a6563743b4a4229560a000700300c0031003201000867657453686f7274010016284c6a6176612f6c616e672f4f626a6563743b4a29530a000700340c0035003601000870757453686f7274010017284c6a6176612f6c616e672f4f626a6563743b4a5329560a000700380c0039003a01000767657443686172010016284c6a6176612f6c616e672f4f626a6563743b4a29430a0007003c0c003d003e01000770757443686172010017284c6a6176612f6c616e672f4f626a6563743b4a4329560a000700400c004100420100076765744c6f6e67010016284c6a6176612f6c616e672f4f626a6563743b4a294a0a000700440c004500460100077075744c6f6e67010017284c6a6176612f6c616e672f4f626a6563743b4a4a29560a000700480c0049004a010008676574466c6f6174010016284c6a6176612f6c616e672f4f626a6563743b4a29460a0007004c0c004d004e010008707574466c6f6174010017284c6a6176612f6c616e672f4f626a6563743b4a4629560a000700500c00510052010009676574446f75626c65010016284c6a6176612f6c616e672f4f626a6563743b4a29440a000700540c00550056010009707574446f75626c65010017284c6a6176612f6c616e672f4f626a6563743b4a4429560a000700580c00290059010004284a29420a0007005b0c002d005c010005284a4229560a0007005e0c0031005f010004284a29530a000700610c00350062010005284a5329560a000700640c00390065010004284a29430a000700670c003d0068010005284a4329560a0007006a0c0011006b010004284a29490a0007006d0c0015006e010005284a4929560a000700700c00410071010004284a294a0a000700730c00450074010005284a4a29560a000700760c00490077010004284a29460a000700790c004d007a010005284a4629560a0007007c0c0051007d010004284a29440a0007007f0c00550080010005284a4429560a000700820c0083007101000a676574416464726573730a000700850c0086007401000a707574416464726573730a000700880c0089007101000e616c6c6f636174654d656d6f72790a0007008b0c008c008d0100107265616c6c6f636174654d656d6f7279010005284a4a294a0a0007008f0c009000910100097365744d656d6f7279010018284c6a6176612f6c616e672f4f626a6563743b4a4a4229560a000700930c00900094010006284a4a4229560a000700960c0097009801000a636f70794d656d6f727901002a284c6a6176612f6c616e672f4f626a6563743b4a4c6a6176612f6c616e672f4f626a6563743b4a4a29560a0007009a0c0097009b010006284a4a4a29560a0007009d0c009e009f01000a667265654d656d6f7279010004284a29560a000700a10c00a200a30100116f626a6563744669656c644f666673657401001c284c6a6176612f6c616e672f7265666c6563742f4669656c643b294a0a000700a50c00a600a30100117374617469634669656c644f66667365740a000700a80c00a900aa01000f7374617469634669656c644261736501002d284c6a6176612f6c616e672f7265666c6563742f4669656c643b294c6a6176612f6c616e672f4f626a6563743b0a000700ac0c00ad00ae01000f6172726179426173654f6666736574010014284c6a6176612f6c616e672f436c6173733b29490a000700b00c00b100ae01000f6172726179496e6465785363616c650a000700b30c00b400b501000b6164647265737353697a650100032829490a000700b70c00b800b50100087061676553697a650a000700ba0c00bb00bc010010616c6c6f63617465496e7374616e6365010025284c6a6176612f6c616e672f436c6173733b294c6a6176612f6c616e672f4f626a6563743b0a000700be0c00bf00c001000e7468726f77457863657074696f6e010018284c6a6176612f6c616e672f5468726f7761626c653b29560a000700c20c00c300c4010014636f6d70617265416e64537761704f626a65637401003a284c6a6176612f6c616e672f4f626a6563743b4a4c6a6176612f6c616e672f4f626a6563743b4c6a6176612f6c616e672f4f626a6563743b295a0a000700c60c00c700c8010011636f6d70617265416e6453776170496e74010018284c6a6176612f6c616e672f4f626a6563743b4a4949295a0a000700ca0c00cb00cc010012636f6d70617265416e64537761704c6f6e67010018284c6a6176612f6c616e672f4f626a6563743b4a4a4a295a0a000700ce0c00cf001a0100116765744f626a656374566f6c6174696c650a000700d10c00d2001e0100117075744f626a656374566f6c6174696c650a000700d40c00d5001201000e676574496e74566f6c6174696c650a000700d70c00d8001601000e707574496e74566f6c6174696c650a000700da0c00db0022010012676574426f6f6c65616e566f6c6174696c650a000700dd0c00de0026010012707574426f6f6c65616e566f6c6174696c650a000700e00c00e1002a01000f67657442797465566f6c6174696c650a000700e30c00e4002e01000f70757442797465566f6c6174696c650a000700e60c00e7003201001067657453686f7274566f6c6174696c650a000700e90c00ea003601001070757453686f7274566f6c6174696c650a000700ec0c00ed003a01000f67657443686172566f6c6174696c650a000700ef0c00f0003e01000f70757443686172566f6c6174696c650a000700f20c00f3004201000f6765744c6f6e67566f6c6174696c650a000700f50c00f6004601000f7075744c6f6e67566f6c6174696c650a000700f80c00f9004a010010676574466c6f6174566f6c6174696c650a000700fb0c00fc004e010010707574466c6f6174566f6c6174696c650a000700fe0c00ff0052010011676574446f75626c65566f6c6174696c650a000701010c01020056010011707574446f75626c65566f6c6174696c650a000701040c0105001e0100107075744f7264657265644f626a6563740a000701070c0108001601000d7075744f726465726564496e740a0007010a0c010b004601000e7075744f7264657265644c6f6e670a0007010d0c010e010f010006756e7061726b010015284c6a6176612f6c616e672f4f626a6563743b29560a000701110c011201130100047061726b010005285a4a29560a000701150c0116011701000e6765744c6f616441766572616765010006285b444929490a000701190c011a011b01000c676574416e64416464496e74010017284c6a6176612f6c616e672f4f626a6563743b4a4929490a0007011d0c011e011f01000d676574416e644164644c6f6e67010017284c6a6176612f6c616e672f4f626a6563743b4a4a294a0a000701210c0122011b01000c676574416e64536574496e740a000701240c0125011f01000d676574416e645365744c6f6e670a000701270c0128012901000f676574416e645365744f626a656374010039284c6a6176612f6c616e672f4f626a6563743b4a4c6a6176612f6c616e672f4f626a6563743b294c6a6176612f6c616e672f4f626a6563743b0a0007012b0c012c00060100096c6f616446656e63650a0007012e0c012f000601000a73746f726546656e63650a000701310c0132000601000966756c6c46656e63650a000701340c0135013601000d696e766f6b65436c65616e6572010018284c6a6176612f6e696f2f427974654275666665723b29560701380100176f72672f7265646b616c652f7574696c2f556e73616665010004436f646501000f4c696e654e756d6265725461626c650100124c6f63616c5661726961626c655461626c65010004746869730100224c6f72672f7265646b616c652f7574696c2f416e6f6e796d6f7573556e736166653b0100036f626a0100124c6a6176612f6c616e672f4f626a6563743b0100104d6574686f64506172616d65746572730100016f0100066f66667365740100014a01000178010001490100015a010001420100015301000143010001460100014401000761646472657373010005627974657301000576616c7565010007737263426173650100097372634f6666736574010008646573744261736501000a646573744f666673657401000a7372634164647265737301000b6465737441646472657373010001660100194c6a6176612f6c616e672f7265666c6563742f4669656c643b01000a6172726179436c6173730100114c6a6176612f6c616e672f436c6173733b0100164c6f63616c5661726961626c65547970655461626c650100144c6a6176612f6c616e672f436c6173733c2a3e3b0100095369676e6174757265010017284c6a6176612f6c616e672f436c6173733c2a3e3b2949010003636c7301000a457863657074696f6e730701600100206a6176612f6c616e672f496e7374616e74696174696f6e457863657074696f6e010028284c6a6176612f6c616e672f436c6173733c2a3e3b294c6a6176612f6c616e672f4f626a6563743b01000265650100154c6a6176612f6c616e672f5468726f7761626c653b010008657870656374656401000674687265616401000a69734162736f6c75746501000474696d650100076c6f61646176670100025b440100066e656c656d7301000564656c74610100086e657756616c756501000c6469726563744275666665720100154c6a6176612f6e696f2f427974654275666665723b01000a536f7572636546696c65010014416e6f6e796d6f7573556e736166652e6a6176610021000a00020001013700010012000d000e0000005700010005010f0002013900000049000200020000000d2ab700012a2bc00007b50009b100000002013a0000000e00030000000a0004000b000c000c013b0000001600020000000d013c013d00000000000d013e013f000101400000000501013e00000001001100120002013900000048000400040000000a2ab400092b20b6000fac00000002013a00000006000100000010013b0000002000030000000a013c013d00000000000a0141013f00010000000a0142014300020140000000090201410000014200000001001500160002013900000058000500050000000c2ab400092b201504b60013b100000002013a0000000a000200000015000b0016013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c01440145000401400000000d0301410000014200000144000000010019001a0002013900000048000400040000000a2ab400092b20b60017b000000002013a0000000600010000001a013b0000002000030000000a013c013d00000000000a0141013f00010000000a0142014300020140000000090201410000014200000001001d001e0002013900000058000500050000000c2ab400092b201904b6001bb100000002013a0000000a00020000001f000b0020013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c0144013f000401400000000d030141000001420000014400000001002100220002013900000048000400040000000a2ab400092b20b6001fac00000002013a00000006000100000024013b0000002000030000000a013c013d00000000000a0141013f00010000000a0142014300020140000000090201410000014200000001002500260002013900000058000500050000000c2ab400092b201504b60023b100000002013a0000000a000200000029000b002a013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c01440146000401400000000d0301410000014200000144000000010029002a0002013900000048000400040000000a2ab400092b20b60027ac00000002013a0000000600010000002e013b0000002000030000000a013c013d00000000000a0141013f00010000000a0142014300020140000000090201410000014200000001002d002e0002013900000058000500050000000c2ab400092b201504b6002bb100000002013a0000000a000200000033000b0034013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c01440147000401400000000d030141000001420000014400000001003100320002013900000048000400040000000a2ab400092b20b6002fac00000002013a00000006000100000038013b0000002000030000000a013c013d00000000000a0141013f00010000000a0142014300020140000000090201410000014200000001003500360002013900000058000500050000000c2ab400092b201504b60033b100000002013a0000000a00020000003d000b003e013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c01440148000401400000000d0301410000014200000144000000010039003a0002013900000048000400040000000a2ab400092b20b60037ac00000002013a00000006000100000042013b0000002000030000000a013c013d00000000000a0141013f00010000000a0142014300020140000000090201410000014200000001003d003e0002013900000058000500050000000c2ab400092b201504b6003bb100000002013a0000000a000200000047000b0048013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c01440149000401400000000d030141000001420000014400000001004100420002013900000048000400040000000a2ab400092b20b6003fad00000002013a0000000600010000004c013b0000002000030000000a013c013d00000000000a0141013f00010000000a0142014300020140000000090201410000014200000001004500460002013900000058000600060000000c2ab400092b201604b60043b100000002013a0000000a000200000051000b0052013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c01440143000401400000000d0301410000014200000144000000010049004a0002013900000048000400040000000a2ab400092b20b60047ae00000002013a00000006000100000056013b0000002000030000000a013c013d00000000000a0141013f00010000000a0142014300020140000000090201410000014200000001004d004e0002013900000058000500050000000c2ab400092b201704b6004bb100000002013a0000000a00020000005b000b005c013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c0144014a000401400000000d030141000001420000014400000001005100520002013900000048000400040000000a2ab400092b20b6004faf00000002013a00000006000100000060013b0000002000030000000a013c013d00000000000a0141013f00010000000a0142014300020140000000090201410000014200000001005500560002013900000058000600060000000c2ab400092b201804b60053b100000002013a0000000a000200000065000b0066013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c0144014b000401400000000d03014100000142000001440000000100290059000201390000003d00030003000000092ab400091fb60057ac00000002013a0000000600010000006a013b00000016000200000009013c013d000000000009014c0143000101400000000501014c00000001002d005c000201390000004c000400040000000a2ab400091f1db6005ab100000002013a0000000a00020000006f00090070013b0000002000030000000a013c013d00000000000a014c014300010000000a01440147000301400000000902014c00000144000000010031005f000201390000003d00030003000000092ab400091fb6005dac00000002013a00000006000100000074013b00000016000200000009013c013d000000000009014c0143000101400000000501014c0000000100350062000201390000004c000400040000000a2ab400091f1db60060b100000002013a0000000a0002000000790009007a013b0000002000030000000a013c013d00000000000a014c014300010000000a01440148000301400000000902014c000001440000000100390065000201390000003d00030003000000092ab400091fb60063ac00000002013a0000000600010000007e013b00000016000200000009013c013d000000000009014c0143000101400000000501014c00000001003d0068000201390000004c000400040000000a2ab400091f1db60066b100000002013a0000000a00020000008300090084013b0000002000030000000a013c013d00000000000a014c014300010000000a01440149000301400000000902014c00000144000000010011006b000201390000003d00030003000000092ab400091fb60069ac00000002013a00000006000100000088013b00000016000200000009013c013d000000000009014c0143000101400000000501014c000000010015006e000201390000004c000400040000000a2ab400091f1db6006cb100000002013a0000000a00020000008d0009008e013b0000002000030000000a013c013d00000000000a014c014300010000000a01440145000301400000000902014c000001440000000100410071000201390000003d00030003000000092ab400091fb6006fad00000002013a00000006000100000092013b00000016000200000009013c013d000000000009014c0143000101400000000501014c0000000100450074000201390000004c000500050000000a2ab400091f21b60072b100000002013a0000000a00020000009700090098013b0000002000030000000a013c013d00000000000a014c014300010000000a01440143000301400000000902014c000001440000000100490077000201390000003d00030003000000092ab400091fb60075ae00000002013a0000000600010000009c013b00000016000200000009013c013d000000000009014c0143000101400000000501014c00000001004d007a000201390000004c000400040000000a2ab400091f25b60078b100000002013a0000000a0002000000a1000900a2013b0000002000030000000a013c013d00000000000a014c014300010000000a0144014a000301400000000902014c00000144000000010051007d000201390000003d00030003000000092ab400091fb6007baf00000002013a000000060001000000a6013b00000016000200000009013c013d000000000009014c0143000101400000000501014c0000000100550080000201390000004c000500050000000a2ab400091f29b6007eb100000002013a0000000a0002000000ab000900ac013b0000002000030000000a013c013d00000000000a014c014300010000000a0144014b000301400000000902014c000001440000000100830071000201390000003d00030003000000092ab400091fb60081ad00000002013a000000060001000000b0013b00000016000200000009013c013d000000000009014c0143000101400000000501014c0000000100860074000201390000004c000500050000000a2ab400091f21b60084b100000002013a0000000a0002000000b5000900b6013b0000002000030000000a013c013d00000000000a014c014300010000000a01440143000301400000000902014c000001440000000100890071000201390000003d00030003000000092ab400091fb60087ad00000002013a000000060001000000ba013b00000016000200000009013c013d000000000009014d0143000101400000000501014d00000001008c008d0002013900000048000500050000000a2ab400091f21b6008aad00000002013a000000060001000000bf013b0000002000030000000a013c013d00000000000a014c014300010000000a014d0143000301400000000902014c0000014d00000001009000910002013900000064000700070000000e2ab400092b2016041506b6008eb100000002013a0000000a0002000000c4000d00c5013b0000003400050000000e013c013d00000000000e0141013f00010000000e0142014300020000000e014d014300040000000e014e01470006014000000011040141000001420000014d0000014e00000001009000940002013900000058000600060000000c2ab400091f211505b60092b100000002013a0000000a0002000000c9000b00ca013b0000002a00040000000c013c013d00000000000c014c014300010000000c014d014300030000000c014e0147000501400000000d03014c0000014d0000014e0000000100970098000201390000007000090009000000102ab400092b20190416051607b60095b100000002013a0000000a0002000000ce000f00cf013b0000003e000600000010013c013d000000000010014f013f000100000010015001430002000000100151013f00040000001001520143000500000010014d0143000701400000001505014f0000015000000151000001520000014d000000010097009b0002013900000058000700070000000c2ab400091f211605b60099b100000002013a0000000a0002000000d3000b00d4013b0000002a00040000000c013c013d00000000000c0153014300010000000c0154014300030000000c014d0143000501400000000d030153000001540000014d00000001009e009f000201390000004100030003000000092ab400091fb6009cb100000002013a0000000a0002000000d8000800d9013b00000016000200000009013c013d000000000009014c0143000101400000000501014c0000000100a200a3000201390000003d00020002000000092ab400092bb600a0ad00000002013a000000060001000000dd013b00000016000200000009013c013d0000000000090155015600010140000000050101550000000100a600a3000201390000003d00020002000000092ab400092bb600a4ad00000002013a000000060001000000e2013b00000016000200000009013c013d0000000000090155015600010140000000050101550000000100a900aa000201390000003d00020002000000092ab400092bb600a7b000000002013a000000060001000000e7013b00000016000200000009013c013d0000000000090155015600010140000000050101550000000100ad00ae000301390000004f00020002000000092ab400092bb600abac00000003013a000000060001000000ec013b00000016000200000009013c013d00000000000901570158000101590000000c0001000000090157015a00010140000000050101570000015b00000002015c000100b100ae000301390000004f00020002000000092ab400092bb600afac00000003013a000000060001000000f1013b00000016000200000009013c013d00000000000901570158000101590000000c0001000000090157015a00010140000000050101570000015b00000002015c000100b400b5000101390000003200010001000000082ab40009b600b2ac00000002013a000000060001000000f6013b0000000c000100000008013c013d0000000100b800b5000101390000003200010001000000082ab40009b600b6ac00000002013a000000060001000000fb013b0000000c000100000008013c013d0000000100bb00bc000401390000004f00020002000000092ab400092bb600b9b000000003013a00000006000100000100013b00000016000200000009013c013d000000000009015d0158000101590000000c000100000009015d015a0001015e000000040001015f01400000000501015d0000015b000000020161000100bf00c0000201390000004100020002000000092ab400092bb600bdb100000002013a0000000a00020000010500080106013b00000016000200000009013c013d0000000000090162016300010140000000050101620000000100c300c40002013900000060000600060000000e2ab400092b2019041905b600c1ac00000002013a0000000600010000010a013b0000003400050000000e013c013d00000000000e0141013f00010000000e0142014300020000000e0164013f00040000000e0144013f00050140000000110401410000014200000164000001440000000100c700c80002013900000060000600060000000e2ab400092b2015041505b600c5ac00000002013a0000000600010000010f013b0000003400050000000e013c013d00000000000e0141013f00010000000e0142014300020000000e0164014500040000000e0144014500050140000000110401410000014200000164000001440000000100cb00cc0002013900000060000800080000000e2ab400092b2016041606b600c9ac00000002013a00000006000100000114013b0000003400050000000e013c013d00000000000e0141013f00010000000e0142014300020000000e0164014300040000000e0144014300060140000000110401410000014200000164000001440000000100cf001a0002013900000048000400040000000a2ab400092b20b600cdb000000002013a00000006000100000119013b0000002000030000000a013c013d00000000000a0141013f00010000000a014201430002014000000009020141000001420000000100d2001e0002013900000058000500050000000c2ab400092b201904b600d0b100000002013a0000000a00020000011e000b011f013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c0144013f000401400000000d03014100000142000001440000000100d500120002013900000048000400040000000a2ab400092b20b600d3ac00000002013a00000006000100000123013b0000002000030000000a013c013d00000000000a0141013f00010000000a014201430002014000000009020141000001420000000100d800160002013900000058000500050000000c2ab400092b201504b600d6b100000002013a0000000a000200000128000b0129013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c01440145000401400000000d03014100000142000001440000000100db00220002013900000048000400040000000a2ab400092b20b600d9ac00000002013a0000000600010000012d013b0000002000030000000a013c013d00000000000a0141013f00010000000a014201430002014000000009020141000001420000000100de00260002013900000058000500050000000c2ab400092b201504b600dcb100000002013a0000000a000200000132000b0133013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c01440146000401400000000d03014100000142000001440000000100e1002a0002013900000048000400040000000a2ab400092b20b600dfac00000002013a00000006000100000137013b0000002000030000000a013c013d00000000000a0141013f00010000000a014201430002014000000009020141000001420000000100e4002e0002013900000058000500050000000c2ab400092b201504b600e2b100000002013a0000000a00020000013c000b013d013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c01440147000401400000000d03014100000142000001440000000100e700320002013900000048000400040000000a2ab400092b20b600e5ac00000002013a00000006000100000141013b0000002000030000000a013c013d00000000000a0141013f00010000000a014201430002014000000009020141000001420000000100ea00360002013900000058000500050000000c2ab400092b201504b600e8b100000002013a0000000a000200000146000b0147013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c01440148000401400000000d03014100000142000001440000000100ed003a0002013900000048000400040000000a2ab400092b20b600ebac00000002013a0000000600010000014b013b0000002000030000000a013c013d00000000000a0141013f00010000000a014201430002014000000009020141000001420000000100f0003e0002013900000058000500050000000c2ab400092b201504b600eeb100000002013a0000000a000200000150000b0151013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c01440149000401400000000d03014100000142000001440000000100f300420002013900000048000400040000000a2ab400092b20b600f1ad00000002013a00000006000100000155013b0000002000030000000a013c013d00000000000a0141013f00010000000a014201430002014000000009020141000001420000000100f600460002013900000058000600060000000c2ab400092b201604b600f4b100000002013a0000000a00020000015a000b015b013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c01440143000401400000000d03014100000142000001440000000100f9004a0002013900000048000400040000000a2ab400092b20b600f7ae00000002013a0000000600010000015f013b0000002000030000000a013c013d00000000000a0141013f00010000000a014201430002014000000009020141000001420000000100fc004e0002013900000058000500050000000c2ab400092b201704b600fab100000002013a0000000a000200000164000b0165013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c0144014a000401400000000d03014100000142000001440000000100ff00520002013900000048000400040000000a2ab400092b20b600fdaf00000002013a00000006000100000169013b0000002000030000000a013c013d00000000000a0141013f00010000000a0142014300020140000000090201410000014200000001010200560002013900000058000600060000000c2ab400092b201804b60100b100000002013a0000000a00020000016e000b016f013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c0144014b000401400000000d0301410000014200000144000000010105001e0002013900000058000500050000000c2ab400092b201904b60103b100000002013a0000000a000200000173000b0174013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c0144013f000401400000000d030141000001420000014400000001010800160002013900000058000500050000000c2ab400092b201504b60106b100000002013a0000000a000200000178000b0179013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c01440145000401400000000d030141000001420000014400000001010b00460002013900000058000600060000000c2ab400092b201604b60109b100000002013a0000000a00020000017d000b017e013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c01440143000401400000000d030141000001420000014400000001010e010f000201390000004100020002000000092ab400092bb6010cb100000002013a0000000a00020000018200080183013b00000016000200000009013c013d0000000000090165013f00010140000000050101650000000101120113000201390000004c000400040000000a2ab400091b20b60110b100000002013a0000000a00020000018700090188013b0000002000030000000a013c013d00000000000a0166014600010000000a0167014300020140000000090201660000016700000001011601170002013900000048000300030000000a2ab400092b1cb60114ac00000002013a0000000600010000018c013b0000002000030000000a013c013d00000000000a0168016900010000000a016a014500020140000000090201680000016a00000001011a011b0002013900000054000500050000000c2ab400092b201504b60118ac00000002013a00000006000100000191013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c016b0145000401400000000d030141000001420000016b00000001011e011f0002013900000054000600060000000c2ab400092b201604b6011cad00000002013a00000006000100000196013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c016b0143000401400000000d030141000001420000016b000000010122011b0002013900000054000500050000000c2ab400092b201504b60120ac00000002013a0000000600010000019b013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c016c0145000401400000000d030141000001420000016c000000010125011f0002013900000054000600060000000c2ab400092b201604b60123ad00000002013a000000060001000001a0013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c016c0143000401400000000d030141000001420000016c00000001012801290002013900000054000500050000000c2ab400092b201904b60126b000000002013a000000060001000001a5013b0000002a00040000000c013c013d00000000000c0141013f00010000000c0142014300020000000c016c013f000401400000000d030141000001420000016c00000001012c0006000101390000003600010001000000082ab40009b6012ab100000002013a0000000a0002000001aa000701ab013b0000000c000100000008013c013d00000001012f0006000101390000003600010001000000082ab40009b6012db100000002013a0000000a0002000001af000701b0013b0000000c000100000008013c013d0000000101320006000101390000003600010001000000082ab40009b60130b100000002013a0000000a0002000001b4000701b5013b0000000c000100000008013c013d0000000101350136000201390000004100020002000000092ab400092bb60133b100000002013a0000000a0002000001b9000801ba013b00000016000200000009013c013d000000000009016d016e000101400000000501016d00000001016f000000020170"; private static final Unsafe unsafeInstance; @@ -78,6 +90,7 @@ public final class Utility { //private static final javax.net.ssl.SSLContext DEFAULTSSL_CONTEXT; //private static final javax.net.ssl.HostnameVerifier defaultVerifier = (s, ss) -> true; static { + System.setProperty("jdk.httpclient.allowRestrictedHeaders", "host"); Unsafe unsafe0 = null; Function strCharFunction0 = null; Function sbCharFunction0 = null; @@ -85,60 +98,65 @@ public final class Utility { Function sbByteFunction0 = null; Predicate strLatin1Function0 = null; ToLongFunction bufferAddrFunction0 = null; + Consumer> signalShutdownConsumer0 = 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); + { //unsafe + Field f = String.class.getDeclaredField("value"); + 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) { + 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 = (Object t) -> unsafe.getObject(t, fd1); + sbByteFunction0 = (Object t) -> unsafe.getObject(t, fd2); + strLatin1Function0 = (Object t) -> unsafe.getByte(t, fd3) == 0; //LATIN1:0 UTF16:1 + bufferAddrFunction0 = (Object t) -> unsafe.getLong(t, fd4); } - 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); + { //signalShutdown + Class>> shutdownClazz1 = null; + try { + shutdownClazz1 = (Class) loader.loadClass("org.re" + "dkale.util.SignalShutDown"); + } catch (Throwable t) { + } + if (shutdownClazz1 == null) { + byte[] classBytes = hexToBin(consumerSignalShutdownBinary); + shutdownClazz1 = (Class>>) new ClassLoader(loader) { + public final Class loadClass(String name, byte[] b) { + return defineClass(name, b, 0, b.length); + } + }.loadClass("org.re" + "dkale.util.SignalShutDown", classBytes); + RedkaleClassLoader.putDynClass(shutdownClazz1.getName(), classBytes, shutdownClazz1); + RedkaleClassLoader.putReflectionDeclaredConstructors(shutdownClazz1, shutdownClazz1.getName()); + signalShutdownConsumer0 = shutdownClazz1.getConstructor().newInstance(); + } } - 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(); } @@ -151,6 +169,7 @@ public final class Utility { sbByteFunction = sbByteFunction0; strLatin1Function = strLatin1Function0; bufferAddrFunction = bufferAddrFunction0; + signalShutdownConsumer = signalShutdownConsumer0; // try { // DEFAULTSSL_CONTEXT = javax.net.ssl.SSLContext.getInstance("SSL"); @@ -181,7 +200,18 @@ public final class Utility { } public static int cpus() { - return Runtime.getRuntime().availableProcessors(); + return cpus; + } + + public static Consumer> signalShutdownConsumer() { + return signalShutdownConsumer; + } + + public static void sleep(long millis) { + try { + Thread.sleep(millis); + } catch (Exception e) { + } } /** @@ -222,6 +252,18 @@ public final class Utility { return future.completeOnTimeout(value, timeout, unit); } + public static CompletableFuture allOfFutures(List> list, IntFunction func) { + CompletableFuture[] futures = list.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(Stream> stream, IntFunction func) { CompletableFuture[] futures = stream.toArray(futureArrayFunc); return CompletableFuture.allOf(futures).thenApply(v -> { @@ -245,6 +287,20 @@ public final class Utility { }); } + public static CompletableFuture allOfFutures(List> list, IntFunction func, BiConsumer consumer) { + CompletableFuture[] futures = list.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(Stream> stream, IntFunction func, BiConsumer consumer) { CompletableFuture[] futures = stream.toArray(futureArrayFunc); return CompletableFuture.allOf(futures).thenApply(v -> { @@ -272,6 +328,82 @@ public final class Utility { }); } + public static CompletableFuture> allOfFutures(List> list) { + CompletableFuture[] futures = list.toArray(futureArrayFunc); + return CompletableFuture.allOf(futures).thenApply(v -> { + int size = futures.length; + List rs = new ArrayList<>(size); + for (int i = 0; i < size; i++) { + rs.add(futures[i].join()); + } + return rs; + }); + } + + public static CompletableFuture> allOfFutures(Stream> stream) { + CompletableFuture[] futures = stream.toArray(futureArrayFunc); + return CompletableFuture.allOf(futures).thenApply(v -> { + int size = futures.length; + List rs = new ArrayList<>(size); + for (int i = 0; i < size; i++) { + rs.add(futures[i].join()); + } + return rs; + }); + } + + public static CompletableFuture> allOfFutures(CompletableFuture[] futures) { + return CompletableFuture.allOf(futures).thenApply(v -> { + int size = futures.length; + List rs = new ArrayList<>(size); + for (int i = 0; i < size; i++) { + rs.add(futures[i].join()); + } + return rs; + }); + } + + public static CompletableFuture> allOfFutures(List> list, BiConsumer consumer) { + CompletableFuture[] futures = list.toArray(futureArrayFunc); + return CompletableFuture.allOf(futures).thenApply(v -> { + int size = futures.length; + List rs = new ArrayList<>(size); + for (int i = 0; i < size; i++) { + T val = futures[i].join(); + consumer.accept(i, val); + rs.add(val); + } + return rs; + }); + } + + public static CompletableFuture> allOfFutures(Stream> stream, BiConsumer consumer) { + CompletableFuture[] futures = stream.toArray(futureArrayFunc); + return CompletableFuture.allOf(futures).thenApply(v -> { + int size = futures.length; + List rs = new ArrayList<>(size); + for (int i = 0; i < size; i++) { + T val = futures[i].join(); + consumer.accept(i, val); + rs.add(val); + } + return rs; + }); + } + + public static CompletableFuture> allOfFutures(CompletableFuture[] futures, BiConsumer consumer) { + return CompletableFuture.allOf(futures).thenApply(v -> { + int size = futures.length; + List rs = new ArrayList<>(size); + for (int i = 0; i < size; i++) { + T val = futures[i].join(); + consumer.accept(i, val); + rs.add(val); + } + return rs; + }); + } + /** * 灏嗗涓猭ey:value鐨勫瓧绗︿覆閿煎缁勫悎鎴愪竴涓狹ap锛宨tems闀垮害蹇呴』鏄伓鏁, 鍙傛暟涓暟鑻ユ槸濂囨暟鐨勮瘽锛屾渶鍚庝竴涓細琚拷鐣 * 绫讳技 JDK9涓殑 Map.of 鏂规硶 @@ -639,6 +771,25 @@ public final class Utility { return sb.toString(); } + /** + * 灏嗗璞¢泦鍚堢敤鍒嗛殧绗︽嫾鎺ユ垚瀛楃涓 + * + * @param 娉涘瀷 + * @param stream 闆嗗悎 + * @param delimiter 鍒嗛殧绗 + * + * @return String + */ + public static String joining(final Stream stream, final String delimiter) { + if (stream == null) return ""; + StringBuilder sb = new StringBuilder(); + stream.forEach(i -> { + if (sb.length() > 0) sb.append(delimiter); + sb.append(i); + }); + return sb.toString(); + } + /** * 灏嗗璞℃暟缁勭敤鍒嗛殧绗︽嫾鎺ユ垚瀛楃涓 * @@ -828,6 +979,24 @@ public final class Utility { return news; } + /** + * 灏嗕竴涓垨澶氫釜鏂板厓绱犳坊鍔犲埌鏁扮粍缁撳熬 + * + * @param 娉涘瀷 + * @param array 鍘熸暟缁 + * @param objs 寰呰拷鍔犳暟鎹 + * + * @return 鏂版暟缁 + */ + public static Object[][] append(final Object[][] array, final Object[]... objs) { + if (array == null || array.length == 0) return objs; + if (objs == null || objs.length == 0) return array; + final Object[][] news = new Object[array.length + objs.length][]; + System.arraycopy(array, 0, news, 0, array.length); + System.arraycopy(objs, 0, news, array.length, objs.length); + return news; + } + /** * 灏嗕竴涓垨澶氫釜鏂板厓绱犳坊鍔犲埌鏁扮粍缁撳熬 * @@ -1466,6 +1635,78 @@ public final class Utility { return newcols; } + /** + * 鏌ヨ鎸囧畾瀵硅薄, 娌℃湁杩斿洖null + * + * @param 娉涘瀷 + * @param array 鏁扮粍 + * @param predicate 鏌ユ壘鍣 + * + * @return 瀵硅薄 + */ + public static T find(final T[] array, final Predicate predicate) { + if (array == null) return null; + for (T item : array) { + if (item != null && predicate.test(item)) return item; + } + return null; + } + + /** + * 鏌ヨ鎸囧畾瀵硅薄, 娌℃湁杩斿洖null + * + * @param 娉涘瀷 + * @param array 鏁扮粍 + * @param predicate 鏌ユ壘鍣 + * + * @return 瀵硅薄 + */ + public static T find(final Collection array, final Predicate predicate) { + if (array == null) return null; + for (T item : array) { + if (item != null && predicate.test(item)) return item; + } + return null; + } + + /** + * 鏌ヨ鎸囧畾瀵硅薄浣嶇疆, 娌℃湁杩斿洖-1 + * + * @param 娉涘瀷 + * @param array 鏁扮粍 + * @param predicate 鏌ユ壘鍣 + * + * @return 浣嶇疆 + */ + public static int findIndex(final T[] array, final Predicate predicate) { + if (array == null) return -1; + int index = -1; + for (T item : array) { + ++index; + if (item != null && predicate.test(item)) return index; + } + return -1; + } + + /** + * 鏌ヨ鎸囧畾瀵硅薄浣嶇疆, 娌℃湁杩斿洖-1 + * + * @param 娉涘瀷 + * @param array 鏁扮粍 + * @param predicate 鏌ユ壘鍣 + * + * @return 浣嶇疆 + */ + public static int findIndex(final Collection array, final Predicate predicate) { + if (array == null) return -1; + int index = -1; + for (T item : array) { + ++index; + if (item != null && predicate.test(item)) return index; + } + return -1; + } + /** * 灏哹uffer鐨勫唴瀹硅浆鎹㈡垚瀛楃涓, string鍙傛暟涓嶄负绌烘椂浼氳拷鍔犲湪buffer鍐呭瀛楃涓蹭箣鍓 * @@ -1879,6 +2120,42 @@ public final class Utility { return ld.atStartOfDay(zid).toInstant().toEpochMilli(); } + /** + * 灏嗘椂闂存牸寮忓寲, 鏀寔%1$ty 鍜 %ty涓ょ鏍煎紡 + * + * @param format 鏍煎紡 + * @param size 甯%t鐨勪釜鏁帮紝鍊煎皬浜0鍒欓渶瑕佽绠 + * @param time 鏃堕棿 + * + * @since 2.7.0 + * + * @return 鏃堕棿鏍煎紡鍖 + */ + public static String formatTime(String format, int size, Object time) { + if (size < 0) { + int c = 0; + if (!format.contains("%1$")) { + for (char ch : format.toCharArray()) { + if (ch == '%') c++; + } + } + size = c; + } + if (size <= 1) return String.format(format, time); + if (size == 2) return String.format(format, time, time); + if (size == 3) return String.format(format, time, time, time); + if (size == 4) return String.format(format, time, time, time, time); + if (size == 5) return String.format(format, time, time, time, time, time); + if (size == 6) return String.format(format, time, time, time, time, time, time); + if (size == 7) return String.format(format, time, time, time, time, time, time, time); + if (size == 8) return String.format(format, time, time, time, time, time, time, time); + Object[] args = new Object[size]; + for (int i = 0; i < size; i++) { + args[i] = time; + } + return String.format(format, args); + } + /** * 灏唅nt[]寮哄埗杞崲鎴恇yte[] * @@ -1895,35 +2172,6 @@ public final class Utility { 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鍔犲瘑 * @@ -1932,7 +2180,18 @@ public final class Utility { * @return md5鍊 */ public static String md5Hex(String str) { - return binToHexString(md5Bytes(str)); + return binToHexString(md5(str)); + } + + /** + * MD5鍔犲瘑 + * + * @param input 寰呭姞瀵嗘暟鎹 + * + * @return md5鍊 + */ + public static String md5Hex(byte[] input) { + return binToHexString(md5(input)); } /** @@ -1942,44 +2201,54 @@ public final class Utility { * * @return md5鍊 */ - public static byte[] md5Bytes(String str) { + public static byte[] md5(String str) { if (str == null) return null; MessageDigest md5; try { md5 = MessageDigest.getInstance("MD5"); } catch (NoSuchAlgorithmException ex) { - throw new RuntimeException(ex); + throw new RuntimeException("Couldn't find a MD5 provider", ex); } return md5.digest(str.getBytes()); } /** - * SHA-256 + * MD5鍔犲瘑 * - * @param bs 寰卙ash鏁版嵁 + * @param input 寰呭姞瀵嗘暟鎹 * - * @return hash鍊 + * @return md5鍊 */ - public static String sha256Hex(byte[] bs) { - return binToHexString(sha256Bytes(bs)); + public static byte[] md5(byte[] input) { + if (input == null) return null; + MessageDigest md5; + try { + md5 = MessageDigest.getInstance("MD5"); + } catch (NoSuchAlgorithmException ex) { + throw new RuntimeException("Couldn't find a MD5 provider", ex); + } + return md5.digest(input); } /** - * SHA-256 + * MD5鍔犲瘑 * - * @param bs 寰卙ash鏁版嵁 + * @param input 寰呭姞瀵嗘暟鎹 + * @param offset 鍋忕Щ閲 + * @param len 闀垮害 * - * @return hash鍊 + * @return md5鍊 */ - public static byte[] sha256Bytes(byte[] bs) { - if (bs == null) return null; - MessageDigest digester; + public static byte[] md5(byte[] input, int offset, int len) { + if (input == null) return null; + MessageDigest md5; try { - digester = MessageDigest.getInstance("SHA-256"); + md5 = MessageDigest.getInstance("MD5"); + md5.update(input, offset, len); + return md5.digest(); } catch (NoSuchAlgorithmException ex) { - throw new RuntimeException(ex); + throw new RuntimeException("Couldn't find a MD5 provider", ex); } - return digester.digest(bs); } /** @@ -1990,7 +2259,55 @@ public final class Utility { * @return hash鍊 */ public static String sha256Hex(String str) { - return binToHexString(sha256Bytes(str)); + return binToHexString(sha256(str)); + } + + /** + * SHA-256 + * + * @param input 寰卙ash鏁版嵁 + * + * @return hash鍊 + */ + public static String sha256Hex(byte[] input) { + return binToHexString(sha256(input)); + } + + /** + * SHA-256 + * + * @param input 寰卙ash鏁版嵁 + * @param offset 鍋忕Щ閲 + * @param len 闀垮害 + * + * @return hash鍊 + */ + public static String sha256Hex(byte[] input, int offset, int len) { + return binToHexString(sha256(input, offset, len)); + } + + /** + * 浠0x寮澶寸殑 SHA-256 + * + * @param input 寰卙ash鏁版嵁 + * + * @return hash鍊 + */ + public static String sha256Hex0x(byte[] input) { + return binTo0xHexString(sha256(input)); + } + + /** + * 浠0x寮澶寸殑 SHA-256 + * + * @param input 寰卙ash鏁版嵁 + * @param offset 鍋忕Щ閲 + * @param len 闀垮害 + * + * @return hash鍊 + */ + public static String sha256Hex0x(byte[] input, int offset, int len) { + return binTo0xHexString(sha256(input, offset, len)); } /** @@ -2000,15 +2317,532 @@ public final class Utility { * * @return hash鍊 */ - public static byte[] sha256Bytes(String str) { + public static byte[] sha256(String str) { if (str == null) return null; MessageDigest digester; + try { + digester = MessageDigest.getInstance("SHA-256"); + } catch (NoSuchAlgorithmException ex) { + throw new RuntimeException("Couldn't find a SHA-256 provider", ex); + } + return digester.digest(str.getBytes(StandardCharsets.UTF_8)); + } + + /** + * SHA-256 + * + * @param input 寰卙ash鏁版嵁 + * + * @return hash鍊 + */ + public static byte[] sha256(byte[] input) { + if (input == null) return null; + MessageDigest digester; try { digester = MessageDigest.getInstance("SHA-256"); } catch (NoSuchAlgorithmException ex) { throw new RuntimeException(ex); } - return digester.digest(str.getBytes()); + return digester.digest(input); + } + + /** + * SHA-256 + * + * @param input 寰卙ash鏁版嵁 + * @param offset 鍋忕Щ閲 + * @param len 闀垮害 + * + * @return hash鍊 + */ + public static byte[] sha256(byte[] input, int offset, int len) { + if (input == null) return null; + MessageDigest digester; + try { + digester = MessageDigest.getInstance("SHA-256"); + digester.update(input, offset, len); + return digester.digest(); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + + /** + * HmacSHA1 + * + * @param key 瀵嗛挜 + * @param input 寰卙ash鏁版嵁 + * + * @return hash鍊 + */ + public static String hmacSha1Base64(String key, String input) { + return Base64.getEncoder().encodeToString(hmacSha1(key.getBytes(UTF_8), input.getBytes(UTF_8))); + } + + /** + * HmacSHA1 + * + * @param key 瀵嗛挜 + * @param input 寰卙ash鏁版嵁 + * + * @return hash鍊 + */ + public static String hmacSha1Base64(byte[] key, byte[] input) { + return Base64.getEncoder().encodeToString(hmacSha1(key, input)); + } + + /** + * HmacSHA1 + * + * @param key 瀵嗛挜 + * @param input 寰卙ash鏁版嵁 + * @param offset 鍋忕Щ閲 + * @param len 闀垮害 + * + * @return hash鍊 + */ + public static String hmacSha1Base64(byte[] key, byte[] input, int offset, int len) { + return Base64.getEncoder().encodeToString(hmacSha1(key, input, offset, len)); + } + + /** + * HmacSHA1 + * + * @param key 瀵嗛挜 + * @param input 寰卙ash鏁版嵁 + * + * @return hash鍊 + */ + public static String hmacSha1Hex(byte[] key, byte[] input) { + return binToHexString(hmacSha1(key, input)); + } + + /** + * HmacSHA1 + * + * @param key 瀵嗛挜 + * @param input 寰卙ash鏁版嵁 + * @param offset 鍋忕Щ閲 + * @param len 闀垮害 + * + * @return hash鍊 + */ + public static String hmacSha1Hex(byte[] key, byte[] input, int offset, int len) { + return binToHexString(hmacSha1(key, input, offset, len)); + } + + /** + * 浠0x寮澶寸殑 HmacSHA1 + * + * @param key 瀵嗛挜 + * @param input 寰卙ash鏁版嵁 + * + * @return hash鍊 + */ + public static String hmacSha1Hex0x(byte[] key, byte[] input) { + return binTo0xHexString(hmacSha1(key, input)); + } + + /** + * 浠0x寮澶寸殑 HmacSHA1 + * + * @param key 瀵嗛挜 + * @param input 寰卙ash鏁版嵁 + * @param offset 鍋忕Щ閲 + * @param len 闀垮害 + * + * @return hash鍊 + */ + public static String hmacSha1Hex0x(byte[] key, byte[] input, int offset, int len) { + return binTo0xHexString(hmacSha1(key, input, offset, len)); + } + + /** + * HmacSHA1 + * + * @param key 瀵嗛挜 + * @param input 寰卙ash鏁版嵁 + * + * @return hash鍊 + */ + public static byte[] hmacSha1(byte[] key, byte[] input) { + if (input == null) return null; + try { + Mac mac = Mac.getInstance("HmacSHA1"); + mac.init(new SecretKeySpec(key, "HmacSHA1")); + return mac.doFinal(input); + } catch (InvalidKeyException | NoSuchAlgorithmException ex) { + throw new RuntimeException(ex); + } + } + + /** + * HmacSHA1 + * + * @param key 瀵嗛挜 + * @param input 寰卙ash鏁版嵁 + * @param offset 鍋忕Щ閲 + * @param len 闀垮害 + * + * @return hash鍊 + */ + public static byte[] hmacSha1(byte[] key, byte[] input, int offset, int len) { + if (input == null) return null; + try { + Mac mac = Mac.getInstance("HmacSHA1"); + mac.init(new SecretKeySpec(key, "HmacSHA1")); + mac.update(input, offset, len); + return mac.doFinal(); + } catch (InvalidKeyException | NoSuchAlgorithmException ex) { + throw new RuntimeException(ex); + } + } + + /** + * HmacSHA256 + * + * @param key 瀵嗛挜 + * @param input 寰卙ash鏁版嵁 + * + * @return hash鍊 + */ + public static String hmacSha256Base64(String key, String input) { + return Base64.getEncoder().encodeToString(hmacSha256(key.getBytes(UTF_8), input.getBytes(UTF_8))); + } + + /** + * HmacSHA256 + * + * @param key 瀵嗛挜 + * @param input 寰卙ash鏁版嵁 + * + * @return hash鍊 + */ + public static String hmacSha256Base64(byte[] key, byte[] input) { + return Base64.getEncoder().encodeToString(hmacSha256(key, input)); + } + + /** + * HmacSHA256 + * + * @param key 瀵嗛挜 + * @param input 寰卙ash鏁版嵁 + * @param offset 鍋忕Щ閲 + * @param len 闀垮害 + * + * @return hash鍊 + */ + public static String hmacSha256Base64(byte[] key, byte[] input, int offset, int len) { + return Base64.getEncoder().encodeToString(hmacSha256(key, input, offset, len)); + } + + /** + * HmacSHA256 + * + * @param key 瀵嗛挜 + * @param input 寰卙ash鏁版嵁 + * + * @return hash鍊 + */ + public static String hmacSha256Hex(byte[] key, byte[] input) { + return binToHexString(hmacSha256(key, input)); + } + + /** + * HmacSHA256 + * + * @param key 瀵嗛挜 + * @param input 寰卙ash鏁版嵁 + * @param offset 鍋忕Щ閲 + * @param len 闀垮害 + * + * @return hash鍊 + */ + public static String hmacSha256Hex(byte[] key, byte[] input, int offset, int len) { + return binToHexString(hmacSha256(key, input, offset, len)); + } + + /** + * 浠0x寮澶寸殑 HmacSHA256 + * + * @param key 瀵嗛挜 + * @param input 寰卙ash鏁版嵁 + * + * @return hash鍊 + */ + public static String hmacSha256Hex0x(byte[] key, byte[] input) { + return binTo0xHexString(hmacSha256(key, input)); + } + + /** + * 浠0x寮澶寸殑 HmacSHA256 + * + * @param key 瀵嗛挜 + * @param input 寰卙ash鏁版嵁 + * @param offset 鍋忕Щ閲 + * @param len 闀垮害 + * + * @return hash鍊 + */ + public static String hmacSha256Hex0x(byte[] key, byte[] input, int offset, int len) { + return binTo0xHexString(hmacSha256(key, input, offset, len)); + } + + /** + * HmacSHA256 + * + * @param key 瀵嗛挜 + * @param input 寰卙ash鏁版嵁 + * + * @return hash鍊 + */ + public static byte[] hmacSha256(byte[] key, byte[] input) { + if (input == null) return null; + try { + Mac mac = Mac.getInstance("HmacSHA256"); + mac.init(new SecretKeySpec(key, "HmacSHA256")); + return mac.doFinal(input); + } catch (InvalidKeyException | NoSuchAlgorithmException ex) { + throw new RuntimeException(ex); + } + } + + /** + * HmacSHA256 + * + * @param key 瀵嗛挜 + * @param input 寰卙ash鏁版嵁 + * @param offset 鍋忕Щ閲 + * @param len 闀垮害 + * + * @return hash鍊 + */ + public static byte[] hmacSha256(byte[] key, byte[] input, int offset, int len) { + if (input == null) return null; + try { + Mac mac = Mac.getInstance("HmacSHA256"); + mac.init(new SecretKeySpec(key, "HmacSHA256")); + mac.update(input, offset, len); + return mac.doFinal(); + } catch (InvalidKeyException | NoSuchAlgorithmException ex) { + throw new RuntimeException(ex); + } + } + + /** + * HmacSHA512 + * + * @param key 瀵嗛挜 + * @param input 寰卙ash鏁版嵁 + * + * @return hash鍊 + */ + public static String hmacSha512Base64(String key, String input) { + return Base64.getEncoder().encodeToString(hmacSha512(key.getBytes(UTF_8), input.getBytes(UTF_8))); + } + + /** + * HmacSHA512 + * + * @param key 瀵嗛挜 + * @param input 寰卙ash鏁版嵁 + * + * @return hash鍊 + */ + public static String hmacSha512Base64(byte[] key, byte[] input) { + return Base64.getEncoder().encodeToString(hmacSha512(key, input)); + } + + /** + * HmacSHA512 + * + * @param key 瀵嗛挜 + * @param input 寰卙ash鏁版嵁 + * @param offset 鍋忕Щ閲 + * @param len 闀垮害 + * + * @return hash鍊 + */ + public static String hmacSha512Base64(byte[] key, byte[] input, int offset, int len) { + return Base64.getEncoder().encodeToString(hmacSha512(key, input, offset, len)); + } + + /** + * HmacSHA512 + * + * @param key 瀵嗛挜 + * @param input 寰卙ash鏁版嵁 + * + * @return hash鍊 + */ + public static String hmacSha512Hex(byte[] key, byte[] input) { + return binToHexString(hmacSha512(key, input)); + } + + /** + * HmacSHA512 + * + * @param key 瀵嗛挜 + * @param input 寰卙ash鏁版嵁 + * @param offset 鍋忕Щ閲 + * @param len 闀垮害 + * + * @return hash鍊 + */ + public static String hmacSha512Hex(byte[] key, byte[] input, int offset, int len) { + return binToHexString(hmacSha512(key, input, offset, len)); + } + + /** + * 浠0x寮澶寸殑 HmacSHA512 + * + * @param key 瀵嗛挜 + * @param input 寰卙ash鏁版嵁 + * + * @return hash鍊 + */ + public static String hmacSha512Hex0x(byte[] key, byte[] input) { + return binTo0xHexString(hmacSha512(key, input)); + } + + /** + * 浠0x寮澶寸殑 HmacSHA512 + * + * @param key 瀵嗛挜 + * @param input 寰卙ash鏁版嵁 + * @param offset 鍋忕Щ閲 + * @param len 闀垮害 + * + * @return hash鍊 + */ + public static String hmacSha512Hex0x(byte[] key, byte[] input, int offset, int len) { + return binTo0xHexString(hmacSha512(key, input, offset, len)); + } + + /** + * HmacSHA512 + * + * @param key 瀵嗛挜 + * @param input 寰卙ash鏁版嵁 + * + * @return hash鍊 + */ + public static byte[] hmacSha512(byte[] key, byte[] input) { + if (input == null) return null; + try { + SecretKey sk = new SecretKeySpec(key, "HmacSHA512"); + Mac mac = Mac.getInstance("HmacSHA512"); + mac.init(sk); + return mac.doFinal(input); + } catch (InvalidKeyException | NoSuchAlgorithmException ex) { + throw new RuntimeException(ex); + } + } + + /** + * HmacSHA512 + * + * @param key 瀵嗛挜 + * @param input 寰卙ash鏁版嵁 + * @param offset 鍋忕Щ閲 + * @param len 闀垮害 + * + * @return hash鍊 + */ + public static byte[] hmacSha512(byte[] key, byte[] input, int offset, int len) { + if (input == null) return null; + try { + SecretKey sk = new SecretKeySpec(key, "HmacSHA512"); + Mac mac = Mac.getInstance("HmacSHA512"); + mac.init(sk); + mac.update(input, offset, len); + return mac.doFinal(); + } catch (InvalidKeyException | NoSuchAlgorithmException ex) { + throw new RuntimeException(ex); + } + } + + /** + * 鏍规嵁鎸囧畾绠楁硶杩涜hash + * + * @param algorithm 绠楁硶鍚 + * @param input 寰卙ash鏁版嵁 + * + * @return hash鍊 + */ + public static byte[] hash(String algorithm, byte[] input) { + try { + MessageDigest digest = MessageDigest.getInstance(algorithm.toUpperCase()); + return digest.digest(input); + } catch (NoSuchAlgorithmException ex) { + throw new RuntimeException("Couldn't find a " + algorithm + " provider", ex); + } + } + + /** + * 鏍规嵁鎸囧畾绠楁硶杩涜hash + * + * @param algorithm 绠楁硶鍚 + * @param input 寰卙ash鏁版嵁 + * @param offset 鍋忕Щ閲 + * @param length 闀垮害 + * + * @return hash鍊 + */ + public static byte[] hash(String algorithm, byte[] input, int offset, int length) { + try { + MessageDigest digest = MessageDigest.getInstance(algorithm.toUpperCase()); + digest.update(input, offset, length); + return digest.digest(); + } catch (NoSuchAlgorithmException ex) { + throw new RuntimeException("Couldn't find a " + algorithm + " provider", ex); + } + } + + /** + * 闅忔満 + * + * @return 闅忔満 + */ + public static SecureRandom secureRandom() { + return random; + } + + /** + * 鐢熸垚闅忔満鏁 + * + * @param size 闅忔満鏁伴暱搴 + * + * @return 闅忔満鏁 + */ + public static byte[] generateRandomBytes(int size) { + byte[] bytes = new byte[size]; + random.nextBytes(bytes); + return bytes; + } + + /** + * 灏嗗瓧鑺傛暟缁勮浆鎹负浠0x寮澶寸殑16杩涘埗瀛楃涓 + * + * @param bytes 瀛楄妭鏁扮粍 + * + * @return 16杩涘埗瀛楃涓 + */ + public static String binTo0xHexString(byte[] bytes) { + return "0x" + new String(binToHex(bytes)); + } + + /** + * 灏嗗瓧鑺傛暟缁勮浆鎹负浠0x寮澶寸殑16杩涘埗瀛楃涓 + * + * @param bytes 瀛楄妭鏁扮粍 + * @param offset 鍋忕Щ閲 + * @param len 闀垮害 + * + * @return 16杩涘埗瀛楃涓 + */ + public static String binTo0xHexString(byte[] bytes, int offset, int len) { + return "0x" + new String(binToHex(bytes, offset, len)); } /** @@ -2090,6 +2924,10 @@ public final class Utility { * @return 瀛楄妭鏁扮粍 */ public static byte[] hexToBin(CharSequence src, int offset, int len) { + if (offset == 0 && src.length() > 2 && src.charAt(0) == '0' && (src.charAt(1) == 'x' || src.charAt(1) == 'X')) { + offset += 2; + len -= 2; + } final int size = (len + 1) / 2; final byte[] bytes = new byte[size]; String digits = "0123456789abcdef"; @@ -2141,6 +2979,10 @@ public final class Utility { * @return 瀛楄妭鏁扮粍 */ public static byte[] hexToBin(char[] src, int offset, int len) { + if (offset == 0 && src.length > 2 && src[0] == '0' && (src[1] == 'x' || src[1] == 'X')) { + offset += 2; + len -= 2; + } final int size = (len + 1) / 2; final byte[] bytes = new byte[size]; String digits = "0123456789abcdef"; @@ -2597,6 +3439,42 @@ public final class Utility { return remoteHttpContent("GET", url, timeout, headers, body).toByteArray(); } + public static String remoteHttpContent(HttpClient client, String method, String url, Charset charset) throws IOException { + return remoteHttpContentAsync(client, method, url, 0, null, null).thenApply(out -> out.toString(charset == null ? StandardCharsets.UTF_8 : charset)).join(); + } + + public static String remoteHttpContent(HttpClient client, String method, String url, int timeout, Charset charset) throws IOException { + return remoteHttpContentAsync(client, method, url, timeout, null, null).thenApply(out -> out.toString(charset == null ? StandardCharsets.UTF_8 : charset)).join(); + } + + public static String remoteHttpContent(HttpClient client, String method, String url, Charset charset, Map headers) throws IOException { + return remoteHttpContentAsync(client, method, url, 0, headers, null).thenApply(out -> out.toString(charset == null ? StandardCharsets.UTF_8 : charset)).join(); + } + + public static String remoteHttpContent(HttpClient client, String method, String url, Charset charset, Map headers, String body) throws IOException { + return remoteHttpContentAsync(client, method, url, 0, headers, body).thenApply(out -> out.toString(charset == null ? StandardCharsets.UTF_8 : charset)).join(); + } + + public static String remoteHttpContent(HttpClient client, String method, String url, int timeout, Charset charset, Map headers) throws IOException { + return remoteHttpContentAsync(client, method, url, timeout, headers, null).thenApply(out -> out.toString(charset == null ? StandardCharsets.UTF_8 : charset)).join(); + } + + public static String remoteHttpContent(HttpClient client, String method, String url, int timeout, Charset charset, Map headers, String body) throws IOException { + return remoteHttpContentAsync(client, method, url, timeout, headers, body).thenApply(out -> out.toString(charset == null ? StandardCharsets.UTF_8 : charset)).join(); + } + + public static byte[] remoteHttpBytesContent(HttpClient client, String method, String url, Charset charset, Map headers, String body) throws IOException { + return remoteHttpContentAsync(client, method, url, 0, headers, body).thenApply(out -> out.toByteArray()).join(); + } + + public static byte[] remoteHttpBytesContent(HttpClient client, String method, String url, int timeout, Charset charset, Map headers) throws IOException { + return remoteHttpContentAsync(client, method, url, timeout, headers, null).thenApply(out -> out.toByteArray()).join(); + } + + public static byte[] remoteHttpBytesContent(HttpClient client, String method, String url, int timeout, Charset charset, Map headers, String body) throws IOException { + return remoteHttpContentAsync(client, method, url, timeout, headers, body).thenApply(out -> out.toByteArray()).join(); + } + public static ByteArrayOutputStream remoteHttpContent(String method, String url, Map headers, String body) throws IOException { return remoteHttpContent(method, url, 0, headers, body); } @@ -2605,131 +3483,295 @@ public final class Utility { return remoteHttpContentAsync(method, url, timeout, headers, body).join(); } + public static ByteArrayOutputStream remoteHttpContent(HttpClient client, String method, String url, int timeout, Map headers, String body) throws IOException { + return remoteHttpContentAsync(client, 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, Map respHeaders) { + return remoteHttpContentAsync("POST", url, 0, null, null, respHeaders).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, int timeout, Map respHeaders) { + return remoteHttpContentAsync("POST", url, timeout, null, null, respHeaders).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, String body, Map respHeaders) { + return remoteHttpContentAsync("POST", url, 0, null, body, respHeaders).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, int timeout, String body, Map respHeaders) { + return remoteHttpContentAsync("POST", url, timeout, null, body, respHeaders).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, Map headers, String body, Map respHeaders) { + return remoteHttpContentAsync("POST", url, 0, headers, body, respHeaders).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, int timeout, Map headers, String body, Map respHeaders) { + return remoteHttpContentAsync("POST", url, timeout, headers, body, respHeaders).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, Charset charset, Map respHeaders) { + return remoteHttpContentAsync("POST", url, 0, null, null, respHeaders).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, int timeout, Charset charset, Map respHeaders) { + return remoteHttpContentAsync("POST", url, timeout, null, null, respHeaders).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(String url, Charset charset, String body, Map respHeaders) { + return remoteHttpContentAsync("POST", url, 0, null, body, respHeaders).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(HttpClient client, String url, Charset charset, String body, Map respHeaders) { + return remoteHttpContentAsync(client, "POST", url, 0, null, body, respHeaders).thenApply(out -> out.toString(charset)); + } + + public static CompletableFuture postHttpContentAsync(HttpClient client, String url, Map headers, String body) { + return remoteHttpContentAsync(client, "POST", url, 0, headers, body).thenApply(out -> out.toString(StandardCharsets.UTF_8)); + } + + public static CompletableFuture postHttpContentAsync(HttpClient client, String url, Map headers, String body, Map respHeaders) { + return remoteHttpContentAsync(client, "POST", url, 0, headers, body, respHeaders).thenApply(out -> out.toString(StandardCharsets.UTF_8)); + } + + public static CompletableFuture postHttpContentAsync(HttpClient client, String url, Charset charset, Map headers, String body) { + return remoteHttpContentAsync(client, "POST", url, 0, headers, body).thenApply(out -> out.toString(charset)); + } + + public static CompletableFuture postHttpContentAsync(HttpClient client, String url, Charset charset, Map headers, String body, Map respHeaders) { + return remoteHttpContentAsync(client, "POST", url, 0, headers, body, respHeaders).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, int timeout, Charset charset, String body, Map respHeaders) { + return remoteHttpContentAsync("POST", url, timeout, null, body, respHeaders).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, Charset charset, Map headers, String body, Map respHeaders) { + return remoteHttpContentAsync("POST", url, 0, headers, body, respHeaders).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 postHttpContentAsync(String url, int timeout, Charset charset, Map headers, String body, Map respHeaders) { + return remoteHttpContentAsync("POST", url, timeout, headers, body, respHeaders).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, Map respHeaders) { + return remoteHttpContentAsync("POST", url, 0, null, null, respHeaders).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, int timeout, Map respHeaders) { + return remoteHttpContentAsync("POST", url, timeout, null, null, respHeaders).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, Map headers, String body, Map respHeaders) { + return remoteHttpContentAsync("POST", url, 0, headers, body, respHeaders).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 postHttpBytesContentAsync(String url, int timeout, Map headers, String body, Map respHeaders) { + return remoteHttpContentAsync("POST", url, timeout, headers, body, respHeaders).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, Map respHeaders) { + return remoteHttpContentAsync("GET", url, 0, null, null, respHeaders).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, int timeout, Map respHeaders) { + return remoteHttpContentAsync("GET", url, timeout, null, null, respHeaders).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, Map headers, String body, Map respHeaders) { + return remoteHttpContentAsync("GET", url, 0, headers, body, respHeaders).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, int timeout, Map headers, String body, Map respHeaders) { + return remoteHttpContentAsync("GET", url, timeout, headers, body, respHeaders).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, Charset charset, Map respHeaders) { + return remoteHttpContentAsync("GET", url, 0, null, null, respHeaders).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, int timeout, Charset charset, Map respHeaders) { + return remoteHttpContentAsync("GET", url, timeout, null, null, respHeaders).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, Charset charset, Map headers, String body, Map respHeaders) { + return remoteHttpContentAsync("GET", url, 0, headers, body, respHeaders).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 getHttpContentAsync(String url, int timeout, Charset charset, Map headers, String body, Map respHeaders) { + return remoteHttpContentAsync("GET", url, timeout, headers, body, respHeaders).thenApply(out -> out.toString(charset)); + } + + public static CompletableFuture getHttpContentAsync(java.net.http.HttpClient client, String url, String body, Map respHeaders) { + return remoteHttpContentAsync(client, "GET", url, 0, null, body, respHeaders).thenApply(out -> out.toString(StandardCharsets.UTF_8)); + } + + public static CompletableFuture getHttpContentAsync(java.net.http.HttpClient client, String url, Charset charset, String body, Map respHeaders) { + return remoteHttpContentAsync(client, "GET", url, 0, null, body, respHeaders).thenApply(out -> out.toString(charset)); + } + + public static CompletableFuture getHttpContentAsync(java.net.http.HttpClient client, String url, Charset charset, Map headers, String body, Map respHeaders) { + return remoteHttpContentAsync(client, "GET", url, 0, headers, body, respHeaders).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, Map respHeaders) { + return remoteHttpContentAsync("GET", url, 0, null, null, respHeaders).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, int timeout, Map respHeaders) { + return remoteHttpContentAsync("GET", url, timeout, null, null, respHeaders).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, Map headers, String body, Map respHeaders) { + return remoteHttpContentAsync("GET", url, 0, headers, body, respHeaders).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 getHttpBytesContentAsync(String url, int timeout, Map headers, String body, Map respHeaders) { + return remoteHttpContentAsync("GET", url, timeout, headers, body, respHeaders).thenApply(out -> out.toByteArray()); + } + + public static CompletableFuture getHttpBytesContentAsync(java.net.http.HttpClient client, String url, int timeout, Map headers, String body, Map respHeaders) { + return remoteHttpContentAsync(client, "GET", url, timeout, headers, body, respHeaders).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, Map headers, String body, Map respHeaders) { + return remoteHttpContentAsync(method, url, 0, headers, body, respHeaders); + } + 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(String method, String url, int timeout, Map headers, String body, Map respHeaders) { + return remoteHttpContentAsync(httpClient, method, url, timeout, headers, body, respHeaders); + } + public static CompletableFuture remoteHttpContentAsync(java.net.http.HttpClient client, String method, String url, int timeout, Map headers, String body) { + return remoteHttpContentAsync(client, method, url, timeout, headers, body, null); + } + + public static CompletableFuture remoteHttpContentAsync(java.net.http.HttpClient client, String method, String url, int timeout, Map headers, String body, Map respHeaders) { 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)); @@ -2756,6 +3798,11 @@ public final class Utility { } byte[] result = resp.body(); if (rs == 200 || result != null) { + if (respHeaders != null) { + resp.headers().map().forEach((k, l) -> { + if (!l.isEmpty()) respHeaders.put(k, l.get(0)); + }); + } ByteArrayOutputStream out = new ByteArrayOutputStream(); if (result != null) { if ("gzip".equalsIgnoreCase(resp.headers().firstValue("content-encoding").orElse(null))) { @@ -2771,7 +3818,7 @@ public final class Utility { } return CompletableFuture.completedFuture(out); } - return CompletableFuture.failedFuture(new IOException(url + " httpcode = " + rs)); + return CompletableFuture.failedFuture(new RetcodeException(rs, url + " httpcode = " + rs)); }); } // diff --git a/src/test/java/org/redkale/test/convert/ConvertCoderTest.java b/src/test/java/org/redkale/test/convert/ConvertCoderTest.java new file mode 100644 index 000000000..b0d461df9 --- /dev/null +++ b/src/test/java/org/redkale/test/convert/ConvertCoderTest.java @@ -0,0 +1,83 @@ +/* + */ +package org.redkale.test.convert; + +import java.math.BigInteger; +import java.util.*; +import org.junit.jupiter.api.*; +import org.redkale.convert.ConvertCoder; +import org.redkale.convert.bson.BsonConvert; +import org.redkale.convert.ext.BigIntegerSimpledCoder.BigIntegerHexJsonSimpledCoder; +import org.redkale.convert.json.JsonConvert; + +/** + * + * @author zhangjx + */ +public class ConvertCoderTest { + + private boolean main; + + public static void main(String[] args) throws Throwable { + ConvertCoderTest test = new ConvertCoderTest(); + test.main = true; + test.run(); + } + + @Test + public void run() throws Exception { + JsonConvert convert = JsonConvert.root(); + BigMessage msg = new BigMessage(); + msg.big = new BigInteger("255"); + msg.big2 = new BigInteger("255"); + msg.big3 = new BigInteger("255"); + msg.map = new HashMap<>(); + msg.map.put("haha", new BigInteger("254")); + + BigMessage2 msg2 = new BigMessage2(); + msg2.big = new BigInteger("255"); + msg2.big2 = new BigInteger("255"); + msg2.big3 = new BigInteger("255"); + msg2.map = new HashMap<>(); + msg2.map.put("haha", new BigInteger("254")); + + System.out.println(convert.convertTo(msg)); + String json = "{\"big\":\"0xff\",\"big2\":\"0xff\",\"big3\":\"255\",\"map\":{\"haha\":\"0xfe\"},\"num1\":0}"; + if (!main) Assertions.assertEquals(convert.convertTo(msg), json); + BigMessage msg12 = convert.convertFrom(BigMessage.class, json); + if (!main) Assertions.assertEquals(convert.convertTo(msg12), json); + + byte[] bs1 = BsonConvert.root().convertTo(msg); + byte[] bs2 = BsonConvert.root().convertTo(msg2); + if (!main) Assertions.assertEquals(Arrays.toString(bs1), Arrays.toString(bs2)); + } + + public static class BigMessage { + + @ConvertCoder(coder = BigIntegerHexJsonSimpledCoder.class) + public BigInteger big; + + @ConvertCoder(encoder = BigIntegerHexJsonSimpledCoder.class, decoder = BigIntegerHexJsonSimpledCoder.class) + public BigInteger big2; + + public BigInteger big3; + + public int num1; + + @ConvertCoder(coder = BigIntegerHexJsonSimpledCoder.class) + public Map map; + } + + public static class BigMessage2 { + + public BigInteger big; + + public BigInteger big2; + + public BigInteger big3; + + public int num1; + + public Map map; + } +} diff --git a/src/test/java/org/redkale/test/convert/CustMessage2Test.java b/src/test/java/org/redkale/test/convert/CustMessage2Test.java new file mode 100644 index 000000000..6cbce9062 --- /dev/null +++ b/src/test/java/org/redkale/test/convert/CustMessage2Test.java @@ -0,0 +1,222 @@ +/* + */ +package org.redkale.test.convert; + +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import java.util.function.*; +import org.junit.jupiter.api.*; +import org.redkale.convert.*; +import org.redkale.convert.json.JsonConvert; +import org.redkale.util.*; + +/** + * + * @author zhangjx + */ +public class CustMessage2Test { + + private boolean main; + + public static void main(String[] args) throws Throwable { + CustMessage2Test test = new CustMessage2Test(); + test.main = true; + test.run(); + } + + @Test + public void run() throws Exception { + final BiFunction objFieldFunc = (Attribute t, Object u) -> { + if (t.field().equals("retinfo")) return null; + return t.get(u); + }; + OnPlayerLeaveMessage msg1 = new OnPlayerLeaveMessage(100, "haha"); + System.out.println(msg1); + OnPlayerLeaveMessage2 msg2 = new OnPlayerLeaveMessage2(100, "haha"); + System.out.println(msg2); + if (!main) Assertions.assertEquals(msg1.toString(), msg2.toString()); + System.out.println(); + + String json = msg1.toString(); + OnPlayerLeaveMessage2 newmsg2 = JsonConvert.root().convertFrom(OnPlayerLeaveMessage2.class, json); + System.out.println(newmsg2); + System.out.println(); + + JsonConvert convert = JsonConvert.root().newConvert(objFieldFunc); + System.out.println(convert.convertTo(msg1)); + System.out.println(convert.convertTo(msg2)); + if (!main) Assertions.assertEquals(convert.convertTo(msg1), convert.convertTo(msg2)); + + } + + public static interface BaseMessage { + + @Inherited + @Documented + @Target({TYPE}) + @Retention(RUNTIME) + public @interface MessageName { + + String value(); + } + + public static String getMessageName(Class clazz) { + MessageName mn = clazz.getAnnotation(MessageName.class); + if (mn != null) return mn.value(); + char[] fieldChars = clazz.getSimpleName().toCharArray(); + fieldChars[0] = Character.toLowerCase(fieldChars[0]); + return new String(fieldChars); + } + + public static Encodeable createConvertEnCoder(final ConvertFactory factory, final Class clazz) { + Encodeable valEncoder = factory.createEncoder(clazz, true); + final String eventName = getMessageName(clazz); + ObjectEncoder encoder = new ObjectEncoder(clazz) { + @Override + protected void afterInitEnMember(ConvertFactory factory) { + Function func1 = t -> eventName; + Attribute attribute1 = Attribute.create(clazz, "event", String.class, func1, null); + EnMember member1 = new EnMember(attribute1, factory.loadEncoder(String.class), null, null); + setIndex(member1, 1); + setPosition(member1, 1); + initForEachEnMember(factory, member1); + + Function func2 = t -> t; + Attribute attribute2 = Attribute.create(clazz, "result", clazz, func2, null); + EnMember member2 = new EnMember(attribute2, valEncoder, null, null); + setIndex(member2, 2); + setPosition(member2, 2); + initForEachEnMember(factory, member2); + this.members = new EnMember[]{member1, member2}; + } + }; + encoder.init(factory); + return encoder; + } + + public static Decodeable createConvertDeCoder(final ConvertFactory factory, final Class clazz) { + Decodeable valDecoder = factory.createDecoder(clazz, true); + final String eventName = getMessageName(clazz); + ObjectDecoder decoder = new ObjectDecoder(clazz) { + @Override + protected void afterInitDeMember(ConvertFactory factory) { + Function func1 = t -> eventName; + Attribute attribute1 = Attribute.create(clazz, "event", String.class, func1, null); + DeMember member1 = new DeMember(attribute1, factory.loadDecoder(String.class), null, null); + setIndex(member1, 1); + setPosition(member1, 1); + initForEachDeMember(factory, member1); + + this.creator = (Creator) objs -> new Object[1]; + Function func2 = t -> t; + BiConsumer consumer2 = (t, v) -> ((Object[]) t)[0] = v; + Attribute attribute2 = Attribute.create(clazz, "result", clazz, func2, consumer2); + DeMember member2 = new DeMember(attribute2, valDecoder, null, null); + setIndex(member2, 2); + setPosition(member2, 2); + initForEachDeMember(factory, member2); + this.members = new DeMember[]{member1, member2}; + } + + @Override + public BaseMessage convertFrom(Reader in) { + Object result = (Object) super.convertFrom(in); + return (BaseMessage) ((Object[]) result)[0]; + } + }; + decoder.init(factory); + return decoder; + } + + } + + @BaseMessage.MessageName("onPlayerLeaveMessage") + public static class OnPlayerLeaveMessage2 implements BaseMessage { + + @ConvertColumn(index = 1) + public int userid; + + @ConvertColumn(index = 2) + public String retinfo; + + public OnPlayerLeaveMessage2() { + } + + public OnPlayerLeaveMessage2(int userid, String retinfo) { + this.userid = userid; + this.retinfo = retinfo; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + } + + public static class OnPlayerLeaveMessage { + + private String event = "onPlayerLeaveMessage"; + + private OnPlayerLeaveContent result; + + public OnPlayerLeaveMessage() { + } + + public OnPlayerLeaveMessage(int userid) { + this.result = new OnPlayerLeaveContent(userid); + } + + public OnPlayerLeaveMessage(int userid, String retinfo) { + this.result = new OnPlayerLeaveContent(userid, retinfo); + } + + public String getEvent() { + return event; + } + + public void setEvent(String event) { + this.event = event; + } + + public OnPlayerLeaveContent getResult() { + return result; + } + + public void setResult(OnPlayerLeaveContent result) { + this.result = result; + } + + public static class OnPlayerLeaveContent { + + @ConvertColumn(index = 1) + public int userid; + + @ConvertColumn(index = 2) + public String retinfo; + + public OnPlayerLeaveContent() { + } + + public OnPlayerLeaveContent(int userid) { + this.userid = userid; + } + + public OnPlayerLeaveContent(int userid, String retinfo) { + this.userid = userid; + this.retinfo = retinfo; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + } + +} diff --git a/src/test/java/org/redkale/test/convert/CustMessageTest.java b/src/test/java/org/redkale/test/convert/CustMessageTest.java new file mode 100644 index 000000000..4dd4d8ed5 --- /dev/null +++ b/src/test/java/org/redkale/test/convert/CustMessageTest.java @@ -0,0 +1,196 @@ +/* + */ +package org.redkale.test.convert; + +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import java.util.function.*; +import org.junit.jupiter.api.*; +import org.redkale.convert.*; +import org.redkale.convert.json.JsonConvert; +import org.redkale.util.*; + +/** + * + * @author zhangjx + */ +public class CustMessageTest { + + private boolean main; + + public static void main(String[] args) throws Throwable { + CustMessageTest test = new CustMessageTest(); + test.main = true; + test.run(); + } + + @Test + public void run() throws Exception { + final BiFunction objFieldFunc = (Attribute t, Object u) -> { + if (t.field().equals("retinfo")) return null; + return t.get(u); + }; + OnPlayerLeaveMessage msg1 = new OnPlayerLeaveMessage(100, "haha"); + System.out.println(msg1); + OnPlayerLeaveMessage2 msg2 = new OnPlayerLeaveMessage2(100, "haha"); + System.out.println(msg2); + if (!main) Assertions.assertEquals(msg1.toString(), msg2.toString()); + System.out.println(); + + String json = msg1.toString(); + OnPlayerLeaveMessage2 newmsg2 = JsonConvert.root().convertFrom(OnPlayerLeaveMessage2.class, json); + System.out.println(newmsg2); + System.out.println(); + + JsonConvert convert = JsonConvert.root().newConvert(objFieldFunc); + System.out.println(convert.convertTo(msg1)); + System.out.println(convert.convertTo(msg2)); + if (!main) Assertions.assertEquals(convert.convertTo(msg1), convert.convertTo(msg2)); + + } + + public static interface BaseMessage { + + @Inherited + @Documented + @Target({TYPE}) + @Retention(RUNTIME) + public @interface MessageName { + + String value(); + } + + public static String getMessageName(Class clazz) { + MessageName mn = clazz.getAnnotation(MessageName.class); + if (mn != null) return mn.value(); + char[] fieldChars = clazz.getSimpleName().toCharArray(); + fieldChars[0] = Character.toLowerCase(fieldChars[0]); + return new String(fieldChars); + } + + public static Encodeable createConvertEnCoder(ConvertFactory factory, Class clazz) { + Encodeable valEncoder = factory.createEncoder(clazz, true); + ObjectEncoder encoder = new ObjectEncoder(clazz) { + @Override + protected void afterInitEnMember(ConvertFactory factory) { + Function func = t -> t; + Attribute attribute = Attribute.create(clazz, getMessageName(clazz), clazz, func, null); + EnMember member = new EnMember(attribute, valEncoder, null, null); + setIndex(member, 1); + setPosition(member, 1); + initForEachEnMember(factory, member); + this.members = new EnMember[]{member}; + } + }; + encoder.init(factory); + return encoder; + } + + public static Decodeable createConvertDeCoder(ConvertFactory factory, Class clazz) { + Decodeable valDecoder = factory.createDecoder(clazz, true); + ObjectDecoder decoder = new ObjectDecoder(clazz) { + @Override + protected void afterInitDeMember(ConvertFactory factory) { + this.creator = (Creator) objs -> new Object[1]; + Function func = t -> t; + BiConsumer consumer = (t, v) -> ((Object[]) t)[0] = v; + Attribute attribute = Attribute.create(clazz, getMessageName(clazz), clazz, func, consumer); + DeMember member = new DeMember(attribute, valDecoder, null, null); + setIndex(member, 1); + setPosition(member, 1); + initForEachDeMember(factory, member); + this.members = new DeMember[]{member}; + } + + @Override + public BaseMessage convertFrom(Reader in) { + Object result = (Object) super.convertFrom(in); + return (BaseMessage) ((Object[]) result)[0]; + } + }; + decoder.init(factory); + return decoder; + } + + } + + @BaseMessage.MessageName("onPlayerLeaveMessage") + public static class OnPlayerLeaveMessage2 implements BaseMessage { + + @ConvertColumn(index = 1) + public int userid; + + @ConvertColumn(index = 2) + public String retinfo; + + public OnPlayerLeaveMessage2() { + } + + public OnPlayerLeaveMessage2(int userid, String retinfo) { + this.userid = userid; + this.retinfo = retinfo; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + } + + public static class OnPlayerLeaveMessage { + + private OnPlayerLeaveContent onPlayerLeaveMessage; + + public OnPlayerLeaveMessage() { + } + + public OnPlayerLeaveMessage(int userid) { + this.onPlayerLeaveMessage = new OnPlayerLeaveContent(userid); + } + + public OnPlayerLeaveMessage(int userid, String retinfo) { + this.onPlayerLeaveMessage = new OnPlayerLeaveContent(userid, retinfo); + } + + public OnPlayerLeaveContent getOnPlayerLeaveMessage() { + return onPlayerLeaveMessage; + } + + public void setOnPlayerLeaveMessage(OnPlayerLeaveContent onPlayerLeaveMessage) { + this.onPlayerLeaveMessage = onPlayerLeaveMessage; + } + + public static class OnPlayerLeaveContent { + + @ConvertColumn(index = 1) + public int userid; + + @ConvertColumn(index = 2) + public String retinfo; + + public OnPlayerLeaveContent() { + } + + public OnPlayerLeaveContent(int userid) { + this.userid = userid; + } + + public OnPlayerLeaveContent(int userid, String retinfo) { + this.userid = userid; + this.retinfo = retinfo; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + } + +} diff --git a/src/test/java/org/redkale/test/convert/InnerCoderEntity.java b/src/test/java/org/redkale/test/convert/InnerCoderEntity.java index 3e01cf905..55c303603 100644 --- a/src/test/java/org/redkale/test/convert/InnerCoderEntity.java +++ b/src/test/java/org/redkale/test/convert/InnerCoderEntity.java @@ -5,6 +5,7 @@ */ package org.redkale.test.convert; +import java.util.*; import org.redkale.convert.*; import org.redkale.convert.bson.*; import org.redkale.convert.json.*; @@ -32,20 +33,25 @@ public class InnerCoderEntity { /** * 璇ユ柟娉曟彁渚涚粰Convert缁勪欢鑷姩鍔犺浇銆 * 1) 鏂规硶鍚嶅彲浠ラ殢鎰忋 - 2) 鏂规硶蹇呴』鏄痵tatic - 3锛夋柟娉曠殑鍙傛暟鏈変笖鍙兘鏈変竴涓紝 涓斿繀椤绘槸org.redkale.convert.ConvertFactory鎴栧瓙绫汇 - 鈥3.1) 鍙傛暟绫诲瀷涓簅rg.redkale.convert.ConvertFactory 琛ㄧず閫傚悎JSON鍜孊SON銆 - 鈥3.2) 鍙傛暟绫诲瀷涓簅rg.redkale.convert.json.JsonFactory 琛ㄧず浠呴傚悎JSON銆 - 鈥3.3) 鍙傛暟绫诲瀷涓簅rg.redkale.convert.bson.BsonFactory 琛ㄧず浠呴傚悎BSON銆 - 4锛夋柟娉曠殑杩斿洖绫诲瀷蹇呴』鏄痮rg.redkale.convert.Decodeable/org.redkale.convert.Encodeable/org.redkale.convert.SimpledCoder - 鑻ヨ繑鍥炵被鍨嬩笉鏄痮rg.redkale.convert.SimpledCoder, 灏卞繀椤绘彁渚涗袱涓柟娉曪細 涓涓繑鍥濪ecodeable 涓涓繑鍥 Encodeable銆 + * 2) 鏂规硶蹇呴』鏄痵tatic + * 3锛夋柟娉曠殑鍙傛暟鏈変笖鍙兘鏈変竴涓紝 涓斿繀椤绘槸org.redkale.convert.ConvertFactory鎴栧瓙绫汇 + * 鈥3.1) 鍙傛暟绫诲瀷涓簅rg.redkale.convert.ConvertFactory 琛ㄧず閫傚悎JSON鍜孊SON銆 + * 鈥3.2) 鍙傛暟绫诲瀷涓簅rg.redkale.convert.json.JsonFactory 琛ㄧず浠呴傚悎JSON銆 + * 鈥3.3) 鍙傛暟绫诲瀷涓簅rg.redkale.convert.bson.BsonFactory 琛ㄧず浠呴傚悎BSON銆 + * 4锛夋柟娉曠殑杩斿洖绫诲瀷蹇呴』鏄痮rg.redkale.convert.Decodeable/org.redkale.convert.Encodeable/org.redkale.convert.SimpledCoder + * 鑻ヨ繑鍥炵被鍨嬩笉鏄痮rg.redkale.convert.SimpledCoder, 灏卞繀椤绘彁渚涗袱涓柟娉曪細 涓涓繑鍥濪ecodeable 涓涓繑鍥 Encodeable銆 * * @param factory + * * @return */ - private static SimpledCoder createConvertCoder(final org.redkale.convert.ConvertFactory factory) { + static SimpledCoder createConvertCoder(final org.redkale.convert.ConvertFactory factory) { return new SimpledCoder() { + private Map deMemberFieldMap; + + private Map deMemberTagMap; + //蹇呴』涓嶦nMember[] 椤哄簭涓鑷 private final DeMember[] deMembers = new DeMember[]{ DeMember.create(factory, InnerCoderEntity.class, "id"), @@ -56,6 +62,15 @@ public class InnerCoderEntity { EnMember.create(factory, InnerCoderEntity.class, "id"), EnMember.create(factory, InnerCoderEntity.class, "val")}; + { + this.deMemberFieldMap = new HashMap<>(this.deMembers.length); + this.deMemberTagMap = new HashMap<>(this.deMembers.length); + for (DeMember member : this.deMembers) { + this.deMemberFieldMap.put(member.getAttribute().field(), member); + this.deMemberTagMap.put(member.getTag(), member); + } + } + @Override public void convertTo(Writer out, InnerCoderEntity value) { if (value == null) { @@ -75,7 +90,7 @@ public class InnerCoderEntity { int index = 0; final Object[] params = new Object[deMembers.length]; while (in.hasNext()) { - DeMember member = in.readFieldName(deMembers); //璇诲彇瀛楁鍚 + DeMember member = in.readFieldName(deMembers, deMemberFieldMap, deMemberTagMap); //璇诲彇瀛楁鍚 in.readBlank(); //璇诲彇瀛楁鍚嶄笌瀛楁鍊间箣闂寸殑闂撮殧绗︼紝JSON鍒欐槸璺宠繃鍐掑彿: if (member == null) { in.skipValue(); //璺宠繃涓嶅瓨鍦ㄧ殑瀛楁鐨勫, 涓鑸笉浼氬彂鐢 diff --git a/src/test/java/org/redkale/test/convert/Json5Test.java b/src/test/java/org/redkale/test/convert/Json5Test.java new file mode 100644 index 000000000..3b4a4507e --- /dev/null +++ b/src/test/java/org/redkale/test/convert/Json5Test.java @@ -0,0 +1,86 @@ +/* + */ +package org.redkale.test.convert; + +import java.util.*; +import org.junit.jupiter.api.*; +import org.redkale.convert.json.JsonConvert; + +/** + * + * @author zhangjx + */ +public class Json5Test { + + private boolean main; + + public static void main(String[] args) throws Throwable { + Json5Test test = new Json5Test(); + test.main = true; + test.run(); + } + + @Test + public void run() throws Exception { + JsonConvert convert = JsonConvert.root(); + Json5Bean bean = new Json5Bean(); + bean.id = 500; + bean.decmails = 3.2f; + bean.value = 44444; + bean.name = "haha"; + String json = "{/*澶氳\r\n娉ㄩ噴**/\"decmails\":3.2,//鍗曡娉ㄩ噴\r\n\"id\":0x1F4,\"name\":\"haha\",\"value\":44444,}"; + Json5Bean bean2 = convert.convertFrom(Json5Bean.class, json); + if (!main) Assertions.assertTrue(bean.equals(bean2)); + System.out.println(convert.convertTo(bean2)); + + String arrayJson = "[" + json + "," + json + "," + "]"; + Json5Bean[] beans = convert.convertFrom(Json5Bean[].class, arrayJson); + System.out.println(convert.convertTo(beans)); + + String intjson = "[1,2,3,4,]"; + int[] ints1 = convert.convertFrom(int[].class, intjson); + System.out.println(Arrays.toString(ints1)); + } + + public static class Json5Bean { + + public int id; + + public float decmails; + + public long value; + + public String name; + + @Override + public int hashCode() { + int hash = 7; + hash = 47 * hash + this.id; + hash = 47 * hash + Float.floatToIntBits(this.decmails); + hash = 47 * hash + (int) (this.value ^ (this.value >>> 32)); + hash = 47 * hash + Objects.hashCode(this.name); + 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 Json5Bean other = (Json5Bean) obj; + if (this.id != other.id) + return false; + if (Float.floatToIntBits(this.decmails) != Float.floatToIntBits(other.decmails)) + return false; + if (this.value != other.value) + return false; + if (!Objects.equals(this.name, other.name)) + return false; + return true; + } + + } +} diff --git a/src/test/java/org/redkale/test/convert/JsonTestMain.java b/src/test/java/org/redkale/test/convert/JsonMainTest.java similarity index 86% rename from src/test/java/org/redkale/test/convert/JsonTestMain.java rename to src/test/java/org/redkale/test/convert/JsonMainTest.java index 69a1181f4..9506cde1e 100644 --- a/src/test/java/org/redkale/test/convert/JsonTestMain.java +++ b/src/test/java/org/redkale/test/convert/JsonMainTest.java @@ -18,7 +18,19 @@ import org.redkale.convert.json.*; * * @author zhangjx */ -public class JsonTestMain { +public class JsonMainTest { + + private boolean main; + + public static void main(String[] args) throws Throwable { + JsonMainTest test = new JsonMainTest(); + test.main = true; + test.run1(); + test.run2(); + test.run3(); + test.run4(); + test.run5(); + } @Test public void run1() throws Throwable { @@ -33,7 +45,7 @@ public class JsonTestMain { byte[] bs = new byte[buffers[0].remaining()]; buffers[0].get(bs); System.out.println(new String(bs)); - Assertions.assertEquals(rs, new String(bs)); + Assertions.assertEquals(rs, new String(bs)); } @Test @@ -88,4 +100,11 @@ public class JsonTestMain { java.sql.Date rs = convert.convertFrom(java.sql.Date.class, json); System.out.println(convert.convertTo(rs)); } + + @Test + public void run5() throws Throwable { + final JsonConvert convert = JsonConvert.root(); + long v = convert.convertFrom(long.class, "100"); + Assertions.assertEquals(100, v); + } } diff --git a/src/test/java/org/redkale/test/convert/JsonMultiDecoderTest.java b/src/test/java/org/redkale/test/convert/JsonMultiDecoderTest.java new file mode 100644 index 000000000..820ad9729 --- /dev/null +++ b/src/test/java/org/redkale/test/convert/JsonMultiDecoderTest.java @@ -0,0 +1,32 @@ +/* + */ +package org.redkale.test.convert; + +import java.lang.reflect.Type; +import org.junit.jupiter.api.*; +import org.redkale.convert.json.JsonConvert; + +/** + * + * @author zhangjx + */ +public class JsonMultiDecoderTest { + + private boolean main; + + public static void main(String[] args) throws Throwable { + JsonMultiDecoderTest test = new JsonMultiDecoderTest(); + test.main = true; + test.run(); + } + + @Test + public void run() throws Exception { + JsonConvert convert = JsonConvert.root(); + String json = "[\"aaaa\",{\"name\":\"haha\"}]"; + Type[] types = new Type[]{String.class, JsonConvert.TYPE_MAP_STRING_STRING}; + Object[] objs = convert.convertFrom(types, json); + System.out.println(convert.convertTo(objs)); + if (!main) Assertions.assertEquals(convert.convertTo(objs), json); + } +} diff --git a/src/test/java/org/redkale/test/convert/JsonMultiObjectDecoderTest.java b/src/test/java/org/redkale/test/convert/JsonMultiObjectDecoderTest.java new file mode 100644 index 000000000..f7dba7913 --- /dev/null +++ b/src/test/java/org/redkale/test/convert/JsonMultiObjectDecoderTest.java @@ -0,0 +1,123 @@ +/* + */ +package org.redkale.test.convert; + +import org.junit.jupiter.api.*; +import org.redkale.convert.ConvertImpl; +import org.redkale.convert.json.JsonConvert; + +/** + * + * @author zhangjx + */ +public class JsonMultiObjectDecoderTest { + + private boolean main; + + public static void main(String[] args) throws Throwable { + JsonMultiObjectDecoderTest test = new JsonMultiObjectDecoderTest(); + test.main = true; + test.run(); + } + + @Test + public void run() throws Exception { + { + String json = "{\"a0\":\"000\",\"a6\":\"666\"}"; + AbstractBean bean = JsonConvert.root().convertFrom(AbstractBean.class, json); + if (!main) Assertions.assertEquals(bean.getClass().getName(), Bean69.class.getName()); + System.out.println(bean); + } + { + String json = "{\"a0\":\"000\",\"a2\":\"222\",\"a4\":\"444\"}"; + AbstractBean bean = JsonConvert.root().convertFrom(AbstractBean.class, json); + if (!main) Assertions.assertEquals(bean.getClass().getName(), Bean423.class.getName()); + System.out.println(bean); + } + { + String json = "{\"a0\":\"000\",\"a6\":\"666\",\"a5\":\"555\"}"; + AbstractBean bean = JsonConvert.root().convertFrom(AbstractBean.class, json); + if (!main) Assertions.assertEquals(bean.getClass().getName(), Bean65.class.getName()); + System.out.println(bean); + } + } + + //[{"1", "2", "3"}, {"2", "3"}, {"4", "2", "3"}, {"6", "7", "8"}, {"6", "5"}, {"6", "9"}] + @ConvertImpl(types = {Bean123.class, Bean23.class, Bean423.class, Bean678.class, Bean65.class, Bean69.class}) + public static abstract class AbstractBean { + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } + } + + public static class Bean123 extends AbstractBean { + + public String a1; + + public String a2; + + public String a3; + } + + public static class Bean23 extends AbstractBean { + + public String a2; + + public String a3; + } + + public static class Bean423 extends AbstractBean { + + public String a4; + + public String a2; + + public String a3; + } + + public static class Bean678 extends AbstractBean { + + public String a6; + + public String a7; + + public String a8; + } + + public static class Bean69 extends AbstractBean { + + public String a6; + + public String a9; + + public Bean69(String a9) { + this.a9 = a9; + } + } + + public static class Bean65 extends AbstractBean { + + private String a6; + + private String a5; + + public Bean65(String a5) { + this.a5 = a5; + } + + public String getA6() { + return a6; + } + + public void setA6(String a6) { + this.a6 = a6; + } + + public String getA5() { + return a5; + } + + } +} diff --git a/src/test/java/org/redkale/test/convert/ObjectOrStringTest.java b/src/test/java/org/redkale/test/convert/ObjectOrStringTest.java new file mode 100644 index 000000000..e20a579a3 --- /dev/null +++ b/src/test/java/org/redkale/test/convert/ObjectOrStringTest.java @@ -0,0 +1,116 @@ +/* + */ +package org.redkale.test.convert; + +import java.lang.reflect.Type; +import org.junit.jupiter.api.*; +import org.redkale.convert.*; +import org.redkale.convert.json.*; + +/** + * + * @author zhangjx + */ +public class ObjectOrStringTest { + + private boolean main; + + public static void main(String[] args) throws Throwable { + ObjectOrStringTest test = new ObjectOrStringTest(); + test.main = true; + test.run(); + } + + @Test + public void run() throws Exception { + JsonConvert convert = JsonConvert.root(); + String json = "[\"aaaaa\",{\"id\":200,\"name\":\"haha\"}]"; + AbstractBean[] beans = convert.convertFrom(AbstractBean[].class, json); + System.out.println(convert.convertTo(beans[0])); + System.out.println(convert.convertTo(beans[1])); + System.out.println(convert.convertTo(beans)); + if (!main) Assertions.assertEquals(json, convert.convertTo(beans)); + } + + public static abstract class AbstractBean { + + //蹇呴』澹版槑涓簆rivate锛 鍚﹀垯鍔犺浇StringBean鏃堕厤缃瓺ecoder浼氶噰鐢ㄦ鏂规硶 + private static Decodeable createDecoder(final org.redkale.convert.json.JsonFactory factory) { + Decodeable stringDecoder = factory.loadDecoder(StringBean.class); + Decodeable objectDecoder = factory.loadDecoder(ObjectBean.class); + return new Decodeable() { + @Override + public AbstractBean convertFrom(JsonReader in) { + Decodeable coder = in.isNextObject() ? objectDecoder : stringDecoder; + return (AbstractBean) coder.convertFrom(in); + } + + @Override + public Type getType() { + return AbstractBean.class; + } + + }; + } + } + + public static class ObjectBean extends AbstractBean { + + private int id; + + private String name; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + } + + public static class StringBean extends AbstractBean { + + private String value; + + public StringBean() { + } + + public StringBean(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + static SimpledCoder createConvertCoder(final org.redkale.convert.ConvertFactory factory) { + return new SimpledCoder() { + @Override + public void convertTo(Writer out, StringBean val) { + out.writeString(val == null ? null : val.value); + } + + @Override + public StringBean convertFrom(Reader in) { + String val = in.readString(); + return new StringBean(val); + } + + }; + } + } +} diff --git a/src/test/java/org/redkale/test/convert/OneOrListTest.java b/src/test/java/org/redkale/test/convert/OneOrListTest.java new file mode 100644 index 000000000..7813da913 --- /dev/null +++ b/src/test/java/org/redkale/test/convert/OneOrListTest.java @@ -0,0 +1,52 @@ +/* + */ +package org.redkale.test.convert; + +import org.junit.jupiter.api.*; +import org.redkale.convert.json.JsonConvert; +import org.redkale.util.OneOrList; + +/** + * + * @author zhangjx + */ +public class OneOrListTest { + + private boolean main; + + public static void main(String[] args) throws Throwable { + OneOrListTest test = new OneOrListTest(); + test.main = true; + test.run(); + } + + @Test + public void run() throws Exception { + JsonConvert convert = JsonConvert.root(); + String json = "[\"aaaaa\"]"; + { + StringOneList sol = convert.convertFrom(StringOneList.class, json); + System.out.println("sol.list = " + convert.convertTo(sol.getList())); + if (!main) Assertions.assertEquals(json, convert.convertTo(sol)); + System.out.println(convert.convertTo(sol)); + } + { + String2OneList sol2 = convert.convertFrom(String2OneList.class, json); + System.out.println("sol2.list = " + convert.convertTo(sol2.getList())); + if (!main) Assertions.assertEquals(json, convert.convertTo(sol2)); + System.out.println(convert.convertTo(sol2)); + } + { + OneOrList sol3 = convert.convertFrom(OneOrList.TYPE_OL_STRING, json); + System.out.println("sol3.list = " + convert.convertTo(sol3.getList())); + if (!main) Assertions.assertEquals(json, convert.convertTo(OneOrList.TYPE_OL_STRING, sol3)); + System.out.println(convert.convertTo(OneOrList.TYPE_OL_STRING, sol3)); + } + } + + public static class StringOneList extends OneOrList { + } + + public static class String2OneList extends StringOneList { + } +} diff --git a/src/test/java/org/redkale/test/convert/StringWrapperTest.java b/src/test/java/org/redkale/test/convert/StringWrapperTest.java new file mode 100644 index 000000000..ab6f0e657 --- /dev/null +++ b/src/test/java/org/redkale/test/convert/StringWrapperTest.java @@ -0,0 +1,44 @@ +/* + */ +package org.redkale.test.convert; + +import java.nio.charset.StandardCharsets; +import org.junit.jupiter.api.*; +import org.redkale.convert.json.JsonConvert; +import org.redkale.util.StringWrapper; + +/** + * + * @author zhangjx + */ +public class StringWrapperTest { + + private boolean main; + + public static void main(String[] args) throws Throwable { + StringWrapperTest test = new StringWrapperTest(); + test.main = true; + test.run(); + } + + @Test + public void run() throws Exception { + JsonConvert convert = JsonConvert.root(); + { + String val = "{}"; + StringWrapper wrapper = new StringWrapper(val); + if (!main) Assertions.assertEquals(val, convert.convertTo(wrapper)); + if (!main) Assertions.assertEquals(val, new String(convert.convertToBytes(wrapper))); + System.out.println(convert.convertTo(wrapper)); + System.out.println(new String(convert.convertToBytes(wrapper))); + } + { + String val = "{id:'甯︿腑鏂'}"; + StringWrapper wrapper = new StringWrapper(val); + if (!main) Assertions.assertEquals(val, convert.convertTo(wrapper)); + if (!main) Assertions.assertEquals(val, new String(convert.convertToBytes(wrapper), StandardCharsets.UTF_8)); + System.out.println(convert.convertTo(wrapper)); + System.out.println(new String(convert.convertToBytes(wrapper), StandardCharsets.UTF_8)); + } + } +} diff --git a/src/test/java/org/redkale/test/convert/TinyTest.java b/src/test/java/org/redkale/test/convert/TinyTest.java new file mode 100644 index 000000000..89274d5e4 --- /dev/null +++ b/src/test/java/org/redkale/test/convert/TinyTest.java @@ -0,0 +1,48 @@ +/* + */ +package org.redkale.test.convert; + +import org.junit.jupiter.api.*; +import org.redkale.convert.json.*; + +/** + * + * @author zhangjx + */ +public class TinyTest { + + private boolean main; + + public static void main(String[] args) throws Throwable { + TinyTest test = new TinyTest(); + test.main = true; + test.run(); + } + + @Test + public void run() throws Exception { + TinyRecord record = new TinyRecord(); + record.id = 5; + { + JsonFactory factory = JsonFactory.create().tiny(true); + JsonConvert convert = factory.getConvert(); + String json = "{\"id\":5}"; + if (!main) Assertions.assertEquals(json, convert.convertTo(record)); + System.out.println(convert.convertTo(record)); + } + { + JsonFactory factory = JsonFactory.create().tiny(false); + JsonConvert convert = factory.getConvert(); + String json = "{\"id\":5,\"name\":\"\"}"; + if (!main) Assertions.assertEquals(json, convert.convertTo(record)); + System.out.println(convert.convertTo(record)); + } + } + + public static class TinyRecord { + + public String name = ""; + + public int id; + } +} diff --git a/src/test/java/org/redkale/test/source/FilterNodeTest.java b/src/test/java/org/redkale/test/source/FilterNodeTest.java index 0a7532fe0..cd4191c29 100644 --- a/src/test/java/org/redkale/test/source/FilterNodeTest.java +++ b/src/test/java/org/redkale/test/source/FilterNodeTest.java @@ -105,7 +105,7 @@ public class FilterNodeTest { FilterNode joinNode1 = FilterJoinNode.create(UserTestTable.class, new String[]{"userid", "username"}, "username", LIKE, bean.username) .or(FilterJoinNode.create(UserTestTable.class, new String[]{"userid", "username"}, "createtime", GREATERTHAN, bean.createtime)); FilterNode joinNode2 = FilterJoinNode.create(CarTypeTestTable.class, "cartype", "typename", LIKE, bean.typename); - final FilterNode node = CarTestBean.caridTransient() ? (joinNode2.or(joinNode1)) : FilterNode.create("carid", GREATERTHAN, bean.carid).and(joinNode1).or(joinNode2); + final FilterNode node = CarTestBean.caridTransient() ? (joinNode2.or(joinNode1)) : FilterNode.filter("carid", GREATERTHAN, bean.carid).and(joinNode1).or(joinNode2); final FilterNode beanNode = FilterNodeBean.createFilterNode(bean); System.out.println("node.string = " + node); System.out.println("bean.string = " + beanNode); diff --git a/src/test/java/org/redkale/test/source/JDBCTest.java b/src/test/java/org/redkale/test/source/JDBCTest.java deleted file mode 100644 index 08d7152c7..000000000 --- a/src/test/java/org/redkale/test/source/JDBCTest.java +++ /dev/null @@ -1,41 +0,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.test.source; - -import org.redkale.source.*; - -/** - * - * @author zhangjx - */ -public class JDBCTest { - - public static void main(String[] args) throws Exception { - DataSource source = DataSources.createDataSource(null, ""); //鑰楁椂锛37415 - int count = 1000; - LoginTestRecord last = null; - long s = System.currentTimeMillis(); - int c = 0; - try { - for (int i = 0; i < count; i++) { - LoginTestRecord record = new LoginTestRecord(); - record.setSessionid(Long.toHexString(System.nanoTime())); - record.setLoginagent("win7"); - record.setLogintime(System.currentTimeMillis()); - record.setLoginip("127.0.0.1"); - record.setUserid(i); - source.insert(record); - last = record; - c = i; - } - } catch (Exception e) { - System.out.println("寮傚父浜: " + c); - e.printStackTrace(); - } - long e = System.currentTimeMillis() - s; - System.out.println("鑰楁椂锛" + e); - } -} diff --git a/src/test/java/org/redkale/test/source/JsonRecord.java b/src/test/java/org/redkale/test/source/JsonRecord.java index f5b1defbf..2e97218ed 100644 --- a/src/test/java/org/redkale/test/source/JsonRecord.java +++ b/src/test/java/org/redkale/test/source/JsonRecord.java @@ -10,6 +10,7 @@ import java.util.*; import javax.persistence.*; import org.redkale.convert.json.JsonConvert; import org.redkale.source.*; +import org.redkale.util.AnyValue.DefaultAnyValue; /** * @@ -60,11 +61,13 @@ public class JsonRecord { } public static void main(String[] args) throws Throwable { - Properties properties = new Properties(); - properties.put("javax.persistence.jdbc.url", "jdbc:mysql://localhost:3306/center?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true"); - properties.put("javax.persistence.jdbc.user", "root"); - properties.put("javax.persistence.jdbc.password", ""); - DataSource source = DataSources.createDataSource("", properties); + DefaultAnyValue conf = DefaultAnyValue.create(); + conf.addValue("name", ""); + conf.addValue("url", "jdbc:mysql://localhost:3306/center?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true"); + conf.addValue("user", "root"); + conf.addValue("password", ""); + DataJdbcSource source = new DataJdbcSource(); + source.init(conf); JsonRecord record = JsonRecord.create(); source.insert(record); source.updateColumn(JsonRecord.class, record.getRecordid(), ColumnValue.mov("recordname", "my name 2")); diff --git a/src/test/java/org/redkale/test/source/TestSourceCache.java b/src/test/java/org/redkale/test/source/TestSourceCache.java index d77e53fec..bfab1285c 100644 --- a/src/test/java/org/redkale/test/source/TestSourceCache.java +++ b/src/test/java/org/redkale/test/source/TestSourceCache.java @@ -66,7 +66,7 @@ public class TestSourceCache { final Flipper flipper = new Flipper(2); flipper.setSort("userid DESC, createtime DESC"); - final FilterNode node = FilterNode.create("userid", FilterExpress.GREATERTHAN, 1000).and("username", FilterExpress.LIKE, "鐢ㄦ埛"); + final FilterNode node = FilterNode.filter("userid", FilterExpress.GREATERTHAN, 1000).and("username", FilterExpress.LIKE, "鐢ㄦ埛"); System.out.println("node = " + node); Sheet sheet = info.getCache().querySheet(null, flipper, node); System.out.println(sheet); diff --git a/src/test/java/org/redkale/test/util/AnyValuePropertiesTest.java b/src/test/java/org/redkale/test/util/AnyValuePropertiesTest.java new file mode 100644 index 000000000..ee956f941 --- /dev/null +++ b/src/test/java/org/redkale/test/util/AnyValuePropertiesTest.java @@ -0,0 +1,79 @@ +/* + */ +package org.redkale.test.util; + +import java.util.Properties; +import org.junit.jupiter.api.*; +import org.redkale.util.AnyValue; + +/** + * + * @author zhangjx + */ +public class AnyValuePropertiesTest { + + @Test + public void run1() { + Properties properties = new Properties(); + properties.put("redkale.aaa.ooo", "value o"); + properties.put("redkale.aaa.ppp", "value p"); + properties.put("redkale.bbb.qqq.rrr", "value r"); + properties.put("redkale.bbb.sss", "value s"); + properties.put("redkale.source[my].sss", "my s"); + properties.put("redkale.source[my].ttt", "my t"); + properties.put("redkale.source[you].sss", "you s"); + properties.put("redkale.source[you].ttt", "you t"); + properties.put("redkale.ddd[2].ww", "ww 2"); + properties.put("redkale.ddd[2].nn", "nn 2"); + properties.put("redkale.ddd[0].ww", "ww 0"); + properties.put("redkale.ddd[0].nn", "nn 0"); + properties.put("redkale.ddd[10].ww", "ww 10"); + properties.put("redkale.ddd[10].nn", "nn 10"); + properties.put("redkale.mmm.node[5]", "n5"); + properties.put("redkale.mmm.node[0]", "n0"); + properties.put("redkale.mmm.node[20]", "n20"); + + String result = "{\r\n" + + " 'redkale': '{\r\n" + + " 'source': '{\r\n" + + " 'my': '{\r\n" + + " 'sss': 'my s',\r\n" + + " 'ttt': 'my t',\r\n" + + " }',\r\n" + + " 'you': '{\r\n" + + " 'ttt': 'you t',\r\n" + + " 'sss': 'you s',\r\n" + + " }',\r\n" + + " }',\r\n" + + " 'ddd': '{\r\n" + + " 'ww': 'ww 0',\r\n" + + " 'nn': 'nn 0',\r\n" + + " }',\r\n" + + " 'ddd': '{\r\n" + + " 'ww': 'ww 2',\r\n" + + " 'nn': 'nn 2',\r\n" + + " }',\r\n" + + " 'ddd': '{\r\n" + + " 'ww': 'ww 10',\r\n" + + " 'nn': 'nn 10',\r\n" + + " }',\r\n" + + " 'mmm': '{\r\n" + + " 'node': 'n0',\r\n" + + " 'node': 'n5',\r\n" + + " 'node': 'n20',\r\n" + + " }',\r\n" + + " 'bbb': '{\r\n" + + " 'sss': 'value s',\r\n" + + " 'qqq': '{\r\n" + + " 'rrr': 'value r',\r\n" + + " }',\r\n" + + " }',\r\n" + + " 'aaa': '{\r\n" + + " 'ppp': 'value p',\r\n" + + " 'ooo': 'value o',\r\n" + + " }',\r\n" + + " }',\r\n" + + "}"; + Assertions.assertEquals(result, AnyValue.loadFromProperties(properties).toString()); + } +} diff --git a/src/test/java/org/redkale/test/util/ResourceInjectMain.java b/src/test/java/org/redkale/test/util/ResourceAnnotationTest.java similarity index 62% rename from src/test/java/org/redkale/test/util/ResourceInjectMain.java rename to src/test/java/org/redkale/test/util/ResourceAnnotationTest.java index 78083a60a..645d203a8 100644 --- a/src/test/java/org/redkale/test/util/ResourceInjectMain.java +++ b/src/test/java/org/redkale/test/util/ResourceAnnotationTest.java @@ -10,6 +10,7 @@ import java.lang.annotation.*; import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.reflect.Field; +import org.junit.jupiter.api.*; import org.redkale.convert.json.JsonConvert; import org.redkale.util.*; @@ -17,25 +18,35 @@ import org.redkale.util.*; * * @author zhangjx */ -public class ResourceInjectMain { +public class ResourceAnnotationTest { + + private boolean main; public static void main(String[] args) throws Throwable { - ResourceFactory factory = ResourceFactory.create(); - factory.register(new CustomConfLoader()); - InjectBean bean = new InjectBean(); - factory.inject(bean); + ResourceAnnotationTest test = new ResourceAnnotationTest(); + test.main = true; + test.run(); } - public static class CustomConfLoader implements ResourceInjectLoader { + @Test + public void run() throws Exception { + ResourceFactory factory = ResourceFactory.create(); + factory.register(new CustomConfProvider()); + InjectBean bean = new InjectBean(); + factory.inject(bean); + if (!main) Assertions.assertEquals(new File("conf/test.xml").toString(), bean.conf.toString()); + } + + public static class CustomConfProvider implements ResourceAnnotationProvider { @Override - public void load(ResourceFactory factory, Object src, CustomConf annotation, Field field, Object attachment) { + public void load(ResourceFactory factory, String srcResourceName, Object srcObj, CustomConf annotation, Field field, Object attachment) { try { - field.set(src, new File(annotation.path())); + field.set(srcObj, new File(annotation.path())); } catch (Exception e) { e.printStackTrace(); } - System.out.println("瀵硅薄鏄 src =" + src + ", path=" + annotation.path()); + System.out.println("瀵硅薄鏄 src =" + srcObj + ", path=" + annotation.path()); } @Override diff --git a/src/test/java/org/redkale/test/util/ResourceLoaderTest.java b/src/test/java/org/redkale/test/util/ResourceLoaderTest.java new file mode 100644 index 000000000..fbd9ea7d3 --- /dev/null +++ b/src/test/java/org/redkale/test/util/ResourceLoaderTest.java @@ -0,0 +1,68 @@ +/* + */ +package org.redkale.test.util; + +import javax.annotation.Resource; +import org.junit.jupiter.api.*; +import org.redkale.convert.json.JsonFactory; +import org.redkale.util.*; + +/** + * + * @author zhangjx + */ +public class ResourceLoaderTest { + + private boolean main; + + public static void main(String[] args) throws Throwable { + ResourceLoaderTest test = new ResourceLoaderTest(); + test.main = true; + test.run(); + } + + @Test + public void run() throws Exception { + ResourceFactory factory = ResourceFactory.create(); + factory.register("a.id", 1234); + factory.register("a.name", "my a name"); + factory.register("b.id", 4321); + factory.register("b.name", "my b name"); + Bean bean = new Bean(); + factory.register("a", bean); + factory.inject("a", bean); + + ParentBean pb = new ParentBean(); + factory.inject(pb); + if (!main) Assertions.assertEquals(new Bean(1234, "my a name").toString(), pb.bean.toString()); + System.out.println(pb.bean); + } + + public static class ParentBean { + + @Resource(name = "a") + public Bean bean; + } + + public static class Bean { + + @Resource(name = "$.id") + public int id; + + @Resource(name = "$.name") + public String name; + + public Bean() { + } + + public Bean(int id, String name) { + this.id = id; + this.name = name; + } + + @Override + public String toString() { + return JsonFactory.root().getConvert().convertTo(this); + } + } +}